From 5c3deba5ac8a0afcd8c139b8d9fb3b07b6346578 Mon Sep 17 00:00:00 2001 From: dschlueter Date: Fri, 26 Jun 2026 10:41:45 +0200 Subject: [PATCH] =?UTF-8?q?fix(web):=20Barge-in=20=E2=80=94=20in-flight=20?= =?UTF-8?q?TTS-Chunks=20nach=20interrupt=20verwerfen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Beim Barge-in konnte ein Audio-Chunk, der im schmalen Fenster zwischen gesendetem interrupt und dem interrupted-Event/ws.close noch eintraf, weiter eingeplant und ~0,2-0,3 s abgespielt werden (im Browser verifiziert). Fix: Beim Senden von interrupt wird die WS als _aborted markiert; der onmessage-Binär-Handler verwirft danach eintreffende Chunks, statt sie via scheduleChunk weiter abzuspielen. Co-Authored-By: Claude Opus 4.8 --- app/web/app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/web/app.js b/app/web/app.js index 0dbf06b..c575b65 100644 --- a/app/web/app.js +++ b/app/web/app.js @@ -630,6 +630,7 @@ function runTurn(path, onopen) { ws.onmessage = (event) => { if (typeof event.data !== "string") { + if (ws._aborted) return; // nach Barge-in: in-flight-Chunks verwerfen, nicht mehr abspielen pcm.push(event.data); // immer cachen (Replay je Bubble) if (expectChunk) { // satzweiser Chunk -> sofort lueckenlos abspielen expectChunk = false; @@ -792,7 +793,7 @@ micBtn.addEventListener("click", () => { unlockTTS(); // iOS: Geräte-TTS bei der Nutzergeste freischalten if (busy) { // Barge-in: laufende KI-Antwort sofort unterbrechen - if (activeWs) activeWs.send(JSON.stringify({ type: "interrupt" })); + if (activeWs) { activeWs._aborted = true; activeWs.send(JSON.stringify({ type: "interrupt" })); } stopAudio(); statusEl.textContent = "Unterbrochen"; // busy + Button-Reset erfolgen sobald die WS schliesst (-> runTurn resolve -> sendVoice/sendText)