3.3 KiB
3.3 KiB
Technical Design: Voice Clone Provider Refactoring
Context
当前语音克隆功能直接依赖阿里云 CosyVoice 的 SDK 和 API。Service 层直接调用 CosyVoiceClient,导致:
- 强耦合:无法轻松切换或添加其他供应商
- 测试困难:难以 mock 外部依赖
- 扩展性差:添加新供应商需要修改 Service 层
Goals / Non-Goals
Goals
- 解耦 Service 层与具体供应商实现
- 支持多供应商并存和动态切换
- 保持现有功能完全兼容
- 为添加硅基流动 IndexTTS-2 打下基础
Non-Goals
- 不改变现有 API 行为
- 不修改数据库结构
- 不改变前端交互
Decisions
1. 采用策略模式 + 工厂模式
Why:
- 策略模式:定义统一接口,各供应商独立实现
- 工厂模式:根据配置动态获取 Provider 实例
- 符合开闭原则,扩展时无需修改现有代码
架构:
VoiceCloneProvider (interface)
├── CosyVoiceProvider (impl) - 阿里云 CosyVoice (DashScope)
├── SiliconFlowProvider (impl) - 阶段二:硅基流动 IndexTTS-2
└── VoiceCloneProviderFactory
说明:
CosyVoiceProvider对应阿里云 DashScope 的语音服务- 默认模型:
cosyvoice-v3-flash - 扩展时添加新的 Provider 实现
2. 统一 DTO 设计
Why: 屏蔽不同供应商的 API 差异
// 统一请求
VoiceCloneRequest {
String audioUrl; // 音频 URL
String prefix; // 音色前缀
String targetModel; // 目标模型
}
// 统一响应
VoiceCloneResult {
String voiceId; // 生成的音色 ID
String requestId; // 请求 ID
}
3. 配置结构设计
新配置结构:
yudao:
voice:
# 默认供应商
default-provider: cosyvoice
# 供应商配置
providers:
cosyvoice: # 阿里云 CosyVoice
enabled: true
api-key: ${DASHSCOPE_API_KEY}
default-model: cosyvoice-v3-flash
# ... 其他配置
siliconflow: # 阶段二添加
enabled: false
api-key: ${SILICONFLOW_API_KEY}
base-url: https://api.siliconflow.cn
default-model: indextts-2
向后兼容:
- 读取旧配置
yudao.cosyvoice.*并合并到新结构 - 优先使用新配置,旧配置作为 fallback
4. 错误处理策略
- Provider 调用失败时,记录详细日志
- 返回统一的业务异常
VOICE_TTS_FAILED - 不暴露底层供应商的技术细节
Risks / Trade-offs
| Risk | Mitigation |
|---|---|
| 破坏现有功能 | 充分测试,保持 DTO 兼容 |
| 配置迁移复杂 | 支持旧配置自动映射 |
| 性能开销 | 工厂缓存 Provider 实例 |
Migration Plan
阶段一:CosyVoice 重构
- 创建接口和工厂
- 重构 CosyVoice 为 Provider 实现
- 更新 Service 层使用接口
- 测试验证
阶段二:添加 SiliconFlow
- 实现 SiliconFlowProvider
- 添加配置支持
- 集成测试
回滚方案
- 保留原有配置支持
- Feature Flag 控制新逻辑
Open Questions
-
Q: 是否需要支持运行时动态切换供应商? A: 初期不支持,通过配置切换即可
-
Q: 是否需要 Provider 健康检查? A: 阶段二考虑添加
-
Q: DTO 字段差异如何处理? A: 使用公共字段,扩展字段放
Map<String, Object> extensions