diff --git a/python_bridge/chat_audio_bridge.py b/python_bridge/chat_audio_bridge.py index 07a2f19..b47fa6f 100755 --- a/python_bridge/chat_audio_bridge.py +++ b/python_bridge/chat_audio_bridge.py @@ -620,6 +620,8 @@ Erst dann starten die automatischen TICKs mit Bildern!""" check_interval = hb_config.get("check_interval", 1) min_pause = hb_config.get("min_pause", 2) max_pause = hb_config.get("max_pause", 4) + auto_new_chat = hb_config.get("auto_new_chat", True) # Auto-Neuer-Chat bei Bilder-Limit? + auto_new_chat_threshold = hb_config.get("auto_new_chat_threshold", 90) # Ab wieviel Bildern? # Debug-Modus: Keine automatischen TICKs if not auto_tick: @@ -744,10 +746,26 @@ Erst dann starten die automatischen TICKs mit Bildern!""" image_uploaded = True uploaded_count = self.chat.get_images_uploaded_count() - if uploaded_count >= 95: - console.print(f"[bold red]⚠️ {uploaded_count}/100 Bilder! Drücke 'N' für neuen Chat![/bold red]") - elif uploaded_count >= 90: - console.print(f"[yellow]⚠️ {uploaded_count}/100 Bilder - Limit fast erreicht![/yellow]") + # ════════════════════════════════════════════════════════════ + # AUTO-NEUER-CHAT: Bei X+ Bildern automatisch neuen Chat! + # Nur wenn in config aktiviert (auto_new_chat: true) + # ════════════════════════════════════════════════════════════ + if uploaded_count >= auto_new_chat_threshold: + if auto_new_chat: + console.print(f"\n[bold yellow]⚠️ {uploaded_count}/100 Bilder - Starte automatisch neuen Chat![/bold yellow]") + logger.info(f"Auto-Neuer-Chat bei {uploaded_count} Bildern (Threshold: {auto_new_chat_threshold})") + + # Neuen Chat starten (wie bei 'N' Taste) + self._start_new_chat_with_instructions() + + # Heartbeat-Loop neu starten (continue springt zum Anfang) + continue + else: + # Auto-New-Chat deaktiviert - nur warnen + if uploaded_count == auto_new_chat_threshold: + console.print(f"\n[bold yellow]⚠️ {uploaded_count}/100 Bilder - Drücke 'N' für neuen Chat![/bold yellow]") + logger.warning(f"Bilder-Limit erreicht ({uploaded_count}), auto_new_chat ist deaktiviert") + elif uploaded_count % 10 == 0: console.print(f"[dim]📷 {uploaded_count} Bilder hochgeladen (Limit: 100)[/dim]") else: diff --git a/python_bridge/chat_web_interface.py b/python_bridge/chat_web_interface.py index 0fc1642..3a09760 100644 --- a/python_bridge/chat_web_interface.py +++ b/python_bridge/chat_web_interface.py @@ -298,6 +298,35 @@ class ClaudeChatInterface: return result + def wait_for_input_field(self, timeout: int = 60) -> bool: + """ + Wartet bis das Chat-Eingabefeld verfügbar ist. + + Nützlich nach CAPTCHA/Login wenn das UI noch lädt. + + Args: + timeout: Maximale Wartezeit in Sekunden + + Returns: + True wenn Eingabefeld gefunden, False bei Timeout + """ + logger.info(f"Warte auf Chat-Eingabefeld (max {timeout}s)...") + start_time = time.time() + + while time.time() - start_time < timeout: + input_field = self._find_input_field() + if input_field: + try: + if input_field.is_displayed() and input_field.is_enabled(): + logger.info("Chat-Eingabefeld bereit!") + return True + except: + pass + time.sleep(1) + + logger.warning(f"Timeout: Eingabefeld nach {timeout}s nicht gefunden") + return False + def send_message_with_delay(self, text: str, delay_before_send: int = 15) -> bool: """ Sendet eine Nachricht mit Verzögerung vor dem Absenden. @@ -306,6 +335,7 @@ class ClaudeChatInterface: Zwischenablage/das Eingabefeld Zeit braucht um den Text zu verarbeiten. Ablauf: + 0. Warte bis Eingabefeld verfügbar (für CAPTCHA/Login-Fälle) 1. Text via JavaScript ins Eingabefeld einfügen (vermeidet Tastaturlayout-Probleme!) 2. Warte delay_before_send Sekunden 3. Send-Button klicken (mit Retry) @@ -318,6 +348,11 @@ class ClaudeChatInterface: True wenn erfolgreich gesendet """ try: + # WICHTIG: Warte auf Eingabefeld (CAPTCHA/Login kann dauern!) + if not self.wait_for_input_field(timeout=120): + logger.error("Eingabefeld nicht verfügbar nach 120s!") + return False + # Finde Eingabefeld input_field = self._find_input_field() @@ -966,8 +1001,8 @@ class ClaudeChatInterface: """ Wartet bis Claude [READY] sendet. - Sucht nach [READY] das NICHT Teil des Instruktions-Textes ist. - Wir zählen wie oft [READY] vorkommt - wenn mehr als 1x, hat Claude geantwortet. + WICHTIG: Prüft nur die LETZTE Claude-Nachricht! + So werden alte [READY] im Chat-Verlauf ignoriert. Args: timeout: Maximale Wartezeit in Sekunden @@ -975,9 +1010,13 @@ class ClaudeChatInterface: Returns: True wenn [READY] empfangen, False bei Timeout """ - logger.info(f"Warte auf [READY] Signal (max {timeout}s)...") + logger.info(f"Warte auf [READY] Signal in letzter Claude-Nachricht (max {timeout}s)...") start_time = time.time() + # Merke die Anzahl der Claude-Nachrichten VOR dem Senden + initial_count = self._count_claude_messages() + logger.debug(f"Initiale Claude-Nachrichten: {initial_count}") + while time.time() - start_time < timeout: # Warte bis Claude fertig ist mit Tippen typing_wait_start = time.time() @@ -988,24 +1027,16 @@ class ClaudeChatInterface: logger.debug("Typing-Wait Timeout, prüfe trotzdem...") break - # Suche [READY] im Seitentext via JavaScript - # Zähle wie oft [READY] vorkommt - 1x ist unsere Instruktion, 2x+ bedeutet Claude hat geantwortet - try: - ready_count = self.driver.execute_script(""" - const text = document.body.innerText.toUpperCase(); - const matches = text.match(/\\[READY\\]/g); - return matches ? matches.length : 0; - """) - - logger.debug(f"[READY] gefunden: {ready_count}x") - - # Mehr als 1x = Claude hat auch [READY] geschrieben - if ready_count and ready_count >= 2: - logger.info(f"[READY] Signal gefunden! ({ready_count}x im Text)") + # Prüfe ob es eine NEUE Claude-Nachricht gibt + current_count = self._count_claude_messages() + if current_count > initial_count: + # Hole die letzte Claude-Nachricht + last_msg = self.get_last_assistant_message() + if last_msg and '[READY]' in last_msg.text.upper(): + logger.info(f"[READY] in letzter Claude-Nachricht gefunden!") return True - - except Exception as e: - logger.debug(f"JavaScript [READY] Suche fehlgeschlagen: {e}") + else: + logger.debug(f"Neue Nachricht aber kein [READY]: {last_msg.text[:50] if last_msg else 'None'}...") # Kurz warten bevor nächster Check time.sleep(1) @@ -1013,6 +1044,15 @@ class ClaudeChatInterface: logger.warning(f"Timeout: Kein [READY] nach {timeout}s") return False + def _count_claude_messages(self) -> int: + """Zählt die Anzahl der Claude-Nachrichten im Chat""" + try: + messages = self._get_all_messages() + return sum(1 for m in messages if m.is_from_assistant) + except Exception as e: + logger.debug(f"Fehler beim Zählen: {e}") + return 0 + def take_screenshot(self, path: str = "screenshot.png"): """Macht einen Screenshot (für Debugging)""" self.driver.save_screenshot(path) diff --git a/python_bridge/config.yaml b/python_bridge/config.yaml index bbc3401..a00bb1e 100644 --- a/python_bridge/config.yaml +++ b/python_bridge/config.yaml @@ -52,6 +52,14 @@ heartbeat: # Nach wie vielen Fehlern in Folge stoppen? max_consecutive_errors: 5 + # Automatisch neuen Chat starten wenn Bilder-Limit erreicht? + # true = Bei 90+ Bildern automatisch neuen Chat starten + # false = Nur Warnung anzeigen, manuell mit 'N' neuen Chat starten + auto_new_chat: true + + # Ab wie vielen Bildern neuen Chat starten (nur wenn auto_new_chat: true) + auto_new_chat_threshold: 90 + # ============================================================================ # Text-to-Speech (Claudes Stimme) # ============================================================================