From b830388d9fed866385cbd7cefcd22f04a086fb50 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sun, 28 Dec 2025 17:11:13 +0100 Subject: [PATCH] wait for finish tts --- python_bridge/chat_audio_bridge.py | 66 ++++++++++++++++++------------ 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/python_bridge/chat_audio_bridge.py b/python_bridge/chat_audio_bridge.py index 62a466a..07a2f19 100755 --- a/python_bridge/chat_audio_bridge.py +++ b/python_bridge/chat_audio_bridge.py @@ -136,6 +136,12 @@ class ClaudesEyesAudioBridge: self._speaking = threading.Event() self._speaking.clear() # Anfangs nicht am Sprechen + # Awaiting-TTS-Flag: Wird gesetzt wenn Nachricht gesendet wurde + # und wir auf TTS warten. Erst clearen wenn TTS komplett fertig ist. + # So wartet Heartbeat auch während gTTS das Audio generiert. + self._awaiting_tts = threading.Event() + self._awaiting_tts.clear() # Anfangs nicht wartend + # Mute-Flag: Wenn True, ignoriert STT alle Eingaben # Startet gemutet um ungewollte Aufnahmen zu vermeiden self._muted = True @@ -642,19 +648,21 @@ Erst dann starten die automatischen TICKs mit Bildern!""" break # ════════════════════════════════════════════════════════════════ - # WICHTIG: Nach dem Claude fertig getippt hat, warte kurz damit - # TTS die Nachricht finden und mit Sprechen beginnen kann. - # Dann warte bis TTS fertig ist. + # WICHTIG: Warte bis TTS komplett fertig ist! + # _awaiting_tts wurde beim Senden gesetzt und wird erst + # gelöscht wenn TTS die Nachricht vorgelesen hat (oder wenn + # es nichts vorzulesen gab). # ════════════════════════════════════════════════════════════════ - logger.debug("Claude fertig mit Tippen, warte auf TTS...") - time.sleep(1.5) # Kurz warten bis TTS die Nachricht findet + if self._awaiting_tts.is_set(): + logger.info("Heartbeat: Warte auf TTS (Nachricht wurde gesendet)...") - # Jetzt warte bis TTS fertig ist mit Sprechen - if self._speaking.is_set(): - logger.debug("Claude spricht (TTS), warte bis fertig...") - while self.running and self._speaking.is_set(): + # Warte bis TTS komplett fertig ist (kein Timeout!) + while self.running and self._awaiting_tts.is_set(): + if self._speaking.is_set(): + logger.debug("Heartbeat: Claude spricht gerade...") time.sleep(0.5) - logger.debug("Claude fertig mit Sprechen") + + logger.info("Heartbeat: TTS fertig, fahre fort") if not self.running: break @@ -708,6 +716,10 @@ Erst dann starten die automatischen TICKs mit Bildern!""" stefan_message = f"Stefan sagt: {stefan_text}" console.print(f"[green]🎤 Stefan:[/green] {stefan_text[:100]}{'...' if len(stefan_text) > 100 else ''}") + # WICHTIG: Signalisiere dass wir auf TTS warten + self._awaiting_tts.set() + logger.debug("_awaiting_tts gesetzt (Stefan-Nachricht)") + self.chat.send_message(stefan_message) self.stats.ticks_sent += 1 self.consecutive_errors = 0 @@ -745,6 +757,10 @@ Erst dann starten die automatischen TICKs mit Bildern!""" tick_message = "[TICK]" console.print("[dim]→ TICK[/dim]") + # WICHTIG: Signalisiere dass wir auf TTS warten + self._awaiting_tts.set() + logger.debug("_awaiting_tts gesetzt (TICK)") + success = self.chat.send_message(tick_message) if success: @@ -840,15 +856,7 @@ Erst dann starten die automatischen TICKs mit Bildern!""" if self._current_chat_id: self._save_tts_state(self._current_chat_id, msg.id) - # ════════════════════════════════════════════════════════════════ - # WICHTIG: Nachrichten mit Steuercodes werden NICHT vorgelesen! - # Diese sind reine Roboter-Befehle, keine Sprache für Stefan. - # ════════════════════════════════════════════════════════════════ - if self._contains_control_codes(msg.text): - logger.debug(f"TTS: Nachricht enthält Steuercodes, übersprungen") - continue - - # Text für Sprache aufbereiten + # Text für Sprache aufbereiten (Steuercodes etc. entfernen) speech_text = self._clean_for_speech(msg.text) logger.debug(f"TTS: Original: '{msg.text[:100]}...'") logger.debug(f"TTS: Nach Bereinigung: '{speech_text[:100] if speech_text else ''}' ({len(speech_text) if speech_text else 0} Zeichen)") @@ -859,10 +867,13 @@ Erst dann starten die automatischen TICKs mit Bildern!""" tts_text = tts_text[12:].strip() logger.debug(f"TTS: 'Claude sagt:' entfernt, Rest: '{tts_text}' ({len(tts_text)} Zeichen)") - # Prüfe ob nach Entfernen noch Text übrig ist + # Prüfe ob nach Entfernen noch sprechbarer Text übrig ist # Kein Mindestlänge-Check damit auch kurze Antworten wie "Ja!" gesprochen werden - if not tts_text: - logger.info(f"TTS: Nach Prefix-Entfernung kein Text übrig, übersprungen (Original: '{msg.text[:50]}')") + if not tts_text or not tts_text.strip(): + logger.info(f"TTS: Nach Bereinigung kein sprechbarer Text übrig, übersprungen (Original: '{msg.text[:80]}')") + # Trotzdem _awaiting_tts clearen - die Nachricht wurde verarbeitet! + self._awaiting_tts.clear() + logger.debug("TTS: _awaiting_tts.clear() (kein sprechbarer Text)") continue # In Konsole anzeigen (ohne Prefix) @@ -872,14 +883,15 @@ Erst dann starten die automatischen TICKs mit Bildern!""" # Vorlesen (ohne "Claude sagt:" - das ist ja klar) # WICHTIG: Speaking-Flag setzen damit Heartbeat wartet! - logger.info(f"TTS: Spreche {len(tts_text)} Zeichen...") + logger.info(f"TTS: _speaking.set() - Spreche {len(tts_text)} Zeichen: '{tts_text[:50]}...'") self._speaking.set() # Signalisiere: Claude spricht! try: self.tts.speak(tts_text) finally: self._speaking.clear() # Fertig mit Sprechen + self._awaiting_tts.clear() # TTS komplett fertig! + logger.info("TTS: _speaking.clear() + _awaiting_tts.clear() - Fertig mit Sprechen") self.stats.messages_spoken += 1 - logger.debug("TTS: Sprechen beendet") else: logger.debug(f"TTS: Nachricht ist nicht von Claude, übersprungen") @@ -922,10 +934,10 @@ Erst dann starten die automatischen TICKs mit Bildern!""" time.sleep(0.5) continue - # WICHTIG: Wenn Claude spricht (TTS), nicht aufzeichnen! + # WICHTIG: Wenn Claude spricht (TTS) oder wir auf TTS warten, nicht aufzeichnen! # Das verhindert Echo (Mikrofon nimmt TTS auf) und # überlappende Gespräche - wir lassen Claude ausreden. - if self._speaking.is_set(): + if self._speaking.is_set() or self._awaiting_tts.is_set(): # Falls wir mitten in einer Aufnahme waren, diese beenden if self._recording.is_set(): self._finalize_recording(current_session_texts) @@ -937,7 +949,7 @@ Erst dann starten die automatischen TICKs mit Bildern!""" result = self.stt.listen_once(timeout=1) # Nochmal prüfen nach dem Hören (falls zwischendurch gemutet oder Claude spricht) - if self.is_muted() or self._speaking.is_set(): + if self.is_muted() or self._speaking.is_set() or self._awaiting_tts.is_set(): continue if result and result.text and len(result.text) > 2: