You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

10 KiB

批量对话配音生成接口 - 实施总结

实施完成

日期: 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

参数:

{
  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;              // 模型名称(可选)
}

响应:

{
  "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 不影响现有激活状态

手动测试脚本

# 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. 确认依赖

# 确认 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. 重启服务

# 重启后端服务(应用新代码)
docker-compose restart server-app

# 重启 Celery Worker
docker-compose restart server-celery-ai

3. 验证部署

# 检查 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 使用示例
    • 注意事项

验收标准

  • API 接口实现完成
  • 支持批量生成(1-50 个对话)
  • 配音自动写入 storyboard_voiceovers
  • 支持部分失败容错
  • 完整的权限验证
  • 积分预扣和消耗记录
  • Celery 异步任务实现
  • 文档完整(RFC + Changelog)
  • 代码语法检查通过
  • 单元测试覆盖(待补充)
  • 集成测试覆盖(待补充)
  • 手动测试验证(待执行)

🎉 总结

成功实现了批量对话配音生成接口,核心功能包括:

  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. 性能优化(考虑并行生成)