// Package voice implements asynchronous speech-to-text and text-to-speech for // the Cyrene runtime, following DevDocs/design/06-多模态.md §1. // // Voice input (STT) is transcribed to text and fed into the same agent pipeline // as a chat message; the reply is synthesized (TTS) back to audio. Both // directions degrade through a provider chain — cloud → local → edge-tts/espeak // → silent — so an unavailable provider falls through to the next rung instead // of failing the whole turn. The stub default implementations are HTTP-based and // testable with a stdlib httptest server; real cloud/local providers remain // adaptation points for later milestones. package voice import "context" // Audio is a piece of audio data plus its encoding. type Audio struct { // Format is the encoding, e.g. "wav", "mp3", "ogg". Format string // Data is the raw audio bytes. Data []byte } // STT converts audio to text. type STT interface { // STT transcribes audio and returns the spoken text. ctx controls // cancellation and must be honored. STT(ctx context.Context, audio Audio) (string, error) } // TTS synthesizes speech audio from text. type TTS interface { // TTS synthesizes audio from text. ctx controls cancellation and must be // honored. TTS(ctx context.Context, text string) (Audio, error) } // VoiceCloner creates a custom voice (声音复刻) from a public reference audio URL. // A nil-cloner provider (no cloud rung configured) returns ErrNotConfigured. type VoiceCloner interface { // CloneVoice creates a custom voice and returns its voice_id. referenceURL is // a public audio URL; prefix is the voice-name prefix (≤10 alphanumeric chars). CloneVoice(ctx context.Context, referenceURL, prefix string) (string, error) } // ctxKeyTTSInstruction is the context key for a per-request TTS instruction. // The TTS interface only carries (ctx, text), so an optional instruction is // threaded through ctx to reach the adapter without widening the interface. type ctxKeyTTSInstruction struct{} // WithTTSInstruction returns ctx carrying an optional per-request TTS instruction // (emotion/tone) that overrides the configured VOICE_TTS_INSTRUCTION for one call. func WithTTSInstruction(ctx context.Context, instruction string) context.Context { return context.WithValue(ctx, ctxKeyTTSInstruction{}, instruction) } // TTSInstructionFromContext returns the per-request TTS instruction set by // WithTTSInstruction, or "" when none is carried. func TTSInstructionFromContext(ctx context.Context) string { if v, ok := ctx.Value(ctxKeyTTSInstruction{}).(string); ok { return v } return "" }