feat(voice): real TTS fallback chain and whisper-compatible STT
- TTS providers: cloud (OpenAI-compatible /audio/speech, e.g. Bailian compatible mode with cosyvoice), local self-hosted HTTP server, edge-tts CLI, espeak CLI, silent — ordered by TTS_PROVIDER list, skipping providers whose binary/config is missing - STT: whisper-compatible /audio/transcriptions endpoint (cloud or self-hosted faster-whisper), replacing the empty dashscope stub - config: TTS_CLOUD_URL/KEY/MODEL/VOICE, TTS_LOCAL_URL, STT_API_URL/ KEY/MODEL; cloud keys fall back to DASHSCOPE_API_KEY - gateway /voice/tts now returns real audio/mpeg bytes instead of a byte count - tests: cloud/local/whisper round-trips via httptest, chain skip behavior, fallback order; kept and adapted prior service tests
This commit is contained in:
1 parent
b8fb7feb86
commit
a0357a7bbd
7 files changed
+410
-63
No files matched your search
@@ -10,6 +10,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -124,12 +125,24 @@ func main() {
|
||||
logger.Infof("[plugin] loaded %d plugins: %v", reg.Count(), reg.ListNames())
|
||||
|
||||
// === 5. Voice Service ===
|
||||
orEmpty := func(v, fallback string) string {
|
||||
if v != "" {
|
||||
return v
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
voiceSvc := voicesvc.New(voicesvc.Config{
|
||||
STTProvider: cfg.ASRProvider,
|
||||
TTSProviders: []string{cfg.TTSProvider},
|
||||
DashScopeKey: cfg.DashScopeAPIKey,
|
||||
STTApiURL: cfg.STTApiURL,
|
||||
STTApiKey: orEmpty(cfg.STTApiKey, cfg.DashScopeAPIKey),
|
||||
STTModel: cfg.STTModel,
|
||||
TTSProviders: splitComma(cfg.TTSProvider),
|
||||
TTSCloudURL: cfg.TTSCloudURL,
|
||||
TTSCloudKey: orEmpty(cfg.TTSCloudKey, cfg.DashScopeAPIKey),
|
||||
TTSCloudModel: cfg.TTSCloudModel,
|
||||
TTSCloudVoice: cfg.TTSCloudVoice,
|
||||
TTSLocalURL: cfg.TTSLocalURL,
|
||||
})
|
||||
logger.Infof("[voice] ready")
|
||||
logger.Infof("[voice] ready (tts chain: %v)", voiceSvc.TTSProviderNames())
|
||||
|
||||
// === 6. Memory Service ===
|
||||
var memSvc *memory.Service
|
||||
@@ -407,6 +420,17 @@ type llmLoggerAdapter struct{ *llmlog.CallLogger }
|
||||
|
||||
func (a *llmLoggerAdapter) Recent(n int) []map[string]any { return a.CallLogger.RecentMaps(n) }
|
||||
|
||||
// splitComma splits a comma-separated config value into trimmed non-empty parts.
|
||||
func splitComma(s string) []string {
|
||||
var out []string
|
||||
for _, p := range strings.Split(s, ",") {
|
||||
if p = strings.TrimSpace(p); p != "" {
|
||||
out = append(out, p)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func pluginNamesToMap(names []string) []map[string]string {
|
||||
result := make([]map[string]string, len(names))
|
||||
for i, n := range names {
|
||||
|
||||
Reference in new issue
Block a user