fix(route): 不在 router 覆盖 template.VoiceKey,避免对外 voice 名误透传给上游
bug 描述:
原 router.go:169 写 req.VoiceKey = voice,把"对外 voice 名"(OpenAI 风格
字符串,如 "chun"/"alloy")覆盖到 template.VoiceKey,导致上游(provider)
拿到的 VoiceKey 是对外字符串而非上游音色 ID(如 "BV001_streaming")。
火山侧 optionsFromRequest (adapter/volcano/provider.go:55) 直接把
VoiceKey 当 speaker 塞进 HTTP body,结果 speaker="chun" 在火山查不到
-> 55000000。
修法:
- router 只换"账号身份"(Credentials),其它字段(尤其 VoiceKey)由
controller 维护;文档 §5 的设计本就是这样,代码是实现走样
- 删 router.go:169 那行,加注释明确"不动 template.VoiceKey"
- 同步修 SelectAndSynthesize 函数注释,把"调用方契约"写清楚:
* voice (第 2 参数) = 对外 voice 名,用于过滤 Channel.Voices 白名单
* template.VoiceKey 必须是上游 speaker ID,已由 controller 解析 voices 表填好
* router 不修改 template 任何字段,只换 Credentials
回归保护(本地测试,不入库):
- 新增 TestSelectAndSynthesize_VoiceKey_NotOverwrittenByExternalName:
模拟完整链路(对外 voice="chun" + 模板 VoiceKey="BV001_streaming"),
断言 router 调用 Synthesize 时 req.VoiceKey 仍是 "BV001_streaming"
- 顺手重构 mockProvider:加 lastVoiceKey + failOn 字段,清理 FirstFailsSecondSucceeds
测试的随机性陷阱(pickByWeight 是随机的,不应固定 chosen ID)
- 全包 16 个测试通过;go build/vet/test 全绿
影响:
- 客户端语义不变(对外 voice 名仍按 Channel.Voices 白名单过滤)
- controller 行为不变(它原本就在 voice 路由后把 v.Speaker 填到 ttsReq.VoiceKey)
- 上游调用正确(从错误地传对外字符串 -> 正确地传上游 speaker ID)