Fix: TTS seriell statt parallel (Chatterbox nicht thread-safe -> 502/hängt) + Fehler statt ewig 'denkt'

Frontend feuerte Satz-TTS parallel; 3 gleichzeitige Chatterbox-Generierungen zerschossen sich
(alignment-Bug -> 502, keine Stimme, Status blieb 'thinking'). Jetzt seriell (1 Call gleichzeitig,
Reihenfolge bleibt). Wenn nichts abgespielt wird -> Fehlermeldung statt Dauer-'denkt'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-28 01:57:20 +02:00
parent 53d0796bd5
commit 6d7a17e765
4 changed files with 71 additions and 52 deletions
+27 -8
View File
@@ -98,16 +98,29 @@ export function useVoiceAgent() {
let pending = ""
setMessages((m) => [...m, { role: "assistant", text: "" }])
// TTS SERIELL abarbeiten (Satz für Satz), nicht parallel: Chatterbox ist nicht thread-safe
// (parallele Generierungen → 502) und Cloud-Engines mögen keine gleichzeitigen Calls. Hält
// außerdem die Reihenfolge. Die Audio-Wiedergabe selbst puffert die AudioQueue.
let ttsChain: Promise<void> = Promise.resolve()
let spokeAny = false
let ttsFailed = false
const speak = (sentence: string) => {
if (!sentence.trim()) return
fetch("/api/voice/tts", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text: sentence, engine, voice }),
ttsChain = ttsChain.then(async () => {
try {
const r = await fetch("/api/voice/tts", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text: sentence, engine, voice }),
})
if (!r.ok) throw new Error(`TTS ${r.status}`)
await queue.enqueue(await r.arrayBuffer())
spokeAny = true
} catch (e) {
ttsFailed = true
console.error("TTS-Fehler:", e)
}
})
.then((r) => (r.ok ? r.arrayBuffer() : Promise.reject(new Error(`TTS ${r.status}`))))
.then((buf) => queue.enqueue(buf))
.catch((e) => console.error("TTS-Fehler:", e))
}
try {
@@ -155,7 +168,13 @@ export function useVoiceAgent() {
}
}
if (pending.trim()) speak(pending) // Rest (letzter Satz ohne Satzzeichen)
if (!assistant.trim()) setStatus("idle")
await ttsChain // auf alle (seriellen) TTS-Calls warten
if (!assistant.trim()) { setStatus("idle"); return }
// Nichts abgespielt → nicht ewig bei „denkt" hängen, Fehler zeigen.
if (!spokeAny) {
setStatus("error")
setError(ttsFailed ? "Sprachausgabe fehlgeschlagen — Engine/Stimme prüfen." : "Keine Sprachausgabe erzeugt.")
}
} catch (e: any) {
setStatus("error"); setError(`Agent-Antwort fehlgeschlagen: ${e.message}`)
}