feat(generate): #1744 批量预览对接后端变体真实片段 + 智能匹配候选池×3 #1748

Merged
auto-approve-bot merged 1 commits from feat/1744-batch-real-variant-clips into develop 2026-09-06 20:45:10 +08:00
Owner

背景 / 工单 #1744

批量预览 N 个视频时,变体差异仅靠前端 variantSeed 本地模拟(素材轮换+随机起点),不调后端;后端正式渲染走独立 plan(#1745 已上线 reselect_plan_for_variant),导致预览与成片不一致

改动

1. 批量预览对接真实变体片段(方案 A:轻量选片端点,零渲染成本)

  • 新增 api/generation/variantPlans.tsPOST /generation/variant-plans,请求 {template_id, asset_ids, count, source_edit_plan_id?},响应 {items: [{variant_index, plan_id, clips}], total}只选片不渲染视频,复用后端已有的 reselect_plan_for_variant 同源逻辑
  • 新增 hooks/useBatchVariantPlans.ts:批量模式 step4 素材就绪后拉取 N 个变体的真实 plan clips
  • CanvasPreviewGrid 每个变体卡片优先播放 serverClips(播放器本就支持,serverClips 非空时优先、为空回退 variantSeed),加载中显示「独立选片中…」角标
  • useGenerateVideo 正式生成时按勾选索引回传 variant_plan_ids,后端直接关联对应 plan、不再重选,保证预览所见即成片

2. 三级降级(后端端点未上线不阻塞)

  • 404(端点未上线):静默降级本地 variantSeed 模拟,用户无感
  • 400(素材不足):静默(全局 axios 拦截器已 toast 后端 detail,正式生成时后端同样拦截)
  • 网络/超时/5xx:toast 一次「预览素材排布加载失败,正式生成时每个视频仍会独立随机选片」
  • hook 仅 isBatch && currentStep===4 && 素材就绪 启用;N=1 单视频零回归

3. 智能匹配候选池扩大(工单附带项)

  • computeLimitFromSegments 规则改为 max(片段数×3, ceil(总时长/15s), 片段数),钳制 [1,200];DEFAULT_LIMIT 10→30
  • 保证批量变体独立选片 + 跨变体 20% 区间避让有足够候选素材

4. 测试

  • 新增 15 例单测:候选池规则 6 例 + hook(降级/竞态/指纹去重/reset bailout)9 例
  • 修复过程中发现并修复一个真实 bug:hook reset 分支无条件 setState 新数组引用,内联字面量 props 下会触发无限渲染循环(测试中表现为 worker OOM),改为函数式更新 bailout

后端依赖(不阻塞本 PR 合并,前端已降级)

  1. 需实现 POST /api/v1/generation/variant-plans:变体 0 返回源/草稿 plan clips,变体 1..N-1 调 EditPlanService.reselect_plan_for_variant(与正式生成同源),只选片不渲染;clips 需支持按任意 plan_id 查询(现有 GET clips 端点经 get_draft_plan_id 只能拿草稿 plan)
  2. CreateGenerationTaskRequest 增加 variant_plan_ids: list[str](Pydantic v2 默认 extra=ignore,前端提前传不会 422),创建批量任务时直接关联对应 plan

验证

  • tsc 净 / eslint 0 warning / prettier 干净 / npm run build 通过
  • vitest 全量 33 文件 329 例全过(含新增 15 例)
## 背景 / 工单 #1744 批量预览 N 个视频时,变体差异仅靠前端 `variantSeed` 本地模拟(素材轮换+随机起点),不调后端;后端正式渲染走独立 plan(#1745 已上线 `reselect_plan_for_variant`),导致**预览与成片不一致**。 ## 改动 ### 1. 批量预览对接真实变体片段(方案 A:轻量选片端点,零渲染成本) - 新增 `api/generation/variantPlans.ts`:`POST /generation/variant-plans`,请求 `{template_id, asset_ids, count, source_edit_plan_id?}`,响应 `{items: [{variant_index, plan_id, clips}], total}`。**只选片不渲染视频**,复用后端已有的 `reselect_plan_for_variant` 同源逻辑 - 新增 `hooks/useBatchVariantPlans.ts`:批量模式 step4 素材就绪后拉取 N 个变体的真实 plan clips - `CanvasPreviewGrid` 每个变体卡片优先播放 `serverClips`(播放器本就支持,serverClips 非空时优先、为空回退 variantSeed),加载中显示「独立选片中…」角标 - `useGenerateVideo` 正式生成时按勾选索引回传 `variant_plan_ids`,后端直接关联对应 plan、不再重选,保证**预览所见即成片** ### 2. 三级降级(后端端点未上线不阻塞) - 404(端点未上线):静默降级本地 variantSeed 模拟,用户无感 - 400(素材不足):静默(全局 axios 拦截器已 toast 后端 detail,正式生成时后端同样拦截) - 网络/超时/5xx:toast 一次「预览素材排布加载失败,正式生成时每个视频仍会独立随机选片」 - hook 仅 `isBatch && currentStep===4 && 素材就绪` 启用;**N=1 单视频零回归** ### 3. 智能匹配候选池扩大(工单附带项) - `computeLimitFromSegments` 规则改为 `max(片段数×3, ceil(总时长/15s), 片段数)`,钳制 [1,200];DEFAULT_LIMIT 10→30 - 保证批量变体独立选片 + 跨变体 20% 区间避让有足够候选素材 ### 4. 测试 - 新增 15 例单测:候选池规则 6 例 + hook(降级/竞态/指纹去重/reset bailout)9 例 - 修复过程中发现并修复一个真实 bug:hook reset 分支无条件 setState 新数组引用,内联字面量 props 下会触发无限渲染循环(测试中表现为 worker OOM),改为函数式更新 bailout ## 后端依赖(不阻塞本 PR 合并,前端已降级) 1. 需实现 `POST /api/v1/generation/variant-plans`:变体 0 返回源/草稿 plan clips,变体 1..N-1 调 `EditPlanService.reselect_plan_for_variant`(与正式生成同源),只选片不渲染;clips 需支持按任意 plan_id 查询(现有 GET clips 端点经 `get_draft_plan_id` 只能拿草稿 plan) 2. `CreateGenerationTaskRequest` 增加 `variant_plan_ids: list[str]`(Pydantic v2 默认 extra=ignore,前端提前传不会 422),创建批量任务时直接关联对应 plan ## 验证 - tsc 净 / eslint 0 warning / prettier 干净 / `npm run build` 通过 - vitest 全量 33 文件 329 例全过(含新增 15 例)
xiaoxia added 1 commit 2026-09-06 20:20:44 +08:00
feat(generate): #1744 批量预览对接后端变体真实片段 + 智能匹配候选池扩大×3
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 4s
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 / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (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 / 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 / PR Build Web Image (pull_request) Successful in 1m39s
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 2m25s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 2m59s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 2m58s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m19s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 3m50s
AI Code Review / AI Code Review (pull_request) Successful in 2m2s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 19m14s
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 1s
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 / Production Browser E2E (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m0s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m6s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 7s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 1m11s
4eb3b49520
- 新增 POST /generation/variant-plans 轻量选片端点客户端与 useBatchVariantPlans hook:
  批量 step4 素材就绪后拉取各变体真实 plan clips,Canvas 预览优先播放 serverClips,
  预览所见即成片;端点 404/400 静默降级本地 variantSeed 模拟,网络错误 toast 一次
- 正式生成批量提交时按勾选索引回传 variant_plan_ids,后端直接关联不重选
- useSmartMatch 候选池下限改为 max(片段数×3, ceil(总时长/15s), 片段数),
  DEFAULT_LIMIT 10→30,保证批量变体独立选片避让有足够素材
- N=1 单视频链路零回归(hook 仅 isBatch && step4 启用)
- 新增单测 15 例(候选池规则 6 + hook 降级/竞态/去重/bailout 9)
auto-approve-bot approved these changes 2026-09-06 20:24:02 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

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

CI全绿,自动审批通过。

CI全绿,自动审批通过。

🚀 预览环境已部署

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

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

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

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

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

代码审查结果 - PR #1748

⚠️ 问题(0个需要修改)

💡 建议(0个可选)


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


🤖 由 AI 代码审查机器人自动生成 | 2026-09-06 12:31:05 | 模型:

## 代码审查结果 - PR #1748 ### ⚠️ 问题(0个需要修改) 无 ### 💡 建议(0个可选) 无 --- ✅ 格式检查通过 | ✅ 逻辑审查通过 | ✅ 性能良好 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-09-06 12:31:05 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
auto-approve-bot merged commit bcbcb41750 into develop 2026-09-06 20:45:10 +08:00
auto-approve-bot deleted branch feat/1744-batch-real-variant-clips 2026-09-06 20:45:11 +08:00

🗑️ 预览环境已清理

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

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

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