fix: 预览视频标题渲染全链路修复 — custom_title注入+ASR路径标题支持 #1399

Merged
xiaoxia merged 2 commits from fix/preview-title-render into develop 2026-08-17 00:50:27 +08:00
Owner

问题

用户在 Step4 选了标题后,生成的预览视频里没有标题文字。全链路排查发现 3 个断点。

根因分析

断点1 (P0) — generate_video() 未传递 custom_title

task_info["custom_title"] 存在但调用 _render_video() 时没传过去。

断点2 (P0) — _render_video() 无 custom_title 参数

没有参数接收 custom_title,内部只从模板默认配置注入标题,用户自定义标题从未被注入到 plan.config["title"]

断点3 (P1) — ASR 路径完全跳过标题

generate_ass_from_timeline() 没有标题参数,有配音时标题也不渲染。

次要问题 — 字段名不匹配

前端发 font_size/font_color,后端 build_ass_contentsize/color

修复

文件 改动
generation.py _render_video() 增加 custom_title 参数,JSON解析+字段归一化(font_size→size, font_color→color)后注入 virtual_plan.config["title"]generate_video() 调用处传递 task_info.get("custom_title", "")
subtitle_generator.py generate_ass_from_timeline() 增加 title_text/title_config/video_duration 参数,ASR字幕与标题共存于同一ASS文件
unified_render_service.py _maybe_generate_ass() ASR路径传递 title_text/title_config/video_duration

新增测试

  • test_preview_title_render.py — 9个测试覆盖3个断点
    • 标题注入 + 字段归一化 + 空值防护 + JSON异常降级
    • ASR+标题共存ASS输出 + 无标题降级 + boolean stroke/shadow兼容

验收标准

  • 无配音预览:视频有标题,字号/颜色/描边/阴影与用户设置一致
  • 有配音预览:视频有标题 + ASR 字幕,互不遮挡
  • 不选标题时:视频无标题叠加,行为不变
## 问题 用户在 Step4 选了标题后,生成的预览视频里没有标题文字。全链路排查发现 3 个断点。 ## 根因分析 ### 断点1 (P0) — `generate_video()` 未传递 `custom_title` `task_info["custom_title"]` 存在但调用 `_render_video()` 时没传过去。 ### 断点2 (P0) — `_render_video()` 无 custom_title 参数 没有参数接收 custom_title,内部只从模板默认配置注入标题,用户自定义标题从未被注入到 `plan.config["title"]`。 ### 断点3 (P1) — ASR 路径完全跳过标题 `generate_ass_from_timeline()` 没有标题参数,有配音时标题也不渲染。 ### 次要问题 — 字段名不匹配 前端发 `font_size`/`font_color`,后端 `build_ass_content` 读 `size`/`color`。 ## 修复 | 文件 | 改动 | |---|---| | `generation.py` | `_render_video()` 增加 `custom_title` 参数,JSON解析+字段归一化(`font_size→size`, `font_color→color`)后注入 `virtual_plan.config["title"]`;`generate_video()` 调用处传递 `task_info.get("custom_title", "")` | | `subtitle_generator.py` | `generate_ass_from_timeline()` 增加 `title_text`/`title_config`/`video_duration` 参数,ASR字幕与标题共存于同一ASS文件 | | `unified_render_service.py` | `_maybe_generate_ass()` ASR路径传递 `title_text`/`title_config`/`video_duration` | ## 新增测试 - `test_preview_title_render.py` — 9个测试覆盖3个断点 - 标题注入 + 字段归一化 + 空值防护 + JSON异常降级 - ASR+标题共存ASS输出 + 无标题降级 + boolean stroke/shadow兼容 ## 验收标准 - ✅ 无配音预览:视频有标题,字号/颜色/描边/阴影与用户设置一致 - ✅ 有配音预览:视频有标题 + ASR 字幕,互不遮挡 - ✅ 不选标题时:视频无标题叠加,行为不变
xiaoxia force-pushed fix/preview-title-render from c89cd02726 to 1629a2e3a8 2026-08-17 00:29:51 +08:00 Compare
xiaoxia added 1 commit 2026-08-17 00:30:02 +08:00
fix: 预览视频标题渲染全链路修复 — custom_title注入+ASR路径标题支持
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 / 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 / Check if frontend-only change (pull_request) Successful in 46s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m36s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m43s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m47s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m12s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
c8789670e9
修复3个断点导致预览视频不渲染用户自定义标题:

断点1(P0): generate_video() 未将 custom_title 传给 _render_video()
断点2(P0): _render_video() 没有接收 custom_title,也未注入 plan.config[title]
断点3(P1): generate_ass_from_timeline() ASR路径完全跳过标题渲染
次要: 前端 font_size/font_color 与后端 size/color 字段名不匹配

修改:
- generation.py: _render_video 增加 custom_title 参数,JSON解析+字段归一化后
  注入 virtual_plan.config[title]; generate_video 调用处传递 task_info[custom_title]
- subtitle_generator.py: generate_ass_from_timeline 增加 title_text/title_config/
  video_duration 参数,ASR字幕与标题共存于同一ASS文件
- unified_render_service.py: _maybe_generate_ass 的ASR路径传递标题参数
- 新增 test_preview_title_render.py (9个测试覆盖3个断点)
xiaoxia force-pushed fix/preview-title-render from 1629a2e3a8 to c8789670e9 2026-08-17 00:30:02 +08:00 Compare

🚀 预览环境已部署

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

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

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

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

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1399 | | 预览链接 | [https://pr-1399.preview.xiaoxiajianji.com](https://pr-1399.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
auto-approve-bot added 1 commit 2026-08-17 00:33:39 +08:00
style: auto-format with black + isort + prettier [skip ci-format-check]
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 / 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 / Check if frontend-only change (pull_request) Successful in 23s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 1m36s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m45s
AI Code Review / AI Code Review (pull_request) Successful in 2m0s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 2m1s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m12s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m5s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m7s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 3m10s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m45s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 5m30s
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 / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m37s
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 30s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 46s
423ee5bb48
Collaborator

代码审查结果 - PR #1399

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

  1. apps/worker/worker_app/tasks/generation.py 第1162行:类型不安全导致崩溃风险。
    • 代码 user_title_cfg.get("text", "").strip() 假设 text 字段一定是字符串。如果 JSON 中传入 "text": null"text": 123,调用 .strip() 会抛出 AttributeError,导致 Worker 任务崩溃。
  2. apps/worker/video_processing/subtitle_generator.py 第202-206行:配置字段类型未校验导致崩溃风险。
    • 代码 t_stroke = title_cfg.get("stroke", {}) or {} 仅处理了 None/False 的情况。如果 stroke 传入的是非空字符串(如 "yes")或其他非字典对象,后续 t_stroke.get(...) 会抛出 AttributeError
  3. apps/worker/video_processing/subtitle_generator.py 第217行:数值转换缺乏异常处理。
    • 代码 int(title_cfg.get("size", 36)) 和后续的 float(...) 转换未做保护。如果 JSON 中传入 "size": null"size": "invalid",会导致 TypeErrorValueError 致使渲染失败。

💡 建议(2个可选)

  1. apps/worker/video_processing/subtitle_generator.py 第184-195行:避免修改传入的参数对象。
    • 代码直接修改 title_cfg(即引用的 title_config 字典),这种副作用可能导致调用方(unified_render_service.py)持有的配置数据被意外更改。建议使用 copy.deepcopy 或创建新字典。
  2. apps/worker/video_processing/subtitle_generator.py 第220行:增加对 title_text 的空值保护。
    • 尽管类型提示为 str,但若调用方传入 Nonetitle_text.strip() 会报错。建议改为 (title_text or "").strip() 以增强鲁棒性。

格式检查通过 | 逻辑审查需修改 | 建议关注性能


🤖 由 AI 代码审查机器人自动生成 | 2026-08-16 16:35:40 | 模型:

## 代码审查结果 - PR #1399 ### ⚠️ 问题(3个需要修改) 1. **apps/worker/worker_app/tasks/generation.py 第1162行**:类型不安全导致崩溃风险。 - 代码 `user_title_cfg.get("text", "").strip()` 假设 `text` 字段一定是字符串。如果 JSON 中传入 `"text": null` 或 `"text": 123`,调用 `.strip()` 会抛出 `AttributeError`,导致 Worker 任务崩溃。 2. **apps/worker/video_processing/subtitle_generator.py 第202-206行**:配置字段类型未校验导致崩溃风险。 - 代码 `t_stroke = title_cfg.get("stroke", {}) or {}` 仅处理了 None/False 的情况。如果 `stroke` 传入的是非空字符串(如 `"yes"`)或其他非字典对象,后续 `t_stroke.get(...)` 会抛出 `AttributeError`。 3. **apps/worker/video_processing/subtitle_generator.py 第217行**:数值转换缺乏异常处理。 - 代码 `int(title_cfg.get("size", 36))` 和后续的 `float(...)` 转换未做保护。如果 JSON 中传入 `"size": null` 或 `"size": "invalid"`,会导致 `TypeError` 或 `ValueError` 致使渲染失败。 ### 💡 建议(2个可选) 1. **apps/worker/video_processing/subtitle_generator.py 第184-195行**:避免修改传入的参数对象。 - 代码直接修改 `title_cfg`(即引用的 `title_config` 字典),这种副作用可能导致调用方(`unified_render_service.py`)持有的配置数据被意外更改。建议使用 `copy.deepcopy` 或创建新字典。 2. **apps/worker/video_processing/subtitle_generator.py 第220行**:增加对 `title_text` 的空值保护。 - 尽管类型提示为 `str`,但若调用方传入 `None`,`title_text.strip()` 会报错。建议改为 `(title_text or "").strip()` 以增强鲁棒性。 --- ✅ 格式检查通过 | ❌ 逻辑审查需修改 | ✅ 建议关注性能 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-08-16 16:35:40 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
xiaoxia merged commit 13b8fb7f66 into develop 2026-08-17 00:50:27 +08:00

🗑️ 预览环境已清理

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

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

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