// Package voice 为 Cyrene 运行时实现异步语音转文字与文字转语音, // 遵循 DevDocs/design/06-多模态.md §1。 // // 语音输入(STT)被转写为文字,并作为一条 chat 消息进入同一条智能体 // 流水线;回复则被合成(TTS)回音频。两个 // 方向都经一条提供方链降级 —— cloud → local → edge-tts/espeak // → silent —— 因此某个提供方不可用时会落到下一级,而不是 // 让整个 turn 失败。默认实现是 HTTP 桩实现,可用 // 标准库 httptest 服务器测试;真实的云端/本地提供方仍作为 // 后续里程碑的适配点。 package voice import "context" // Audio 是一段音频数据及其编码。 type Audio struct { // Format 是编码格式,例如 "wav"、"mp3"、"ogg"。 Format string // Data 是原始音频字节。 Data []byte } // STT 把音频转换成文字。 type STT interface { // STT 转写音频并返回说出的文字。ctx 控制 // 取消,必须被遵守。 STT(ctx context.Context, audio Audio) (string, error) } // TTS 从文字合成语音音频。 type TTS interface { // TTS 从文字合成音频。ctx 控制取消,必须 // 被遵守。 TTS(ctx context.Context, text string) (Audio, error) } // VoiceCloner 从公开的参考音频 URL 创建自定义音色(声音复刻)。 // 未配置 cloner 的提供方(云端一级未配置)返回 ErrNotConfigured。 type VoiceCloner interface { // CloneVoice 创建自定义音色并返回其 voice_id。referenceURL 是 // 公开音频 URL;prefix 是音色名前缀(≤10 个字母数字字符)。 CloneVoice(ctx context.Context, referenceURL, prefix string) (string, error) } // ctxKeyTTSInstruction 是逐请求 TTS 指令的 context 键。 // TTS 接口只携带 (ctx, text),因此可选指令经 // ctx 透传以抵达适配器,而无需拓宽该接口。 type ctxKeyTTSInstruction struct{} // WithTTSInstruction 返回携带一条逐请求 TTS 指令 // (情绪/语气)的 ctx,该指令对这一次调用覆盖配置里的 VOICE_TTS_INSTRUCTION。 func WithTTSInstruction(ctx context.Context, instruction string) context.Context { return context.WithValue(ctx, ctxKeyTTSInstruction{}, instruction) } // TTSInstructionFromContext 返回由 WithTTSInstruction 设置的逐请求 // TTS 指令,未携带时返回 ""。 func TTSInstructionFromContext(ctx context.Context) string { if v, ok := ctx.Value(ctxKeyTTSInstruction{}).(string); ok { return v } return "" }