diff --git a/python_bridge/chat_web_interface.py b/python_bridge/chat_web_interface.py index 0ff324f..fe31b9b 100644 --- a/python_bridge/chat_web_interface.py +++ b/python_bridge/chat_web_interface.py @@ -613,35 +613,41 @@ class ClaudeChatInterface: if not claude_elements: try: # Claude.ai 2024/2025 nutzt oft conversation-turn Divs - # WICHTIG: Wir suchen die ÄUSSERSTEN Elemente die "Claude sagt:" enthalten + # WICHTIG: Wir suchen die INNERSTEN Elemente die mit "Claude sagt:" BEGINNEN + # und NICHT in der Sidebar/Navigation sind found = self.driver.execute_script(""" const msgs = []; - // Suche nach Nachrichten die KEINE user-message sind - // und einen substantiellen Text-Inhalt haben - const allDivs = document.querySelectorAll('div'); - for (const div of allDivs) { + // Suche nach Elementen die mit "Claude sagt:" BEGINNEN + const allDivs = document.querySelectorAll('div, p, span'); + for (const elem of allDivs) { // Überspringe wenn es ein user-message ist - if (div.getAttribute('data-testid') === 'user-message') continue; - if (div.closest('[data-testid="user-message"]')) continue; + if (elem.getAttribute('data-testid') === 'user-message') continue; + if (elem.closest('[data-testid="user-message"]')) continue; - // Suche nach Elementen die typische Claude-Antwort-Merkmale haben - const text = div.innerText || ''; + // Überspringe Sidebar/Navigation Elemente + if (elem.closest('nav')) continue; + if (elem.closest('[role="navigation"]')) continue; + if (elem.closest('[class*="sidebar"]')) continue; + if (elem.closest('[class*="Sidebar"]')) continue; - // Claude-Antworten müssen "Claude sagt:" enthalten - // UND der Text muss lang genug sein (mindestens 20 Zeichen) - if (text.includes('Claude sagt:') && text.length > 20) { - msgs.push(div); + // Hole den direkten Text-Inhalt (nicht von Kindern) + const text = (elem.innerText || '').trim(); + + // Text muss mit "Claude sagt:" BEGINNEN (nicht irgendwo enthalten) + // Das filtert Container-Elemente raus die die ganze Seite enthalten + if (text.startsWith('Claude sagt:') && text.length > 20 && text.length < 10000) { + msgs.push(elem); } } - // Dedupliziere: Behalte nur die ÄUSSERSTEN Elemente (Container) - // Nicht die innersten - wir wollen den vollständigen Text! + // Dedupliziere: Behalte nur die INNERSTEN Elemente + // (die den Text direkt enthalten, nicht Container) const filtered = msgs.filter(div => { - // Behalte dieses Element nur wenn kein anderes Element es enthält + // Behalte dieses Element nur wenn es KEIN anderes Element enthält for (const other of msgs) { - if (other !== div && other.contains(div)) { - // Ein anderes Element enthält dieses -> verwerfen + if (other !== div && div.contains(other)) { + // Dieses Element enthält ein anderes -> verwerfen (zu groß) return false; } } @@ -779,9 +785,22 @@ class ClaudeChatInterface: logger.debug(f"Überspringe User-Befehl (normalized): {text}") continue - # Prüfe ob es wirklich eine Claude-Nachricht ist (muss "Claude sagt:" enthalten) - if "Claude sagt:" not in text: - logger.debug(f"Claude-Element {i} übersprungen: Kein 'Claude sagt:' gefunden") + # Prüfe ob es wirklich eine Claude-Nachricht ist (muss mit "Claude sagt:" BEGINNEN) + if not text.startswith("Claude sagt:"): + # Fallback: Prüfe ob "Claude sagt:" irgendwo am Anfang einer Zeile steht + lines = text.split('\n') + found_claude_line = False + for line in lines[:5]: # Nur erste 5 Zeilen prüfen + if line.strip().startswith("Claude sagt:"): + found_claude_line = True + break + if not found_claude_line: + logger.debug(f"Claude-Element {i} übersprungen: Beginnt nicht mit 'Claude sagt:'") + continue + + # Filtere Sidebar/Navigation Elemente (beginnen oft mit "Neuer Chat") + if text.startswith("Neuer Chat") or text.startswith("Chats") or text.startswith("Projekte"): + logger.debug(f"Claude-Element {i} übersprungen: Ist Sidebar/Navigation") continue msg_id = elem.get_attribute("data-message-id")