mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-11 03:13:24 +00:00
An agent's tts_voice_id (e.g. "en-US-GuyNeural" for Edge) was applied regardless of the selected TTS provider, causing OpenAI and other providers to reject unknown voice IDs. - Add internal/audio/voice_compat.go with IsVoiceCompatible, GetProviderDefaultVoice, and FilterVoiceForProvider helpers - Update TtsTool.resolveVoiceAndModel to report whether the voice came from an agent override (voiceFromAgent) - Apply applyVoiceCompat per-provider branch in Execute so incompatible agent voices fall back to the provider's default with a slog.Warn for operator visibility - Add voice_compat_test.go with table-driven tests for all cases Co-authored-by: Bruno Clermont <bruno.clermont@gmail.com>
61 lines
1.9 KiB
Go
61 lines
1.9 KiB
Go
package audio
|
|
|
|
import "strings"
|
|
|
|
// edgeVoiceDefaultVoice is the default Edge TTS voice.
|
|
const edgeVoiceDefaultVoice = "en-US-AriaNeural"
|
|
|
|
// openaiDefaultVoice is the default OpenAI TTS voice.
|
|
const openaiDefaultVoice = "alloy"
|
|
|
|
// IsVoiceCompatible reports whether the given voice ID is compatible with the
|
|
// named TTS provider. Returns true for providers without validation rules.
|
|
//
|
|
// Edge voices follow the BCP-47 + Neural suffix pattern (e.g. "en-US-GuyNeural").
|
|
// OpenAI voices are a fixed set: alloy, echo, fable, onyx, nova, shimmer.
|
|
func IsVoiceCompatible(provider, voice string) bool {
|
|
if voice == "" {
|
|
return true
|
|
}
|
|
switch provider {
|
|
case "edge":
|
|
return strings.Contains(voice, "Neural")
|
|
case "openai":
|
|
switch voice {
|
|
case "alloy", "echo", "fable", "onyx", "nova", "shimmer":
|
|
return true
|
|
}
|
|
return false
|
|
default:
|
|
// No validation for other providers.
|
|
return true
|
|
}
|
|
}
|
|
|
|
// GetProviderDefaultVoice returns the default voice ID for the named provider.
|
|
// Returns an empty string for providers where the SDK selects its own default.
|
|
func GetProviderDefaultVoice(provider string) string {
|
|
switch provider {
|
|
case "edge":
|
|
return edgeVoiceDefaultVoice
|
|
case "openai":
|
|
return openaiDefaultVoice
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
// FilterVoiceForProvider returns the voice to use for the given provider.
|
|
// If the voice is incompatible with the provider it falls back to the
|
|
// provider's default voice (which may be empty, signalling "use SDK default").
|
|
// agentOverride indicates the voice came from agent configuration (not from
|
|
// explicit tool args or tenant defaults) so that the caller can decide whether
|
|
// to emit a warning.
|
|
func FilterVoiceForProvider(provider, voice string, agentOverride bool) (filtered string, changed bool) {
|
|
if IsVoiceCompatible(provider, voice) {
|
|
return voice, false
|
|
}
|
|
def := GetProviderDefaultVoice(provider)
|
|
return def, true
|
|
}
|