diff --git a/Docs/BACKEND_DEV.md b/Docs/BACKEND_DEV.md index cd797c1..61f39d7 100644 --- a/Docs/BACKEND_DEV.md +++ b/Docs/BACKEND_DEV.md @@ -2,6 +2,12 @@ 本文档定义后端开发的结构规范、接口契约与实现习惯。目标是让新功能按统一范式落地,旧逻辑在修复时逐步抽离。 +## 文档定位 + +- 本文档只定义后端开发规范与工程约束(分层职责、契约、流程、代码习惯)。 +- 接口说明、部署运行与环境配置示例请查看 `Docs/BACKEND_README.md`。 +- 历史变更请记录在 `Docs/DevLogs/` 与 `Docs/TASK_COMPLETE.md`,不要写入本规范文档。 + --- ## 1. 模块化与分层原则 @@ -43,7 +49,7 @@ backend/ │ │ └── admin/ # 管理员功能 │ ├── repositories/ # Supabase 数据访问 │ ├── services/ # 外部服务集成 -│ │ ├── uploader/ # 平台发布器(douyin/weixin) +│ │ ├── uploader/ # 平台发布器(douyin/weixin/xiaohongshu/bilibili) │ │ ├── qr_login_service.py │ │ ├── publish_service.py │ │ ├── remotion_service.py @@ -162,7 +168,7 @@ backend/user_data/{user_uuid}/cookies/ - `MUSETALK_BATCH_SIZE` (推理批大小,默认 32) - `MUSETALK_VERSION` (v15) - `MUSETALK_USE_FLOAT16` (半精度,默认 true) -- `LIPSYNC_DURATION_THRESHOLD` (秒,>=此值用 MuseTalk,默认 120) +- `LIPSYNC_DURATION_THRESHOLD` (秒,>=此值用 MuseTalk;代码默认 120,本仓库当前 `.env` 配置 100) ### 微信视频号 - `WEIXIN_HEADLESS_MODE` (headful/headless-new) @@ -179,6 +185,14 @@ backend/user_data/{user_uuid}/cookies/ - `DOUYIN_FORCE_SWIFTSHADER` - `DOUYIN_DEBUG_ARTIFACTS` / `DOUYIN_RECORD_VIDEO` / `DOUYIN_KEEP_SUCCESS_VIDEO` +### 小红书 +- `XIAOHONGSHU_HEADLESS_MODE` (headful/headless-new,默认 headless-new) +- `XIAOHONGSHU_CHROME_PATH` / `XIAOHONGSHU_BROWSER_CHANNEL` +- `XIAOHONGSHU_USER_AGENT` +- `XIAOHONGSHU_LOCALE` / `XIAOHONGSHU_TIMEZONE_ID` +- `XIAOHONGSHU_FORCE_SWIFTSHADER` +- `XIAOHONGSHU_DEBUG_ARTIFACTS` + ### 支付宝 - `ALIPAY_APP_ID` / `ALIPAY_PRIVATE_KEY_PATH` / `ALIPAY_PUBLIC_KEY_PATH` - `ALIPAY_NOTIFY_URL` / `ALIPAY_RETURN_URL` @@ -191,8 +205,9 @@ backend/user_data/{user_uuid}/cookies/ ## 10. Playwright 发布调试 - 诊断日志落盘:`backend/app/debug_screenshots/weixin_network.log` / `douyin_network.log` -- 关键失败截图:`backend/app/debug_screenshots/weixin_*.png` / `douyin_*.png` +- 关键失败截图:`backend/app/debug_screenshots/weixin_*.png` / `douyin_*.png` / `xiaohongshu_*.png` - 视频号建议使用 headful + xvfb-run(避免 headless 解码/指纹问题) +- 发布专项实现细节(登录链路、成功判定、排障)统一维护在 `Docs/PUBLISH_DEPLOY.md` --- diff --git a/Docs/BACKEND_README.md b/Docs/BACKEND_README.md index 088706f..70e239b 100644 --- a/Docs/BACKEND_README.md +++ b/Docs/BACKEND_README.md @@ -1,6 +1,12 @@ # ViGent2 后端开发指南 -本文档提供后端架构概览与接口规范。开发规范与分层约定见 `Docs/BACKEND_DEV.md`。 +本文档提供后端架构概览、接口说明与运行配置。 + +## 📌 文档定位 + +- 本文档用于说明后端服务能力、接口与部署运行方式(面向使用与联调)。 +- 开发规范、分层约束与代码实现习惯请查看 `Docs/BACKEND_DEV.md`。 +- 历史变更与里程碑请查看 `Docs/DevLogs/` 与 `Docs/TASK_COMPLETE.md`。 --- @@ -8,7 +14,7 @@ 后端采用 **FastAPI** 框架,基于 Python 3.10+ 构建,主要负责业务逻辑处理、AI 任务调度以及与各微服务组件的交互。 -### 目录结构 +### 目录结构(概览) ``` backend/ @@ -36,6 +42,8 @@ backend/ └── requirements.txt # 依赖清单 ``` +> 详细分层职责(router/service/workflow/repositories)与开发约束请查看 `Docs/BACKEND_DEV.md`。 + --- ## 🔌 API 接口规范 @@ -56,6 +64,7 @@ backend/ 2. **视频生成 (Videos)** * `POST /api/videos/generate`: 提交生成任务 + * `GET/POST /api/videos/voice-preview`: 生成音色试听短音频(返回二进制音频流) * `GET /api/videos/tasks/{task_id}`: 查询单个任务状态 * `GET /api/videos/tasks`: 获取用户所有任务列表 * `GET /api/videos/generated`: 获取历史视频列表 @@ -69,11 +78,14 @@ backend/ 4. **社交发布 (Publish)** * `POST /api/publish`: 发布视频到 抖音/微信视频号/B站/小红书 - * `POST /api/publish/login`: 扫码登录平台 - * `GET /api/publish/login/status`: 查询登录状态(含刷脸验证二维码) + * `POST /api/publish/login/{platform}`: 获取平台二维码并启动扫码登录 + * `GET /api/publish/login/status/{platform}`: 轮询登录状态(含抖音刷脸验证二维码) + * `POST /api/publish/logout/{platform}`: 注销平台登录(删除 Cookie) + * `POST /api/publish/cookies/save/{platform}`: 保存客户端提取的 Cookie * `GET /api/publish/accounts`: 获取已登录账号列表 + * `GET /api/publish/screenshot/{filename}`: 获取发布成功截图(需登录) -> 提示:视频号/抖音发布建议使用 headful + xvfb-run 运行后端。 +> 提示:视频号/抖音发布建议使用 headful + xvfb-run 运行后端。发布专项实现与部署说明见 `Docs/PUBLISH_DEPLOY.md`。 5. **资源库 (Assets)** * `GET /api/assets/subtitle-styles`: 字幕样式列表 @@ -138,7 +150,11 @@ backend/ - `speed`: 语速(声音克隆模式,默认 1.0,范围 0.8-1.2) - `custom_assignments`: 自定义素材分配数组(每项含 `material_path` / `start` / `end` / `source_start` / `source_end?`),存在时优先按时间轴可见段生成 - `output_aspect_ratio`: 输出画面比例(`9:16` 或 `16:9`,默认 `9:16`) -- `language`: TTS 语言(默认自动检测,声音克隆时透传给 CosyVoice 3.0) +- `lipsync_model`: 唇形模型路由模式(`default` / `fast` / `advanced`) + - `default`: 阈值路由(`LIPSYNC_DURATION_THRESHOLD`) + - `fast`: 强制 MuseTalk,不可用时回退 LatentSync + - `advanced`: 强制 LatentSync +- `language`: TTS 语言区域(默认 `zh-CN`;会映射为 Whisper 的 `zh/en/...` 与 CosyVoice 的 `Chinese/English/Auto`) - `title`: 片头标题文字 - `title_display_mode`: 标题显示模式(`short` / `persistent`,默认 `short`) - `title_duration`: 标题显示时长(秒,默认 `4.0`;`short` 模式生效) @@ -161,7 +177,7 @@ backend/ - 多素材片段在拼接前统一重编码,并强制 `25fps + CFR`,减少段边界时间基不一致导致的画面卡顿。 - concat 流程启用 `+genpts` 重建时间戳,提升拼接后时间轴连续性。 - 对带旋转元数据的 MOV 素材会先做方向归一化,再进入分辨率判断和后续流程。 -- compose 阶段(视频轨+音频轨合并)使用 `-c:v copy` 流复制替代重编码,几乎瞬间完成。 +- compose 阶段(视频轨+音频轨合并)在**无需循环视频**时使用 `-c:v copy` 流复制;需要循环时才重编码。 - FFmpeg 子进程设有超时保护:`_run_ffmpeg()` 600 秒、`_get_duration()` 30 秒,防止畸形文件导致永久挂起。 ### 全局并发控制 @@ -203,7 +219,7 @@ pip install -r requirements.txt ### 3. 环境变量配置 -复制 `.env.example` 到 `.env` 并配置必要的 Key: +当前仓库使用 `backend/.env` 作为运行配置基准;请按你的环境替换敏感值并核对以下关键项(生产环境请勿提交真实密钥): ```ini # Supabase @@ -220,7 +236,13 @@ LATENTSYNC_GPU_ID=1 MUSETALK_GPU_ID=0 MUSETALK_API_URL=http://localhost:8011 MUSETALK_BATCH_SIZE=32 -LIPSYNC_DURATION_THRESHOLD=120 +LIPSYNC_DURATION_THRESHOLD=100 + +# MuseTalk 可调参数(示例) +MUSETALK_DETECT_EVERY=2 +MUSETALK_BLEND_CACHE_EVERY=2 +MUSETALK_ENCODE_CRF=14 +MUSETALK_ENCODE_PRESET=slow ``` ### 4. 启动服务 @@ -232,51 +254,11 @@ uvicorn app.main:app --host 0.0.0.0 --port 8006 --reload --- -## 🧩 服务集成指南 +## 🧩 开发约定与测试 -### 集成新模型 - -如果需要集成新的 AI 模型 (例如新的 TTS 引擎): - -1. 在 `app/services/` 下创建新的 Service 类 (如 `NewTTSService`)。 -2. 实现 `generate` 方法,可以使用 subprocess 调用,也可以是 HTTP 请求。 -3. **重要**: 如果模型占用 GPU,请务必使用 `asyncio.Lock` 进行并发控制,防止 OOM。 -4. 在 `app/modules/` 下创建对应模块,添加 router/service/schemas,并在 `main.py` 注册路由。 - -### 唇形同步混合路由 - -`lipsync_service.py` 实现了 LatentSync + MuseTalk 混合路由: -- 短视频 (<`LIPSYNC_DURATION_THRESHOLD`s) → LatentSync 1.6 (GPU1, 端口 8007) -- 长视频 (>=阈值) → MuseTalk 1.5 (GPU0, 端口 8011) -- MuseTalk 不可用时自动回退到 LatentSync -- 路由逻辑对 workflow 完全透明 - -### 添加定时任务 - -目前推荐使用 **APScheduler** 或 **Crontab** 来管理定时任务。 -社交媒体的定时发布功能目前依赖 `playwright` 的延迟执行,未来计划迁移到 Celery 队列。 - ---- - -## 🛡️ 错误处理 - -全项目统一使用 `Loguru` 进行日志记录。 - -```python -from loguru import logger - -try: - # 业务逻辑 -except Exception as e: - logger.error(f"操作失败: {str(e)}") - raise HTTPException(status_code=500, detail="服务器内部错误") -``` - ---- - -## 🧪 测试 - -运行测试套件: +- 新增模块、分层职责、统一响应、错误处理与调试规范请查看 `Docs/BACKEND_DEV.md`。 +- 建议在核心流程变更后做基础冒烟:登录、视频生成、发布。 +- 测试命令: ```bash pytest diff --git a/Docs/COSYVOICE3_DEPLOY.md b/Docs/COSYVOICE3_DEPLOY.md index 8b8834d..6d252cd 100644 --- a/Docs/COSYVOICE3_DEPLOY.md +++ b/Docs/COSYVOICE3_DEPLOY.md @@ -8,7 +8,7 @@ | 端口 | 8010 | | GPU | 0 (CUDA_VISIBLE_DEVICES=0) | | 推理精度 | FP16 (自动混合精度) | -| PM2 名称 | vigent2-cosyvoice (id=15) | +| PM2 名称 | vigent2-cosyvoice | | Conda 环境 | cosyvoice (Python 3.10) | | 启动脚本 | `run_cosyvoice.sh` | | 服务脚本 | `models/CosyVoice/cosyvoice_server.py` | diff --git a/Docs/DEPLOY_MANUAL.md b/Docs/DEPLOY_MANUAL.md index 5f21848..9ff6f42 100644 --- a/Docs/DEPLOY_MANUAL.md +++ b/Docs/DEPLOY_MANUAL.md @@ -97,7 +97,7 @@ python -m scripts.server # 测试能否启动,Ctrl+C 退出 ### 3b. MuseTalk 1.5 (长视频唇形同步, GPU0) -> MuseTalk 是单步潜空间修复模型(非扩散模型),推理速度接近实时,适合 >=120s 的长视频。与 CosyVoice 共享 GPU0,fp16 推理约需 4-8GB 显存。合成阶段使用 NVENC GPU 硬编码(h264_nvenc)+ 纯 numpy blending,避免双重编码和 PIL 转换开销。 +> MuseTalk 是单步潜空间修复模型(非扩散模型),推理速度接近实时,适合达到路由阈值的长视频(本仓库当前 `.env` 示例为 >=100s)。与 CosyVoice 共享 GPU0,fp16 推理约需 4-8GB 显存。合成阶段已改为 FFmpeg rawvideo 管道直编码(`libx264` + 可配 CRF/preset)并保留 numpy blending,减少中间有损文件。 请参考详细的独立部署指南: **[MuseTalk 部署指南](MUSETALK_DEPLOY.md)** @@ -136,17 +136,21 @@ pip install -r requirements.txt playwright install chromium ``` -> 提示:视频号发布建议使用系统 Chrome + xvfb-run(避免 headless 解码失败)。 -> 抖音发布同样建议 headful 模式 (`DOUYIN_HEADLESS_MODE=headful`)。 +> 提示:视频号发布建议使用系统 Chrome + xvfb-run(避免 headless 解码失败)。 +> 抖音发布同样建议 headful 模式 (`DOUYIN_HEADLESS_MODE=headful`)。 +> 四平台发布专项实现说明请见 `Docs/PUBLISH_DEPLOY.md`。 ### 扫码登录注意事项 - **Cookie 按用户隔离**:每个用户的 Cookie 存储在 `backend/user_data/{uuid}/cookies/` 目录下,多用户并发登录互不干扰。 -- **抖音 QR 登录关键教训**: - - 扫码后绝对**不能重新加载 QR 页面**,否则会销毁会话 token - - 使用**新标签页**检测登录完成状态(检查 URL 包含 `creator-micro` + session cookies 存在) - - 抖音可能弹出**刷脸验证**,后端会自动提取验证二维码返回给前端展示 -- **微信视频号发布**:标题、描述、标签统一写入"视频描述"字段 +- **抖音 QR 登录关键教训**: + - 扫码后绝对**不能重新加载 QR 页面**,否则会销毁会话 token + - 使用**新标签页**检测登录完成状态(检查 URL 包含 `creator-micro` + session cookies 存在) + - 抖音可能弹出**刷脸验证**,后端会自动提取验证二维码返回给前端展示 +- **小红书 QR 登录关键点**: + - 创作平台默认可能是短信登录视图,需先切换到扫码登录再抓取二维码 + - 扫码后可能跳转 `creator.xiaohongshu.com/new/home`,不一定命中旧 `publish` 成功指示 URL +- **微信视频号发布**:标题、描述、标签统一写入"视频描述"字段 --- @@ -195,24 +199,21 @@ playwright install chromium ## 步骤 7: 配置环境变量 -```bash -cd /home/rongye/ProgramFiles/ViGent2/backend - -# 复制配置模板 -cp .env.example .env -``` - -> 💡 **说明**:`.env.example` 已包含正确的默认配置,直接复制即可使用。 -> 如需自定义,可编辑 `.env` 修改以下参数: - -| 配置项 | 默认值 | 说明 | -|--------|--------|------| -| `SUPABASE_URL` | `http://localhost:8008` | Supabase API 内部地址 | -| `SUPABASE_PUBLIC_URL` | `https://api.hbyrkj.top` | Supabase API 公网地址 (前端访问) | -| `LATENTSYNC_GPU_ID` | 1 | GPU 选择 (0 或 1) | -| `LATENTSYNC_USE_SERVER` | false | 设为 true 以启用常驻服务加速 | -| `LATENTSYNC_INFERENCE_STEPS` | 20 | 推理步数 (16-50) | -| `LATENTSYNC_GUIDANCE_SCALE` | 2.0 | 引导系数 (1.0-3.0) | +```bash +cd /home/rongye/ProgramFiles/ViGent2/backend +``` + +> 💡 **说明**:当前仓库直接使用 `backend/.env`。请按你的环境替换敏感值并确认以下参数。 +> 如需自定义,可编辑 `.env` 修改以下参数: + +| 配置项 | 当前示例值 | 说明 | +|--------|------------|------| +| `SUPABASE_URL` | `http://localhost:8008` | Supabase API 内部地址 | +| `SUPABASE_PUBLIC_URL` | `https://api.hbyrkj.top` | Supabase API 公网地址 (前端访问) | +| `LATENTSYNC_GPU_ID` | 1 | GPU 选择 (0 或 1) | +| `LATENTSYNC_USE_SERVER` | true | 设为 true 以启用常驻服务加速 | +| `LATENTSYNC_INFERENCE_STEPS` | 30 | 推理步数 (16-50) | +| `LATENTSYNC_GUIDANCE_SCALE` | 1.9 | 引导系数 (1.0-3.0) | | `LATENTSYNC_ENABLE_DEEPCACHE` | true | DeepCache 推理加速 | | `LATENTSYNC_SEED` | 1247 | 固定随机种子(可复现) | | `DEBUG` | true | 生产环境改为 false | @@ -229,19 +230,26 @@ cp .env.example .env | `DOUYIN_CHROME_PATH` | `/usr/bin/google-chrome` | 抖音 Chrome 路径 | | `DOUYIN_BROWSER_CHANNEL` | | 抖音 Chromium 通道 (可选) | | `DOUYIN_USER_AGENT` | Chrome/144 UA | 抖音浏览器指纹 UA | -| `DOUYIN_LOCALE` | zh-CN | 抖音语言环境 | -| `DOUYIN_TIMEZONE_ID` | Asia/Shanghai | 抖音时区 | -| `DOUYIN_FORCE_SWIFTSHADER` | true | 强制软件 WebGL | -| `DOUYIN_DEBUG_ARTIFACTS` | false | 保留调试截图 | -| `DOUYIN_RECORD_VIDEO` | false | 录制浏览器操作视频 | -| `DOUYIN_KEEP_SUCCESS_VIDEO` | false | 成功后保留录屏 | +| `DOUYIN_LOCALE` | zh-CN | 抖音语言环境 | +| `DOUYIN_TIMEZONE_ID` | Asia/Shanghai | 抖音时区 | +| `DOUYIN_FORCE_SWIFTSHADER` | true | 强制软件 WebGL | +| `XIAOHONGSHU_HEADLESS_MODE` | headless-new | 小红书 Playwright 模式 (headful/headless-new) | +| `XIAOHONGSHU_CHROME_PATH` | `/usr/bin/google-chrome` | 小红书 Chrome 路径 | +| `XIAOHONGSHU_BROWSER_CHANNEL` | | 小红书 Chromium 通道 (可选) | +| `XIAOHONGSHU_USER_AGENT` | Chrome/144 UA | 小红书浏览器指纹 UA | +| `XIAOHONGSHU_LOCALE` | zh-CN | 小红书语言环境 | +| `XIAOHONGSHU_TIMEZONE_ID` | Asia/Shanghai | 小红书时区 | +| `XIAOHONGSHU_FORCE_SWIFTSHADER` | true | 强制软件 WebGL | +| `DOUYIN_DEBUG_ARTIFACTS` | false | 保留调试截图 | +| `DOUYIN_RECORD_VIDEO` | false | 录制浏览器操作视频 | +| `DOUYIN_KEEP_SUCCESS_VIDEO` | false | 成功后保留录屏 | | `CORS_ORIGINS` | `*` | CORS 允许源 (生产环境建议白名单) | | `MUSETALK_GPU_ID` | 0 | MuseTalk GPU 编号 | | `MUSETALK_API_URL` | `http://localhost:8011` | MuseTalk 常驻服务地址 | | `MUSETALK_BATCH_SIZE` | 32 | MuseTalk 推理批大小 | | `MUSETALK_VERSION` | v15 | MuseTalk 模型版本 | | `MUSETALK_USE_FLOAT16` | true | MuseTalk 半精度加速 | -| `LIPSYNC_DURATION_THRESHOLD` | 120 | 秒,>=此值用 MuseTalk,<此值用 LatentSync | +| `LIPSYNC_DURATION_THRESHOLD` | 100 | 秒,>=此值用 MuseTalk,<此值用 LatentSync(代码默认 120,建议在 `.env` 显式配置) | | `ALIPAY_APP_ID` | 空 | 支付宝应用 APPID | | `ALIPAY_PRIVATE_KEY_PATH` | 空 | 应用私钥 PEM 文件路径 | | `ALIPAY_PUBLIC_KEY_PATH` | 空 | 支付宝公钥 PEM 文件路径 | @@ -402,7 +410,7 @@ curl http://localhost:8010/health ### 5. 启动 MuseTalk 长视频唇形同步服务 -> 长视频 (>=120s) 自动路由到 MuseTalk。MuseTalk 不可用时自动回退 LatentSync。 +> 达到阈值(当前 `.env` 示例为 >=100s)自动路由到 MuseTalk。MuseTalk 不可用时自动回退 LatentSync。 > 详细部署步骤见 [MuseTalk 部署指南](MUSETALK_DEPLOY.md)。 1. 启动脚本位于项目根目录: `run_musetalk.sh` diff --git a/Docs/DevLogs/Day30.md b/Docs/DevLogs/Day30.md index 7c98fbb..4c6f331 100644 --- a/Docs/DevLogs/Day30.md +++ b/Docs/DevLogs/Day30.md @@ -1,8 +1,8 @@ -## Remotion 缓存修复 + 编码流水线质量优化 + 唇形同步容错 + 模型选择 (Day 30) +## Remotion 缓存修复 + 编码流水线质量优化 + 唇形同步容错 + 统一下拉交互 (Day 30) ### 概述 -本轮解决四大方面:(1) Remotion bundle 缓存导致标题/字幕丢失的严重 Bug;(2) 全面优化 LatentSync + MuseTalk 双引擎编码流水线,消除冗余有损编码;(3) 增强 LatentSync 的鲁棒性,允许素材中部分帧检测不到人脸时继续推理而非中断任务;(4) 前端唇形模型选择,用户可按需切换默认/快速/高级模型。 +本轮最终合并为五大方面:(1) Remotion bundle 缓存导致标题/字幕丢失的严重 Bug;(2) 全面优化 LatentSync + MuseTalk 双引擎编码流水线,消除冗余有损编码;(3) 增强 LatentSync 的鲁棒性,允许素材中部分帧检测不到人脸时继续推理而非中断任务;(4) 唇形模型选择全链路透传(默认/快速/高级);(5) 首页与发布页选择器统一为 SelectPopover 交互,并修复遮挡、定位与预览层级问题。 --- @@ -278,66 +278,102 @@ needs_audio_compose = str(final_audio_path) != str(audio_path) --- -### 6. 唇形模型前端选择 - -前端生成按钮右侧新增模型下拉,用户可按需选择唇形同步引擎,全链路透传到后端路由。 - -#### 模型选项 - -| 选项 | 值 | 路由逻辑 | -|------|------|------| -| 默认模型 | `default` | 保持现有阈值策略(`LIPSYNC_DURATION_THRESHOLD` 分水岭,短视频 LatentSync,长视频 MuseTalk) | -| 快速模型 | `fast` | 强制 MuseTalk,不可用时回退 LatentSync | -| 高级模型 | `advanced` | 强制 LatentSync,跳过 MuseTalk | - -三种模式最终都有 LatentSync 兜底,不会出现无模型可用的情况。 - -#### 数据流 - -``` -前端 select → setLipsyncModelMode("fast") → localStorage 持久化 - ↓ -用户点击"生成视频" → handleGenerate() - → payload.lipsync_model = lipsyncModelMode - → POST /api/videos/generate { ..., lipsync_model: "fast" } - → workflow: req.lipsync_model 透传给 lipsync.generate(model_mode=...) - → lipsync_service.generate(): 按 model_mode 路由 - → fast: 强制 MuseTalk → 回退 LatentSync - → advanced: 强制 LatentSync - → default: 阈值策略 -``` - -#### 改动文件 - -| 文件 | 改动 | -|------|------| -| `frontend/src/features/home/ui/GenerateActionBar.tsx` | 生成按钮右侧新增模型 `` 升级为统一 `SelectPopover` +- 触发器文案改为业务语义(`默认模型 / 快速模型 / 高级模型` + `按时长智能路由 / 速度优先 / 质量优先`) +- 选择状态持久化到 `useHomePersistence`(`lipsyncModelMode`) + +#### 数据流 + +``` +前端 SelectPopover → setLipsyncModelMode("fast") → localStorage 持久化 + ↓ +用户点击"生成视频" → handleGenerate() + → payload.lipsync_model = lipsyncModelMode + → POST /api/videos/generate { ..., lipsync_model: "fast" } + → workflow: req.lipsync_model 透传给 lipsync.generate(model_mode=...) + → lipsync_service.generate(): 按 model_mode 路由 + → fast: 强制 MuseTalk → 回退 LatentSync + → advanced: 强制 LatentSync + → default: 阈值策略 +``` + +--- + +### 7. 首页/发布页统一下拉交互(SelectPopover) + +#### 7a. 统一改造范围 + +首页与发布页的业务选择项统一迁移到 `SelectPopover`: + +- 首页:音色、参考音频、配音列表、素材选择、BGM 选择、作品选择、标题显示模式、标题/副标题/字幕样式、时间轴画面比例、唇形模型 +- 发布页:选择发布作品(搜索 + 预览) + +例外:`ScriptEditor` 的“历史文案 / AI多语言”按产品要求恢复为原有轻量菜单,不强制统一。 + +#### 7b. 关键交互修复 + +- **遮挡修复**:桌面端面板改为 `Portal + fixed`,脱离局部 stacking context,彻底解决被卡片遮挡 +- **上拉/下拉自适应**:底部空间不足时自动上拉,避免菜单显示不全 +- **同宽展示**:面板宽度与触发器保持一致 +- **风格统一**:面板背景加实(高不透明度),滚动条隐藏但可滚动 +- **已选定位**:再次打开下拉时自动滚动到已选项(`data-popover-selected="true"`) +- **预览协同**: + - 下拉内点“预览”不强制关闭,支持连续预览 + - 视频预览弹窗层级高于下拉,避免被遮挡 + - 预览弹窗打开时,下拉不会因外部点击/Esc被误关闭;关闭预览后仍可继续操作 + +#### 7c. BGM 面板收敛 + +- BGM 改为与“发布作品”同款选择器(搜索 + 列表 + 试听 + 选中态) +- 按产品要求移除首页 BGM 音量滑杆 +- 生成请求统一使用固定 `bgm_volume=0.2` + +--- ## 📁 总修改文件清单 -| 文件 | 改动 | -|------|------| -| `remotion/render.ts` | bundle 缓存使用时硬链接视频+字体到 public 目录 | -| `models/LatentSync/latentsync/utils/util.py` | `read_video` 检测 FPS,25fps 时跳过重编码 | -| `models/LatentSync/latentsync/pipelines/lipsync_pipeline.py` | final mux `-c:v copy`;无脸帧容错 | -| `backend/app/services/video_service.py` | CRF 23→18;`concat_videos` copy;`compose()` 异步化 + 循环 CRF 18 | -| `backend/app/modules/videos/workflow.py` | 线程池化;同分辨率跳过 scale;compose 跳过;片段校验;模型选择透传 | -| `backend/app/modules/videos/schemas.py` | 新增 `lipsync_model` 字段 | -| `backend/app/services/lipsync_service.py` | `generate()` 新增 `model_mode` 三路分支路由 | -| `models/MuseTalk/scripts/server.py` | FFmpeg rawvideo 管道;参数环境变量化 | -| `backend/.env` | 新增 MuseTalk 质量优先参数 | -| `frontend/src/features/home/ui/GenerateActionBar.tsx` | 模型下拉 UI | -| `frontend/src/features/home/ui/HomePage.tsx` | 模型状态透传 | -| `frontend/src/features/home/model/useHomeController.ts` | `lipsyncModelMode` state + payload | -| `frontend/src/features/home/model/useHomePersistence.ts` | 模型选择持久化 | +| 文件 | 改动 | +|------|------| +| `remotion/render.ts` | bundle 缓存使用时硬链接视频+字体到 public 目录 | +| `models/LatentSync/latentsync/utils/util.py` | `read_video` 检测 FPS,25fps 时跳过重编码 | +| `models/LatentSync/latentsync/pipelines/lipsync_pipeline.py` | final mux `-c:v copy`;无脸帧容错 | +| `backend/app/services/video_service.py` | CRF 23→18;`concat_videos` copy;`compose()` 异步化 + 循环 CRF 18 | +| `backend/app/modules/videos/workflow.py` | 线程池化;同分辨率跳过 scale;compose 跳过;片段校验;模型选择透传 | +| `backend/app/modules/videos/schemas.py` | 新增 `lipsync_model` 字段 | +| `backend/app/services/lipsync_service.py` | `generate()` 新增 `model_mode` 三路分支路由 | +| `models/MuseTalk/scripts/server.py` | FFmpeg rawvideo 管道;参数环境变量化 | +| `backend/.env` | MuseTalk 推理/融合/编码参数可配;路由阈值与质量档调优 | +| `frontend/src/shared/ui/SelectPopover.tsx` | 新增统一选择器:Portal+fixed、防遮挡、上拉/下拉自适应、同宽、隐藏滚动条、已选定位、预览协同 | +| `frontend/src/features/home/ui/HomePage.tsx` | 配音卡层级修复;传递统一下拉状态 | +| `frontend/src/features/home/model/useHomeController.ts` | `lipsyncModelMode` 透传;BGM 固定 `bgm_volume=0.2` | +| `frontend/src/features/home/model/useHomePersistence.ts` | 模型模式等新增字段持久化 | +| `frontend/src/features/home/ui/GenerateActionBar.tsx` | 模型选择改为 SelectPopover(速度/质量语义文案) | +| `frontend/src/features/home/ui/VoiceSelector.tsx` | 音色选择统一为 SelectPopover(音色名+语言) | +| `frontend/src/features/home/ui/RefAudioPanel.tsx` | 参考音频选择统一为 SelectPopover(含试听/重命名/删除/重识别) | +| `frontend/src/features/home/ui/GeneratedAudiosPanel.tsx` | 配音列表、语速、语气统一为 SelectPopover | +| `frontend/src/features/home/ui/MaterialSelector.tsx` | 素材选择改为发布页同款下拉(搜索/多选/预览/重命名/删除) | +| `frontend/src/features/home/ui/BgmPanel.tsx` | BGM 选择改为发布页同款下拉(搜索+试听),移除音量滑杆 | +| `frontend/src/features/home/ui/HistoryList.tsx` | 首页作品选择改为下拉(搜索+删除+选中态) | +| `frontend/src/features/home/ui/TitleSubtitlePanel.tsx` | 标题显示模式与样式选择统一为 SelectPopover | +| `frontend/src/features/home/ui/TimelineEditor.tsx` | 画面比例选择统一为 SelectPopover(单行按钮) | +| `frontend/src/features/publish/ui/PublishPage.tsx` | 发布作品选择改为 SelectPopover;预览时下拉保持打开 | +| `frontend/src/components/VideoPreviewModal.tsx` | 提升层级并添加预览标记,与下拉联动 | +| `frontend/src/features/home/ui/ScriptEditor.tsx` | 历史文案/AI多语言恢复原轻量菜单(产品例外) | +| `Docs/FRONTEND_DEV.md` | 新增 SelectPopover 规范、预览层级规范、持久化字段修订 | --- @@ -358,6 +394,12 @@ needs_audio_compose = str(final_audio_path) != str(audio_path) 13. **compose 循环 CRF**: 循环场景编码应为 CRF 18(非 23) 14. **模型选择 UI**: 生成按钮右侧应出现默认模型/快速模型/高级模型下拉 15. **模型选择持久化**: 切换模型后刷新页面,下拉应恢复上次选择 -16. **快速模型路由**: 选择"快速模型"时,后端日志应出现 `强制快速模型:MuseTalk` -17. **高级模型路由**: 选择"高级模型"时,后端日志应出现 `强制高级模型:LatentSync` -18. **默认模型不变**: 选择"默认模型"时行为与改动前完全一致(阈值路由) +16. **快速模型路由**: 选择"快速模型"时,后端日志应出现 `强制快速模型:MuseTalk` +17. **高级模型路由**: 选择"高级模型"时,后端日志应出现 `强制高级模型:LatentSync` +18. **默认模型不变**: 选择"默认模型"时行为与改动前完全一致(阈值路由) +19. **统一下拉样式**: 首页/发布页业务选择项均为同款 SelectPopover(触发器 + 面板 + 选中态) +20. **上拉自适应**: 页面底部打开下拉时应自动上拉,不出现被截断 +21. **已选定位**: 任意下拉再次打开时应自动定位到已选项,而非列表顶端 +22. **预览层级**: 视频预览弹窗应始终覆盖在下拉之上,不被菜单遮挡 +23. **连续预览**: 下拉内点击预览后菜单保持打开,关闭预览后可继续点击其他预览项 +24. **BGM 行为**: 首页 BGM 不再显示音量滑杆,生成请求固定 `bgm_volume=0.2` diff --git a/Docs/DevLogs/Day31.md b/Docs/DevLogs/Day31.md new file mode 100644 index 0000000..1fd0228 --- /dev/null +++ b/Docs/DevLogs/Day31.md @@ -0,0 +1,404 @@ +## 文档分层收敛 + 音色试听修复 + 录音弹窗重构 + 弹窗体系统一 (Day 31) + +### 概述 + +今天的工作聚焦四件事: + +1. 清理并收敛根目录文档(README/DEV 职责边界、历史内容归档、参数描述与代码对齐) +2. 完成 EdgeTTS 音色列表「一键试听」能力,并修复浏览器端试听失败问题 +3. 重构声音克隆录音交互:录音入口下沉到参考音频区域底部右侧,流程改为弹窗 +4. 抽离统一弹窗基座 `AppModal`,将主要弹窗迁移到同一视觉和交互规范 + +--- + +## ✅ 1) 文档体系与内容一致性优化 + +### 1.1 README / DEV 边界明确 + +- 为 `FRONTEND_README.md`、`BACKEND_README.md`、`FRONTEND_DEV.md`、`BACKEND_DEV.md` 增加「文档定位」 +- README 只保留稳定说明(功能、接口、运行),DEV 保留规范(约束、分层、Checklist) +- 将 README 中偏日志化内容(如 Day 标注)清理为稳定表述 + +### 1.2 部署与参数文档对齐当前代码 + +- 将唇形路由阈值文案统一为阈值驱动,并以当前 `.env` 示例 `100` 为参考 +- 修正旧编码描述(将 MuseTalk 合成描述对齐为 rawvideo 管道 + `libx264`) +- 修复文档中不存在的 `.env.example` 指引,改为基于 `backend/.env` 的说明 +- 将 Qwen3-TTS 文档标注为「历史归档(已停用)」并指向 CosyVoice 3.0 + +--- + +## ✅ 2) 音色试听能力落地与故障修复 + +### 2.1 功能实现 + +- 音色下拉项新增试听按钮(播放/暂停/加载态) +- 新增后端试听接口:`/api/videos/voice-preview` +- 试听文本按音色 locale 自动选择固定示例文案(9 国语言 + 中文兜底) + +### 2.2 兼容与稳定性调整 + +- 保留 `POST /api/videos/voice-preview`(兼容) +- 新增 `GET /api/videos/voice-preview?voice=...`,前端改为直接播放 GET 音频流,减少浏览器自动播放策略干扰 + +```python +@router.get("/voice-preview") +async def preview_voice_get(voice: str, current_user: dict = Depends(get_current_user)): + voice_value = voice.strip() + if not voice_value: + raise HTTPException(status_code=400, detail="voice 不能为空") + text = _get_preview_text_for_voice(voice_value) + return await _render_voice_preview(voice=voice_value, text=text) +``` + +### 2.3 本次线上问题结论(已修复) + +- 现象:浏览器端试听请求 404 +- 根因:新增 GET 路由后,后端进程未重启,运行中的代码仍是旧版本 +- 处理:`pm2 restart vigent2-backend` 后路由生效 +- 补充:`curl` 返回 401(无 auth cookie)属于预期;浏览器同源请求会自动带 cookie + +--- + +## ✅ 3) 录音交互重构(声音克隆) + +### 3.1 入口重排 + +- 去掉参考音频面板内的独立录音大块区域 +- 将「上传音频 / 录音」入口放到「我的参考音频」区域底部右侧 + +### 3.2 录音流程改为弹窗 + +- 录音弹窗支持:开始录音 / 停止录音 / 状态计时 / 试听 +- 保留并强化「使用此录音」和「弃用本次录音」 +- 关闭弹窗时若仍在录音,会先停止录音再关闭 +- 修正弹窗挂载位置:从局部组件渲染改为 `AppModal` Portal 到 `document.body`,确保是全页面弹窗体验 +- 参考音频区按钮文案更新:`录音` -> `在线录音` + +### 3.4 文案区按钮视觉统一 + +- 统一「文案提取与编辑」区按钮尺寸与圆角(`px-3 py-1.5 text-xs rounded-lg`) +- 将 `AI智能改写`、`保存文案` 按钮改为与上传/在线录音同等级的视觉规格 +- 同步统一图标尺寸与禁用态样式,消除“底部按钮偏小”问题 + +### 3.5 录音试听条 UI 美化 + +- 将录音完成后的原生白色 `