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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -7,7 +7,7 @@
<link rel="manifest" href="/manifest.webmanifest" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>Mission Control 2.0</title>
<script type="module" crossorigin src="/assets/index-Dtig7Izl.js"></script>
<script type="module" crossorigin src="/assets/index-Crcfqytj.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-jNLzkOWh.css">
</head>
<body>
+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}`)
}