From 3ca834e633d82f8507a0171c81b0ef87d2c892ed Mon Sep 17 00:00:00 2001 From: duffyduck Date: Wed, 6 May 2026 22:57:20 +0200 Subject: [PATCH] fix(audio): Auto-Removal von Sprachnachrichten ohne STT-Result nach 30s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: Wenn eine Aufnahme leer war, nur Wake-Word-Echo enthielt oder STT sonstwie nichts erkannt hat, sendet die Bridge KEIN stt-Event zurueck — die Placeholder-Bubble "Spracheingabe wird verarbeitet" blieb fuer immer im Chat. Folge-Aufnahmen matchten dann via Substring-Fallback die ALTE Placeholder, der echte Text landete in der falschen Bubble. Fix: nach jedem audio-send einen 30s-Timer starten. Wenn nach Ablauf die Bubble (per audioRequestId identifiziert) immer noch "verarbeitet" ist, wird sie entfernt + Toast "nicht erkannt" zeigt das dem User. So bleibt der State sauber + audioRequestId-Match auf zukuenftige Aufnahmen findet die richtige Bubble (statt die hinterbliebene Placeholder). Co-Authored-By: Claude Opus 4.7 (1M context) --- android/src/screens/ChatScreen.tsx | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/android/src/screens/ChatScreen.tsx b/android/src/screens/ChatScreen.tsx index fb26333..f6c9200 100644 --- a/android/src/screens/ChatScreen.tsx +++ b/android/src/screens/ChatScreen.tsx @@ -535,6 +535,7 @@ const ChatScreen: React.FC = () => { audioRequestId, ...(location && { location }), }); + scheduleStaleAudioCleanup(audioRequestId); // resume() wird durch onPlaybackFinished nach ARIAs Antwort getriggert. } else { // Kein Speech im Window → Konversation beenden (Ohr geht aus oder @@ -656,6 +657,25 @@ const ChatScreen: React.FC = () => { // --- Nachricht senden --- + // Aufraeumen von "verarbeitet"-Placeholder die nie ein STT-Result bekommen + // haben (leere Aufnahme, Wake-Word-Echo, STT-Fehler etc). Nach 30s werden + // sie automatisch entfernt damit nicht-erkannte Aufnahmen nicht den State + // verstopfen + naechste echte Aufnahmen die richtige Bubble ersetzen koennen. + const scheduleStaleAudioCleanup = useCallback((audioRequestId: string) => { + setTimeout(() => { + setMessages(prev => { + const idx = prev.findIndex(m => + m.audioRequestId === audioRequestId && + m.text.includes('Spracheingabe wird verarbeitet') + ); + if (idx < 0) return prev; + console.log('[Chat] Sprachnachricht ohne STT-Result entfernt: %s', audioRequestId); + ToastAndroid.show('Sprachnachricht nicht erkannt — entfernt', ToastAndroid.SHORT); + return prev.filter((_, i) => i !== idx); + }); + }, 30000); + }, []); + const sendTextMessage = useCallback(async () => { const text = inputText.trim(); @@ -743,7 +763,8 @@ const ChatScreen: React.FC = () => { audioRequestId, ...(location && { location }), }); - }, [getCurrentLocation, interruptAriaIfBusy]); + scheduleStaleAudioCleanup(audioRequestId); + }, [getCurrentLocation, interruptAriaIfBusy, scheduleStaleAudioCleanup]); // Datei auswaehlen → zur Pending-Liste hinzufuegen const handleFileSelected = useCallback(async (file: FileData) => {