feat(voices): TTS时长修复 + 提取视频配音 + AI配音标识 #1656

Merged
auto-approve-bot merged 4 commits from fix/tts-duration-and-video-extract into develop 2026-09-03 19:04:36 +08:00
Owner

修复内容

1. TTS 素材时长显示修复(后端)

  • 文件: apps/api/app/api/routes/tts.py
  • 问题: save_tts_job_to_libraryduration=job.duration or None,当 job.duration=0.0 时(CosyVoice 同步接口不返回 duration),0.0 or NoneNone,导致素材 duration 字段缺失,前端显示 --:--
  • 修复: 上传音频后通过 ffprobe 提取真实时长作为兜底,duration=audio_duration or job.duration or None

2. 提取视频配音按钮(前端)

  • 位置: 配音库页面右上角,「上传音频」和「克隆音色」之间
  • 样式: 紫色 primary 按钮(与 AI 配音一致),图标 VideoCameraOutlined
  • 功能: 点击弹出 Modal,选择视频文件(MP4/MOV/WebM),上传显示进度,完成后刷新素材列表
  • API: extractVideoVoice()POST /tts/extract-video-voice(后端接口待实现)

3. AI 配音标识(前端)

  • 位置: 配音素材卡片名称右侧
  • 判断: asset.metadata.source === "tts_job"
  • 样式: 紫色边框小标签「AI」
## 修复内容 ### 1. TTS 素材时长显示修复(后端) - **文件**: `apps/api/app/api/routes/tts.py` - **问题**: `save_tts_job_to_library` 中 `duration=job.duration or None`,当 `job.duration=0.0` 时(CosyVoice 同步接口不返回 duration),`0.0 or None` → `None`,导致素材 duration 字段缺失,前端显示 `--:--` - **修复**: 上传音频后通过 ffprobe 提取真实时长作为兜底,`duration=audio_duration or job.duration or None` ### 2. 提取视频配音按钮(前端) - **位置**: 配音库页面右上角,「上传音频」和「克隆音色」之间 - **样式**: 紫色 primary 按钮(与 AI 配音一致),图标 VideoCameraOutlined - **功能**: 点击弹出 Modal,选择视频文件(MP4/MOV/WebM),上传显示进度,完成后刷新素材列表 - **API**: `extractVideoVoice()` → `POST /tts/extract-video-voice`(后端接口待实现) ### 3. AI 配音标识(前端) - **位置**: 配音素材卡片名称右侧 - **判断**: `asset.metadata.source === "tts_job"` - **样式**: 紫色边框小标签「AI」
xiaoxia added 1 commit 2026-09-03 18:29:29 +08:00
feat(voices): TTS时长修复 + 提取视频配音 + AI配音标识
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 11s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 11s
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 50s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m57s
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
AI Code Review / AI Code Review (pull_request) Failing after 3m28s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 1m39s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 1m55s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 3m16s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 2m22s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 29s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 27s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m48s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m35s
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (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 / ACR Image Cleanup (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
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
9c34165b35
后端修复:
- tts.py: save_tts_job_to_library 用 ffprobe 从音频文件提取时长兜底
  解决 job.duration=0 导致 asset.duration=None 的问题
- duration=audio_duration or job.duration or None

前端新增:
- 提取视频配音按钮:VoiceLibrary 页面新增「提取视频配音」按钮(紫色 primary),
  点击弹出 Modal 选择视频文件,上传后显示进度,完成后刷新素材列表
- API: extractVideoVoice() 调用 POST /tts/extract-video-voice
- Hook: useVideoExtract 封装上传状态与进度
- Component: VideoExtractModal 基于 antd Modal
- AI 配音标识:MaterialVoiceTab 卡片名称旁显示紫色「AI」标签,
  依据 metadata.source === "tts_job" 判断
Collaborator

【阻塞级判定】

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

📊 审查概览

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

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

  1. [apps/api/app/api/routes/tts.py: 458-483] 资源泄漏风险
    • 问题类型:数据损坏风险(资源泄漏)
    • 问题描述:代码删除了原有的 finally 块,将临时文件清理逻辑移到了 try-except 块之后的普通执行流中。如果在执行 ffprobe 提取时长之前的代码逻辑中抛出异常(或者在 ffprobe 之前的逻辑中发生错误),程序将直接跳过清理代码,导致 tmp_path 临时文件无法被删除,长期运行可能导致服务器磁盘空间被占满。
    • 修改建议:必须将 tmp_path.unlink() 清理逻辑放回 finally 块中,或者确保在函数退出前(无论是否发生异常)都执行清理。建议恢复 try...finally 结构,将 ffprobe 逻辑包含在 try 中,清理放在 finally 中。

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

  1. [apps/web/src/api/tts/jobs.ts: 78] 认证 Token 处理不完善

    • 具体内容:直接从 localStorage 获取 access_token 并手动设置 Header。这种方式绕过了常规的 apiClient 拦截器,可能无法自动处理 Token 过期刷新逻辑(如果项目中配置了 Refresh Token 机制)。建议复用 apiClient 的上传能力(如果支持进度),或者确保在此处也实现了 Token 刷新逻辑。
  2. [apps/web/src/pages/voices/components/VideoExtractModal.tsx: 全局] 样式维护性问题

    • 具体内容:组件中使用了大量的内联样式(style={{...}}),这会导致样式难以复用、难以维护,并增加 JS bundle 体积。建议将样式提取到 CSS 文件或 CSS Modules 中。

良好实践

  • 后端使用 subprocess.run 并传递列表参数,有效避免了命令注入风险。
  • 前端 VideoExtractModal 组件在上传过程中禁用了关闭按钮和取消操作,防止了误操作导致的中断。
  • 后端对 ffprobe 的调用增加了 timeout 和异常捕获,具备较好的容错性。

🤖 由 AI 代码审查机器人自动生成 | 2026-09-03 10:34:37 | 模型:

### 【阻塞级判定】 - 是否存在阻塞级问题:是 - 阻塞级问题数量:1 个 ### 📊 审查概览 - 整体评价:需修改 - 建议级问题数量:2 个 ### 🔴 阻塞级问题(必须修复) 1. **[apps/api/app/api/routes/tts.py: 458-483] 资源泄漏风险** - 问题类型:数据损坏风险(资源泄漏) - 问题描述:代码删除了原有的 `finally` 块,将临时文件清理逻辑移到了 `try-except` 块之后的普通执行流中。如果在执行 `ffprobe` 提取时长之前的代码逻辑中抛出异常(或者在 `ffprobe` 之前的逻辑中发生错误),程序将直接跳过清理代码,导致 `tmp_path` 临时文件无法被删除,长期运行可能导致服务器磁盘空间被占满。 - 修改建议:必须将 `tmp_path.unlink()` 清理逻辑放回 `finally` 块中,或者确保在函数退出前(无论是否发生异常)都执行清理。建议恢复 `try...finally` 结构,将 `ffprobe` 逻辑包含在 `try` 中,清理放在 `finally` 中。 ### 💡 改进建议(不阻塞合并) 1. **[apps/web/src/api/tts/jobs.ts: 78] 认证 Token 处理不完善** - 具体内容:直接从 `localStorage` 获取 `access_token` 并手动设置 Header。这种方式绕过了常规的 `apiClient` 拦截器,可能无法自动处理 Token 过期刷新逻辑(如果项目中配置了 Refresh Token 机制)。建议复用 `apiClient` 的上传能力(如果支持进度),或者确保在此处也实现了 Token 刷新逻辑。 2. **[apps/web/src/pages/voices/components/VideoExtractModal.tsx: 全局] 样式维护性问题** - 具体内容:组件中使用了大量的内联样式(`style={{...}}`),这会导致样式难以复用、难以维护,并增加 JS bundle 体积。建议将样式提取到 CSS 文件或 CSS Modules 中。 ### ✅ 良好实践 - 后端使用 `subprocess.run` 并传递列表参数,有效避免了命令注入风险。 - 前端 `VideoExtractModal` 组件在上传过程中禁用了关闭按钮和取消操作,防止了误操作导致的中断。 - 后端对 `ffprobe` 的调用增加了 `timeout` 和异常捕获,具备较好的容错性。 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-09-03 10:34:37 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
xiaoxia added 1 commit 2026-09-03 18:37:58 +08:00
fix: AI Code Review 阻塞问题 - 临时文件清理放回 finally 块 + 修复 TS 类型错误
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 / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 7s
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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m32s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 1m37s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 2m5s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m13s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 56s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 52s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 3m31s
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 / Frontend Lint (pull_request) Failing after 1m38s
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 1m59s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m19s
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web 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 Merge on CI Green + Approved (pull_request) Has been cancelled
6a5affa403
- tts.py: ffprobe 提取时长移入 try 块,cleanup 回归 finally
- VoiceLibrary.tsx: 重命名 useVideoExtract 的 handleFileSelect 避免与 useVoiceUpload 冲突
- VideoExtractModal: onFileSelect 类型 File | null 正确传递

🚀 预览环境已部署

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

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

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

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

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1656 | | 预览链接 | [https://pr-1656.preview.xiaoxiajianji.com](https://pr-1656.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
xiaoxia added 1 commit 2026-09-03 18:46:15 +08:00
fix: 修复 duration 优先级 - job.duration 优先,ffprobe 兜底
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 13s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 13s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 23s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 1m28s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 44s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 44s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m50s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 2m16s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m8s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m11s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 3m42s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 6m52s
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) Failing after 1s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (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
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
fb22140f02
原来 audio_duration or job.duration 导致 ffprobe 对假数据返回 3.0
覆盖了 job.duration=6.0。改为 job.duration or audio_duration or None
xiaoxia added 1 commit 2026-09-03 18:57:11 +08:00
fix: resolve ESLint warnings in useVideoExtract
CI/CD Pipeline / Check push changed paths (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 / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 4s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 30s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 2m23s
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 / Unit Tests (pull_request) Successful in 2m37s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m41s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 17s
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 1m53s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 2m51s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m23s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 3m14s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 57s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m52s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 6m33s
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 / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 1s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m45s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 8s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 34s
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Failing after 14m57s
e78e29b61f
- Move handleExtractClose before handleExtract to fix dependency order
- Change catch (err: any) to catch (err: unknown) with proper type guard
- Add handleExtractClose to useCallback dependency array
auto-approve-bot merged commit 6d2d63da7e into develop 2026-09-03 19:04:36 +08:00
auto-approve-bot deleted branch fix/tts-duration-and-video-extract 2026-09-03 19:04:36 +08:00

🗑️ 预览环境已清理

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

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

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