fix(generate): #1750 批量预览五连修——删除假数据 fallback/配音时长/竖屏播放器/封面一键生成 #1751

Merged
auto-approve-bot merged 1 commits from feat/1750-preview-five-fixes into develop 2026-09-07 01:28:35 +08:00
Owner

工单

Closes #1750

五个问题

1. 配音列表不显示时长

  • Step5VoiceSelect 卡片底行:素材配音显示「14.7秒 / 345 KB」,AI 音色显示「按文本合成」,时长 0/缺失兜底「时长未知」
  • getDuration() 此前已存在但未使用,本次接线

2. 批量预览假数据根治(核心)

铁证根因variant-plans 接口后端从未实现(实测 404),前端静默降级到本地模拟(9 素材 × 5s = 45s),导致 3 个卡片都显示 45 秒。

  • 删除 fallback 本地模拟整条分支:variantSeed 轮换、seededRandom 随机偏移、duration_max 兜底、模板时长计算
  • 预览片段唯一来源 = 后端 variant-plans 返回的真实 clips;预览总时长 = serverClips 片段时长之和(成片时长=配音时长等比分配,后端 #1749 实现)
  • 接口失败/数据不完整 → 三态 UI 显示「预览加载失败,请重试」(9:16 占位防卡片塌陷,重试按钮仅变体 0 卡片),严禁假数据冒充预览
  • serverClips 引用的 asset_id 不在前端素材列表时,usePreviewAssets.ensureAssets 按差集补拉素材详情(竞态序号守卫),不再静默回退
  • playToken(0 基变体序号)替代 variantSeed 驱动批量播放互斥
  • useBatchVariantPlans 重写:error/retry 状态;retry 由 state nonce 驱动 effect 统一发请求(修复 retry 直调 load 与 effect 双发导致 requestSeq 竞争把成功结果丢弃)

3. 独立配音模式预览

  • 新增 useVariantVoicePreview:独立模式每卡片挂各自变体配音 URL(voiceLibraryIds[i],素材 id→file_url;AI 音色→按各自标题串行 TTS,Map 缓存 + AbortController + seq 防竞态);共用模式全变体同一条
  • 有配音时素材视频强制 muted(原声不与配音混音);无配音时素材原声兜底
  • 单视频链路加 isBatch 守卫,N=1 零回归

4. 竖屏播放器黑边

  • 结果页/生成中/批量网格播放器容器按视频实际宽高比自适应(9:16 竖放):video width:auto; max-width:100%; max-height:70vh; aspect-ratio:9/16,外包 flex 居中黑底容器
  • 竖屏成片(1080×1920)不再左右大黑边;N=1 单视频零回归

5. 封面「一键全部自动生成」

  • useBatchCovers.generateAll:一次点击收集所有未生成封面串行触发,失败单个不阻塞;分级 toast(全成功/部分失败 okCount/failCount/全失败/全已有封面 info)
  • onCoversChange 支持函数式 updater;busyIndexes/uploadingIndexes 改数组精确定位卡片 loading
  • 按钮 white-space:nowrap; flex-shrink:0,文案不再换行

配套清理

  • 删除死代码:PreviewVideoPanel、useServerPreview、calculateTotalVideoDuration、GenerateResultPanel、result-panel/ 目录
  • 模板时长概念全链路删除(基线:模板只定片段数/结构,无时长概念):模板库/我的模板/智能匹配/详情弹窗/筛选器;computeLimitFromSegments 改为纯「片段数 × 3」钳 [1,200];api 类型 duration_min/max/estimated_duration 标 @deprecated 改可选(兼容旧数据读取);editing-planner 编辑器内部 clip 时长属数据模型不在本次范围
  • 顺带修复全量测试 OOM 根因:useVariantVoicePreview 中 useQuery 解构 = [] 默认值每次渲染产生新数组 → effect 依赖变化 → setUrls 新数组 → 无限渲染循环,worker heap 爆掉。改用模块级稳定常量 EMPTY_VOICE_MATERIALS + 所有 setUrls 内容比较 bailout

测试

  • 全量 vitest:722 passed | 4 skipped(149 files + 1 skipped),此前 OOM 已消失
  • tsc --noEmit / eslint --max-warnings 0 / prettier / vite build 全绿
  • 重写适配测试:useBatchVariantPlans(11 例错误态/nonce retry/越界归一化)、FrontendPreviewPlayer.audio(8 例 serverClips/playToken)、CanvasPreviewGrid.audio(6 例三态/独立配音)、smart-match-pool(4 例新规则)

⚠️ 后端依赖 #1749

POST /api/v1/generation/variant-plans 接口上线前,staging 批量预览将显示「预览加载失败,请重试」——这是工单明确要求的行为(不许假数据)。后端接口部署后即自动恢复真实片段预览。

## 工单 Closes #1750 ## 五个问题 ### 1. 配音列表不显示时长 - `Step5VoiceSelect` 卡片底行:素材配音显示「14.7秒 / 345 KB」,AI 音色显示「按文本合成」,时长 0/缺失兜底「时长未知」 - `getDuration()` 此前已存在但未使用,本次接线 ### 2. 批量预览假数据根治(核心) **铁证根因**:`variant-plans` 接口后端从未实现(实测 404),前端静默降级到本地模拟(9 素材 × 5s = 45s),导致 3 个卡片都显示 45 秒。 - **删除 fallback 本地模拟整条分支**:variantSeed 轮换、seededRandom 随机偏移、duration_max 兜底、模板时长计算 - 预览片段唯一来源 = 后端 `variant-plans` 返回的真实 clips;预览总时长 = serverClips 片段时长之和(成片时长=配音时长等比分配,后端 #1749 实现) - 接口失败/数据不完整 → 三态 UI 显示「预览加载失败,请重试」(9:16 占位防卡片塌陷,重试按钮仅变体 0 卡片),**严禁假数据冒充预览** - serverClips 引用的 asset_id 不在前端素材列表时,`usePreviewAssets.ensureAssets` 按差集补拉素材详情(竞态序号守卫),不再静默回退 - `playToken`(0 基变体序号)替代 variantSeed 驱动批量播放互斥 - `useBatchVariantPlans` 重写:error/retry 状态;retry 由 state nonce 驱动 effect 统一发请求(修复 retry 直调 load 与 effect 双发导致 requestSeq 竞争把成功结果丢弃) ### 3. 独立配音模式预览 - 新增 `useVariantVoicePreview`:独立模式每卡片挂各自变体配音 URL(voiceLibraryIds[i],素材 id→file_url;AI 音色→按各自标题串行 TTS,Map 缓存 + AbortController + seq 防竞态);共用模式全变体同一条 - 有配音时素材视频强制 muted(原声不与配音混音);无配音时素材原声兜底 - 单视频链路加 `isBatch` 守卫,N=1 零回归 ### 4. 竖屏播放器黑边 - 结果页/生成中/批量网格播放器容器按视频实际宽高比自适应(9:16 竖放):video `width:auto; max-width:100%; max-height:70vh; aspect-ratio:9/16`,外包 flex 居中黑底容器 - 竖屏成片(1080×1920)不再左右大黑边;N=1 单视频零回归 ### 5. 封面「一键全部自动生成」 - `useBatchCovers.generateAll`:一次点击收集所有未生成封面串行触发,失败单个不阻塞;分级 toast(全成功/部分失败 okCount/failCount/全失败/全已有封面 info) - `onCoversChange` 支持函数式 updater;busyIndexes/uploadingIndexes 改数组精确定位卡片 loading - 按钮 `white-space:nowrap; flex-shrink:0`,文案不再换行 ## 配套清理 - **删除死代码**:PreviewVideoPanel、useServerPreview、calculateTotalVideoDuration、GenerateResultPanel、result-panel/ 目录 - **模板时长概念全链路删除**(基线:模板只定片段数/结构,无时长概念):模板库/我的模板/智能匹配/详情弹窗/筛选器;`computeLimitFromSegments` 改为纯「片段数 × 3」钳 [1,200];api 类型 duration_min/max/estimated_duration 标 @deprecated 改可选(兼容旧数据读取);editing-planner 编辑器内部 clip 时长属数据模型不在本次范围 - **顺带修复全量测试 OOM 根因**:useVariantVoicePreview 中 useQuery 解构 `= []` 默认值每次渲染产生新数组 → effect 依赖变化 → setUrls 新数组 → 无限渲染循环,worker heap 爆掉。改用模块级稳定常量 EMPTY_VOICE_MATERIALS + 所有 setUrls 内容比较 bailout ## 测试 - 全量 vitest:**722 passed | 4 skipped(149 files + 1 skipped)**,此前 OOM 已消失 - tsc --noEmit / eslint --max-warnings 0 / prettier / vite build 全绿 - 重写适配测试:useBatchVariantPlans(11 例错误态/nonce retry/越界归一化)、FrontendPreviewPlayer.audio(8 例 serverClips/playToken)、CanvasPreviewGrid.audio(6 例三态/独立配音)、smart-match-pool(4 例新规则) ## ⚠️ 后端依赖 #1749 `POST /api/v1/generation/variant-plans` 接口上线前,staging 批量预览将显示「预览加载失败,请重试」——这是工单明确要求的行为(不许假数据)。后端接口部署后即自动恢复真实片段预览。
xiaoxia added 1 commit 2026-09-07 01:23:39 +08:00
fix(generate): #1750 批量预览五连修——删本地模拟假数据/配音时长/竖屏播放器/封面一键生成
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1s
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 / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker 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 / 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 / Validate - Style (pull_request) Successful in 1m28s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m59s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 2m1s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m57s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 2m20s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m30s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 3m55s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 4m11s
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 / Build Production Web 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 3s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 2m22s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 6s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 36s
AI Code Review / AI Code Review (pull_request) Successful in 6m16s
be964c0aa5
1. 配音列表显示时长:Step5VoiceSelect 卡片底行展示真实时长(X.X秒 / 文件大小),
   AI 音色显示「按文本合成」,时长缺失兜底「时长未知」
2. 批量预览假数据根治(铁证:variant-plans 接口 404,前端静默降级 9素材×5s=45s):
   - 删除 fallback 本地模拟整条分支(variantSeed 轮换/seededRandom/duration 兜底/模板时长)
   - 预览片段唯一来源为后端 variant-plans 真实 clips;总时长=片段时长之和
   - 接口失败显示「预览加载失败,请重试」三态占位(9:16 防塌陷),重试按钮仅变体0
   - serverClips 引用素材缺失时 usePreviewAssets.ensureAssets 按 asset_id 差集补拉
   - playToken 替代 variantSeed(0 基变体序号)驱动播放互斥
3. 独立配音模式:useVariantVoicePreview 每变体挂各自配音 URL(voiceLibraryIds[i]),
   共用模式全变体同一条;有配音时素材视频强制 muted
4. 竖屏播放器自适应:结果页/生成中/批量网格播放器容器按 9:16 自适应,
   video max-height:70vh + aspect-ratio,消除竖屏成片左右黑边;N=1 零回归
5. 封面一键全部自动生成:generateAll 一次点击串行触发所有未生成封面,
   失败单个不阻塞,分级 toast(全成功/部分失败/全失败);按钮 nowrap 不换行

配套清理:
- 删除死代码 PreviewVideoPanel/useServerPreview/calculateTotalVideoDuration/
  GenerateResultPanel/result-panel/
- 模板时长概念全链路删除(模板库/我的模板/智能匹配/详情弹窗),
  api 类型 duration_min/max/estimated_duration 标 @deprecated 兼容旧数据
- useBatchVariantPlans 重写:error/retry 状态,retry 由 state nonce 驱动 effect
  统一发请求(修复 retry 直调 load 与 effect 双发 requestSeq 竞争)
- useVariantVoicePreview 修复渲染风暴:useQuery 解构禁用 = [] 默认值,
  改用模块级稳定常量 EMPTY_VOICE_MATERIALS + setUrls 内容比较 bailout
  (修复全量 vitest worker OOM 根因)

依赖后端 #1749:variant-plans 接口上线前,staging 批量预览显示
「预览加载失败,请重试」为预期行为(严禁假数据冒充预览)

测试:722 passed (149 files);tsc/eslint(max-warnings 0)/prettier/build 全绿

🚀 预览环境已部署

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

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

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

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

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1751 | | 预览链接 | [https://pr-1751.preview.xiaoxiajianji.com](https://pr-1751.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
auto-approve-bot approved these changes 2026-09-07 01:26:09 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

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

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot merged commit 478c9c2bc3 into develop 2026-09-07 01:28:35 +08:00
auto-approve-bot deleted branch feat/1750-preview-five-fixes 2026-09-07 01:28:35 +08:00

🗑️ 预览环境已清理

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

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

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