Files
sionrui/openspec/changes/refactor-voice-provider/design.md
2026-01-27 01:39:08 +08:00

3.3 KiB
Raw Blame History

Technical Design: Voice Clone Provider Refactoring

Context

当前语音克隆功能直接依赖阿里云 CosyVoice 的 SDK 和 API。Service 层直接调用 CosyVoiceClient,导致:

  1. 强耦合:无法轻松切换或添加其他供应商
  2. 测试困难:难以 mock 外部依赖
  3. 扩展性差:添加新供应商需要修改 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 重构

  1. 创建接口和工厂
  2. 重构 CosyVoice 为 Provider 实现
  3. 更新 Service 层使用接口
  4. 测试验证

阶段二:添加 SiliconFlow

  1. 实现 SiliconFlowProvider
  2. 添加配置支持
  3. 集成测试

回滚方案

  • 保留原有配置支持
  • Feature Flag 控制新逻辑

Open Questions

  1. Q: 是否需要支持运行时动态切换供应商? A: 初期不支持,通过配置切换即可

  2. Q: 是否需要 Provider 健康检查? A: 阶段二考虑添加

  3. Q: DTO 字段差异如何处理? A: 使用公共字段,扩展字段放 Map<String, Object> extensions