feat(#1677): 多视频批量生成前端 — 数量弹窗/批量预览/独立标题配音封面/5步流程 #1704

Merged
auto-approve-bot merged 3 commits from feat/1677-batch-generation into develop 2026-09-05 09:03:43 +08:00
Owner

关联 Issue

Closes #1677

后端依赖

PR #1701(已合并部署 staging,commit c1763b99):POST /generation/preview 支持 preview_count 返回 {items:[...N变体], total}POST /generation/tasks 支持 count + titles[]/voice_library_ids[]/cover_urls[](长度1=共用、长度N=独立、空数组=回退旧逻辑)。

改动内容

流程:6步 → 5步

模板 → 素材 → 配音 → 标题(含确认生成)→ 封面;删除 Step7ConfirmGenerate / useStep7Generate / SummaryCard 冗余组件。

1. 数量弹窗(Step1)

  • 选模板点「下一步」弹窗「要生成几个视频?」,1~10,默认1,回车=1,Esc 取消
  • 选1:单视频模式,全程走原有 Canvas 实时预览链路,零回归
  • 选N(>1):批量模式

2. 标题页布局对调 + 合并确认生成(Step4)

  • 左侧大区域:单视频=FrontendPreviewPlayer 实时预览(不变);批量=ServerPreviewGrid 服务器预览网格,N 个卡片各自独立播放、独立进度轮询、失败态、勾选框(默认全选)、CSS 标题浮层(位置/字体随全局样式)
  • 右边栏:标题样式全局统一(字体/颜色/位置/大小);批量时 N 个独立标题输入框实时叠加浮层;单视频保留 AI 标题生成器 + AutoComplete
  • 底部固定「确认生成 N 个视频」(N=勾选数);生成中显示进度,完成后「下一步:选择封面」

3. 批量预览

  • 进标题页自动 POST /previewpreview_count=N,对返回的 N 个 task_id 分别 GET /preview/{task_id} 并行轮询
  • 指纹检测:素材/配音/数量/BGM/标题样式变化才重渲染(标题文字变化只更新浮层不重渲染)

4. 配音(Step3)

  • 默认共用一个配音(UI 不变);开关切换后 N 个紧凑配音选择器各自独立
  • 共用:不传 voice_library_ids[](回退旧单值字段);独立:传长度 N 数组

5. 封面(Step5)

  • N 张封面卡片按勾选顺序展示(与成片顺序对齐),各自带变体标题
  • 逐个 AI 生成(传对应 generated_video_id)或上传(素材库 image 库);一键全部生成
  • 未设置封面的变体传空串,后端回退智能封面

6. 正式生成

  • POST /taskscount=勾选数 + titles[]/voice_library_ids[](仅独立配音)/cover_urls[](按勾选索引映射)
  • 批量任务并行轮询,平均进度聚合,全部完成后跳转封面步骤

验收红线

  • N=1 零回归:不传任何数组字段,Canvas 预览、AI标题、单封面流程与旧版完全一致
  • N=3:3 个独立预览(各自可播放、独立标题浮层)、独立配音可选、勾选后批量生成 3 条成片、3 张封面

本地验证

  • tsc --noEmit 0 错误;eslint 0 error;prettier 已格式化;vitest 4/4 passed;npm run build 成功
## 关联 Issue Closes #1677 ## 后端依赖 PR #1701(已合并部署 staging,commit c1763b99):`POST /generation/preview` 支持 `preview_count` 返回 `{items:[...N变体], total}`;`POST /generation/tasks` 支持 `count` + `titles[]`/`voice_library_ids[]`/`cover_urls[]`(长度1=共用、长度N=独立、空数组=回退旧逻辑)。 ## 改动内容 ### 流程:6步 → 5步 模板 → 素材 → 配音 → 标题(含确认生成)→ 封面;删除 Step7ConfirmGenerate / useStep7Generate / SummaryCard 冗余组件。 ### 1. 数量弹窗(Step1) - 选模板点「下一步」弹窗「要生成几个视频?」,1~10,默认1,回车=1,Esc 取消 - 选1:单视频模式,全程走原有 Canvas 实时预览链路,**零回归** - 选N(>1):批量模式 ### 2. 标题页布局对调 + 合并确认生成(Step4) - 左侧大区域:单视频=FrontendPreviewPlayer 实时预览(不变);批量=ServerPreviewGrid 服务器预览网格,N 个卡片各自独立播放、独立进度轮询、失败态、勾选框(默认全选)、CSS 标题浮层(位置/字体随全局样式) - 右边栏:标题样式全局统一(字体/颜色/位置/大小);批量时 N 个独立标题输入框实时叠加浮层;单视频保留 AI 标题生成器 + AutoComplete - 底部固定「确认生成 N 个视频」(N=勾选数);生成中显示进度,完成后「下一步:选择封面」 ### 3. 批量预览 - 进标题页自动 `POST /preview` 传 `preview_count=N`,对返回的 N 个 task_id 分别 `GET /preview/{task_id}` 并行轮询 - 指纹检测:素材/配音/数量/BGM/标题样式变化才重渲染(标题文字变化只更新浮层不重渲染) ### 4. 配音(Step3) - 默认共用一个配音(UI 不变);开关切换后 N 个紧凑配音选择器各自独立 - 共用:不传 voice_library_ids[](回退旧单值字段);独立:传长度 N 数组 ### 5. 封面(Step5) - N 张封面卡片按勾选顺序展示(与成片顺序对齐),各自带变体标题 - 逐个 AI 生成(传对应 generated_video_id)或上传(素材库 image 库);一键全部生成 - 未设置封面的变体传空串,后端回退智能封面 ### 6. 正式生成 - `POST /tasks` 传 `count`=勾选数 + `titles[]`/`voice_library_ids[]`(仅独立配音)/`cover_urls[]`(按勾选索引映射) - 批量任务并行轮询,平均进度聚合,全部完成后跳转封面步骤 ## 验收红线 - **N=1 零回归**:不传任何数组字段,Canvas 预览、AI标题、单封面流程与旧版完全一致 - N=3:3 个独立预览(各自可播放、独立标题浮层)、独立配音可选、勾选后批量生成 3 条成片、3 张封面 ## 本地验证 - tsc --noEmit 0 错误;eslint 0 error;prettier 已格式化;vitest 4/4 passed;npm run build 成功
xiaoxia added 1 commit 2026-09-05 07:59:34 +08:00
feat(#1677): 多视频批量生成前端 — 数量弹窗/批量预览/独立标题配音封面/5步流程
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 5s
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 3s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m58s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m12s
AI Code Review / AI Code Review (pull_request) Failing after 3m30s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Failing after 10m10s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m42s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 1m50s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 2m7s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 10m53s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 4m21s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
970380662e
- Step1 选模板后弹数量弹窗(1-10),1=单视频零回归,N>1=批量模式
- Step4 标题页布局对调:左侧大区域预览(单=Canvas实时预览,批量=服务器预览网格),
  右边栏标题设置;批量时N个独立标题输入框+CSS浮层实时叠加
- 确认生成合并进标题页:预览卡片带勾选框(默认全选),底部确认生成N个视频
- 批量预览:POST /preview 传 preview_count,N个task_id并行轮询
- Step3 配音:共用/独立开关,独立模式N个紧凑选择器,提交 voice_library_ids[]
- 封面步骤:N张封面卡片按勾选顺序展示,逐个AI生成/上传,提交 cover_urls[]
- 正式生成:POST /tasks 传 count + titles[]/voice_library_ids[]/cover_urls[]
  (长度1共用/长度N独立/空数组回退旧逻辑),批量任务并行轮询平均进度
- STEPS 6步→5步(模板/素材/配音/标题/封面),删除Step7确认生成冗余组件
xiaoxia added 1 commit 2026-09-05 08:38:27 +08:00
fix(#1677): AI Review 阻塞项修复 — 配音模式切换同步+预览标题双重叠加
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 9s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 10s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 2m12s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m58s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 2m32s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 3m24s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 3m45s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 2m59s
AI Code Review / AI Code Review (pull_request) Failing after 4m29s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 5m10s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 5s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Failing after 11m0s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
b0ea3565ee
- 配音同步 effect 响应模式切换:独立→共用时所有变体刷成共用配音;
  独立模式下共用配音变化仅同步变体[0],不覆盖用户单独选择
- 批量预览不再传 titles/title_config 给后端:标题由 CSS 浮层实时叠加,
  避免服务器预览视频烧录标题后与前端浮层双重显示;
  buildPreviewRequest 移除 titleSettings 依赖及 eslint-disable;
  预览指纹不含 titles,标题文字/样式变化不触发重渲染

🚀 预览环境已部署

项目 详情
PR号 #1704
预览链接 https://pr-1704.preview.xiaoxiajianji.com
API环境 staging

💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。

🔄 每次提交新代码后预览环境会自动更新。

🗑️ PR 关闭或合并后,预览环境会自动清理。

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1704 | | 预览链接 | [https://pr-1704.preview.xiaoxiajianji.com](https://pr-1704.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
Collaborator

【阻塞级判定】

  • 是否存在阻塞级问题:是
  • 阻塞级问题数量:1 个

📊 审查概览

  • 整体评价:需修改
  • 建议级问题数量:1 个

🔴 阻塞级问题(必须修复)

  1. [apps/web/src/pages/generate/GeneratePage.tsx: 357, 361, 363, 95] 状态更新函数中存在空指针风险
    • 问题类型:逻辑bug
    • 问题描述:在 handleCountConfirmuseEffect 中,多处使用了 setState 的函数式更新(如 setPreviewTitles((prev) => ...)),代码中直接访问了 prev[0]prev[i] 或调用 prev.map()。如果初始状态(prev)为 undefinednull(例如页面刚加载未经过初始化流程,或状态被重置时),这些操作会抛出 TypeError: Cannot read properties of undefined 导致页面崩溃。
    • 修改建议:在访问 prev 之前添加默认空数组回退。例如:
      • setPreviewTitles((prev) => { const p = prev || []; ... })
      • setVoiceLibraryIds((prev) => Array.from({ length: count }, (_, i) => (prev || [])[i] ?? ...))
      • setVoiceLibraryIds((prevIds) => (prevIds || []).map(...))

💡 改进建议(不阻塞合并)

  1. [apps/web/src/pages/generate/GeneratePage.tsx: 656] 冗余代码
    • 具体内容:poster={finalVideo.thumbnail_url || undefined} 中的 || undefined 是冗余的,当 thumbnail_url 为 falsy 值时,直接传递该值即可,React 会自动处理。建议简化为 poster={finalVideo.thumbnail_url}

良好实践

  • 使用 useCallbackuseMemobuildPreviewRequestpreviewReady 等进行优化,避免不必要的重渲染。
  • 引入 prevVoiceSyncRef 来处理配音同步逻辑,有效避免了 useEffect 的依赖循环问题。
  • 批量预览和单视频预览的逻辑分离清晰,通过 isBatch 标志控制,便于维护。

格式检查通过 | 逻辑审查需修改 | 性能良好


🤖 由 AI 代码审查机器人自动生成 | 2026-09-05 00:43:11 | 模型:

### 【阻塞级判定】 - 是否存在阻塞级问题:是 - 阻塞级问题数量:1 个 ### 📊 审查概览 - 整体评价:需修改 - 建议级问题数量:1 个 ### 🔴 阻塞级问题(必须修复) 1. **[apps/web/src/pages/generate/GeneratePage.tsx: 357, 361, 363, 95] 状态更新函数中存在空指针风险** - 问题类型:逻辑bug - 问题描述:在 `handleCountConfirm` 和 `useEffect` 中,多处使用了 `setState` 的函数式更新(如 `setPreviewTitles((prev) => ...)`),代码中直接访问了 `prev[0]`、`prev[i]` 或调用 `prev.map()`。如果初始状态(`prev`)为 `undefined` 或 `null`(例如页面刚加载未经过初始化流程,或状态被重置时),这些操作会抛出 `TypeError: Cannot read properties of undefined` 导致页面崩溃。 - 修改建议:在访问 `prev` 之前添加默认空数组回退。例如: - `setPreviewTitles((prev) => { const p = prev || []; ... })` - `setVoiceLibraryIds((prev) => Array.from({ length: count }, (_, i) => (prev || [])[i] ?? ...))` - `setVoiceLibraryIds((prevIds) => (prevIds || []).map(...))` ### 💡 改进建议(不阻塞合并) 1. **[apps/web/src/pages/generate/GeneratePage.tsx: 656] 冗余代码** - 具体内容:`poster={finalVideo.thumbnail_url || undefined}` 中的 `|| undefined` 是冗余的,当 `thumbnail_url` 为 falsy 值时,直接传递该值即可,React 会自动处理。建议简化为 `poster={finalVideo.thumbnail_url}`。 ### ✅ 良好实践 - 使用 `useCallback` 和 `useMemo` 对 `buildPreviewRequest`、`previewReady` 等进行优化,避免不必要的重渲染。 - 引入 `prevVoiceSyncRef` 来处理配音同步逻辑,有效避免了 `useEffect` 的依赖循环问题。 - 批量预览和单视频预览的逻辑分离清晰,通过 `isBatch` 标志控制,便于维护。 --- ✅ 格式检查通过 | ❌ 逻辑审查需修改 | ✅ 性能良好 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-09-05 00:43:11 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
xiaoxia added 1 commit 2026-09-05 08:56:28 +08:00
fix(#1677): AI Review 防御性修复 — setState 函数式更新空数组兜底
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m34s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m51s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 2m0s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m17s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 2m20s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m38s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 2m40s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 6m13s
AI Code Review / AI Code Review (pull_request) Successful in 6m17s
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m40s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 16s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Failing after 10m59s
6846f68e03
- setPreviewTitles/setVoiceLibraryIds/setPreviewCovers/setSelectedVariantIds
  函数式更新中 prev 加 (prev || []) 兜底,防御状态重置场景
- 清理 poster={url || undefined} 冗余写法
auto-approve-bot approved these changes 2026-09-05 08:59:08 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot approved these changes 2026-09-05 08:59:08 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot merged commit af25045123 into develop 2026-09-05 09:03:43 +08:00
auto-approve-bot deleted branch feat/1677-batch-generation 2026-09-05 09:03:50 +08:00

🗑️ 预览环境已清理

PR #1704 已关闭或合并,对应的预览环境已被清理。

如有需要,可以重新打开 PR 来重新生成预览环境。

🗑️ **预览环境已清理** PR #1704 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Sign in to join this conversation.