# 批量对话配音生成接口 - 实施总结 ## ✅ 实施完成 **日期**: 2026-02-13 **方案**: 方案 2 - 新增专用接口 **状态**: 代码实现完成,待测试验证 --- ## 📦 改动文件清单 | 文件 | 改动内容 | 状态 | |------|---------|------| | `server/app/models/ai_job.py` | 新增 `AIJobType.DIALOGUE_VOICEOVER = 10` | ✅ | | `server/app/schemas/ai.py` | 新增 `GenerateDialogueVoiceoversRequest` | ✅ | | `server/app/api/v1/ai.py` | 新增 `/generate-dialogue-voiceovers` 路由 + 导入 | ✅ | | `server/app/services/ai_service.py` | 新增 `generate_dialogue_voiceovers()` 方法 | ✅ | | `server/app/tasks/ai_tasks.py` | 新增 `generate_dialogue_voiceovers_task` | ✅ | | `docs/server/rfcs/145-dialogue-voiceovers-batch-generation.md` | RFC 文档 | ✅ | | `docs/server/changelogs/2026-02-13-dialogue-voiceovers-batch-generation.md` | Changelog | ✅ | --- ## 🎯 核心功能 ### 1. 新增 API 接口 **端点**: `POST /api/v1/ai/generate-dialogue-voiceovers` **参数**: ```typescript { dialogue_ids: string[]; // 对话 ID 列表(1-50 个) voice_id: string; // 音色 ID voice_name?: string; // 音色名称(可选) speed: number; // 语速(0.25-4.0,默认 1.0) volume: number; // 音量(0.0-2.0,默认 1.0) pitch: number; // 音调(0.5-2.0,默认 1.0) is_active: boolean; // 是否设为激活配音(默认 false) model?: string; // 模型名称(可选) } ``` **响应**: ```json { "code": 200, "message": "批量配音生成任务创建成功", "data": { "jobId": "550e8400-e29b-41d4-a716-446655440000", "taskId": "celery-task-id", "status": "pending", "estimatedCredits": 150, "dialogueCount": 10 } } ``` --- ### 2. 业务流程 ``` 用户请求 ↓ AIService.generate_dialogue_voiceovers() ├─ 验证用户存在 ├─ 验证对话数量(1-50) ├─ 获取所有对话并验证存在性 ├─ 验证所有对话属于同一分镜 ├─ 验证分镜权限(至少 viewer) ├─ 检查配额 ├─ 获取模型配置(默认 AUDIO 类型) ├─ 计算所需积分(基于总字符数) ├─ 预扣积分 ├─ 创建 AI Job(job_type=10) └─ 启动 Celery 任务 ↓ generate_dialogue_voiceovers_task (Celery 异步) ├─ 逐个处理对话: │ ├─ 获取对话内容 │ ├─ 调用 TTS Provider 生成配音 │ ├─ 上传音频到 MinIO │ └─ 写入 storyboard_voiceovers 表 ├─ 收集成功/失败列表 └─ 更新任务状态为 COMPLETED ↓ 返回结果 ├─ successful_count: 成功数量 ├─ failed_count: 失败数量 ├─ successful_voiceovers: 成功的配音列表 └─ failed_dialogues: 失败的对话列表 ``` --- ### 3. 关键特性 #### ✅ 批量处理 - 一次请求最多 50 个对话 - 推荐 10-20 个对话(性能平衡) #### ✅ 部分失败容错 - 单个对话失败不影响其他对话 - 已成功的配音保留 - 失败的对话在结果中标记 #### ✅ 完整参数支持 - `voice_id` + `voice_name`:音色配置 - `speed`, `volume`, `pitch`:TTS 参数 - `is_active`:自动激活配音 #### ✅ 自动写入业务表 - 直接写入 `storyboard_voiceovers` 表 - 无需手动上传或关联 #### ✅ 权限验证 - 验证用户存在性 - 验证对话存在性 - 验证分镜权限(至少 viewer) - 所有对话必须属于同一分镜 --- ## 📊 与现有接口对比 | 特性 | `/generate-voice`(通用 TTS) | `/generate-dialogue-voiceovers`(批量对话) | |------|-------------------------------|-------------------------------------------| | **用途** | 任意文本转语音 | 为分镜对话生成配音 | | **输入** | 自由文本(`text`) | 对话 ID 列表(`dialogue_ids`) | | **数据源** | 用户输入 | `storyboard_dialogues` 表 | | **写入表** | `ai_generation_results` | `storyboard_voiceovers` | | **批量支持** | ❌ 单次单个 | ✅ 单次最多 50 个 | | **分镜关联** | 可选 | 强制验证 | | **权限验证** | 用户存在性 | 分镜权限 | | **失败策略** | 全部失败 | 部分失败继续 | | **参数** | `voice_type`, `speed`, `language` | `voice_id`, `speed`, `volume`, `pitch`, `is_active` | **保留原有接口**: - ✅ `/generate-voice` 可用于通用 TTS(非分镜场景) - ✅ 测试音色、预览效果 - ✅ 其他业务模块使用 --- ## 🧪 测试清单 ### 必须测试 - [ ] **基本功能** - [ ] 成功创建批量配音任务 - [ ] 配音写入 `storyboard_voiceovers` 表 - [ ] 任务状态正确更新(PENDING → PROCESSING → COMPLETED) - [ ] **参数验证** - [ ] 空对话列表 → ValidationError - [ ] 超过 50 个对话 → ValidationError - [ ] 无效的对话 ID → ValidationError - [ ] 对话属于不同分镜 → ValidationError - [ ] **权限验证** - [ ] 用户不存在 → ValidationError - [ ] 对话不存在 → ValidationError - [ ] 分镜不存在 → ValidationError - [ ] 无分镜权限 → PermissionError - [ ] **积分系统** - [ ] 积分不足 → InsufficientCreditsError - [ ] 积分正确预扣(基于总字符数) - [ ] 任务成功后积分确认 - [ ] 部分失败不退款 - [ ] **部分失败容错** - [ ] 单个对话失败,其他继续 - [ ] 成功的配音保留 - [ ] 失败原因在 `outputData.failed_dialogues` 中记录 - [ ] **激活配音** - [ ] `is_active=true` 自动停用其他配音 - [ ] `is_active=false` 不影响现有激活状态 --- ### 手动测试脚本 ```bash # 1. 准备测试数据(创建分镜和对话) export TOKEN="your-test-token" export STORYBOARD_ID="test-storyboard-id" # 创建测试对话 curl -X POST "http://localhost:6160/api/v1/storyboard-resources/dialogues" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "storyboard_id": "'$STORYBOARD_ID'", "content": "这是测试对话1", "character_name": "角色A", "sequence_order": 1 }' # 获取对话 ID export DIALOGUE_ID_1="returned-dialogue-id-1" export DIALOGUE_ID_2="returned-dialogue-id-2" # 2. 批量生成配音 curl -X POST "http://localhost:6160/api/v1/ai/generate-dialogue-voiceovers" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "dialogue_ids": ["'$DIALOGUE_ID_1'", "'$DIALOGUE_ID_2'"], "voice_id": "EXAVITQu4vr4xnSDxMaL", "voice_name": "Bella", "speed": 1.0, "volume": 1.0, "pitch": 1.0, "is_active": true }' # 获取 job_id export JOB_ID="returned-job-id" # 3. 查询任务状态(轮询直到完成) watch -n 2 "curl -s -X GET 'http://localhost:6160/api/v1/ai/jobs/$JOB_ID' \ -H 'Authorization: Bearer $TOKEN' | jq '.data.status, .data.progress'" # 4. 查看任务结果 curl -X GET "http://localhost:6160/api/v1/ai/jobs/$JOB_ID" \ -H "Authorization: Bearer $TOKEN" | jq '.data.outputData' # 5. 验证配音已写入 curl -X GET "http://localhost:6160/api/v1/storyboard-resources/dialogues/$DIALOGUE_ID_1/voiceovers" \ -H "Authorization: Bearer $TOKEN" | jq '.data' ``` --- ## ⚠️ 注意事项 ### 1. 积分消耗 - **预扣全部积分**:基于所有对话的总字符数一次性预扣 - **部分失败不退款**:即使部分对话失败,积分不退还 - **建议**:先测试少量对话(2-3个),确认效果后再批量生成 ### 2. 性能考虑 - **串行处理**:当前实现为串行处理(逐个对话) - **预计时长**:每个对话约 5-10 秒(TTS + 上传) - **推荐批量**:10-20 个对话(避免超时) ### 3. 失败处理 - **部分失败**:已成功的配音保留在数据库 - **重试策略**:失败的对话可单独重新提交 - **查看原因**:查询任务状态,检查 `outputData.failed_dialogues` ### 4. 激活配音 - **`is_active=true`**:每个对话的新配音会自动停用该对话的其他配音 - **`is_active=false`**:生成配音但不激活,需手动激活 --- ## 🚀 部署步骤 ### 1. 确认依赖 ```bash # 确认 Celery 正常运行 docker exec jointo-server-celery-ai celery -A app.core.celery_app inspect active # 确认 Redis 正常 docker exec jointo-server-redis redis-cli ping ``` ### 2. 重启服务 ```bash # 重启后端服务(应用新代码) docker-compose restart server-app # 重启 Celery Worker docker-compose restart server-celery-ai ``` ### 3. 验证部署 ```bash # 检查 API 文档(确认新端点存在) curl http://localhost:6160/docs # 查看日志 docker logs -f jointo-server-app | grep "generate-dialogue-voiceovers" ``` --- ## 📚 文档资源 - **RFC 145**: `/docs/server/rfcs/145-dialogue-voiceovers-batch-generation.md` - 完整的技术设计文档 - 业务流程详解 - 使用示例和测试计划 - **Changelog**: `/docs/server/changelogs/2026-02-13-dialogue-voiceovers-batch-generation.md` - 变更概述 - API 使用示例 - 注意事项 --- ## ✅ 验收标准 - [x] API 接口实现完成 - [x] 支持批量生成(1-50 个对话) - [x] 配音自动写入 `storyboard_voiceovers` 表 - [x] 支持部分失败容错 - [x] 完整的权限验证 - [x] 积分预扣和消耗记录 - [x] Celery 异步任务实现 - [x] 文档完整(RFC + Changelog) - [x] 代码语法检查通过 - [ ] 单元测试覆盖(待补充) - [ ] 集成测试覆盖(待补充) - [ ] 手动测试验证(待执行) --- ## 🎉 总结 成功实现了批量对话配音生成接口,核心功能包括: 1. ✅ **新增专用接口**:`/api/v1/ai/generate-dialogue-voiceovers` 2. ✅ **批量处理**:一次请求最多 50 个对话 3. ✅ **自动写入**:配音直接写入 `storyboard_voiceovers` 表 4. ✅ **部分失败容错**:已成功的配音保留 5. ✅ **完整参数支持**:voice_id, speed, volume, pitch, is_active 6. ✅ **权限验证**:分镜权限、对话归属验证 7. ✅ **文档完整**:RFC + Changelog **下一步**: 1. 执行手动测试验证功能 2. 补充单元测试和集成测试 3. 前端集成调用 4. 性能优化(考虑并行生成)