fix ready loop die zweite

This commit is contained in:
duffyduck 2025-12-29 01:23:13 +01:00
parent 190689cd83
commit 8db8a693b5
2 changed files with 102 additions and 17 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -679,12 +679,14 @@ class ClaudeChatInterface:
if not claude_elements: if not claude_elements:
try: try:
# Claude.ai 2024/2025 nutzt oft conversation-turn Divs # Claude.ai 2024/2025 nutzt oft conversation-turn Divs
# WICHTIG: Wir suchen die INNERSTEN Elemente die mit "Claude sagt:" BEGINNEN # WICHTIG: Wir suchen den CONTAINER der die gesamte Claude-Nachricht enthält,
# und NICHT in der Sidebar/Navigation sind # nicht nur das Element mit "Claude sagt:" - denn [READY] kann in einem
# separaten Child-Element stehen!
found = self.driver.execute_script(""" found = self.driver.execute_script("""
const msgs = []; const msgs = [];
// Suche nach Elementen die mit "Claude sagt:" BEGINNEN // Strategie: Finde Elemente mit "Claude sagt:" und dann den
// ÜBERGEORDNETEN Container der die vollständige Nachricht enthält
const allDivs = document.querySelectorAll('div, p, span'); const allDivs = document.querySelectorAll('div, p, span');
for (const elem of allDivs) { for (const elem of allDivs) {
// Überspringe wenn es ein user-message ist // Überspringe wenn es ein user-message ist
@ -697,30 +699,63 @@ class ClaudeChatInterface:
if (elem.closest('[class*="sidebar"]')) continue; if (elem.closest('[class*="sidebar"]')) continue;
if (elem.closest('[class*="Sidebar"]')) continue; if (elem.closest('[class*="Sidebar"]')) continue;
// Hole den direkten Text-Inhalt (nicht von Kindern) // Hole den direkten Text-Inhalt
const text = (elem.innerText || '').trim(); const text = (elem.innerText || '').trim();
// Text muss mit "Claude sagt:" BEGINNEN (nicht irgendwo enthalten) // Text muss mit "Claude sagt:" BEGINNEN
// Das filtert Container-Elemente raus die die ganze Seite enthalten
if (text.startsWith('Claude sagt:') && text.length > 20 && text.length < 10000) { if (text.startsWith('Claude sagt:') && text.length > 20 && text.length < 10000) {
msgs.push(elem); // Suche nach dem übergeordneten Container (z.B. prose-Container)
// der auch [READY] enthalten könnte
let container = elem;
let parent = elem.parentElement;
// Gehe nach oben bis wir einen guten Container finden
// (max 5 Ebenen, um nicht die ganze Seite zu erfassen)
for (let i = 0; i < 5 && parent; i++) {
const parentText = (parent.innerText || '').trim();
// Stoppe wenn wir einen zu großen Container erreichen
if (parentText.length > 15000) break;
// Stoppe wenn wir in user-message oder Navigation sind
if (parent.getAttribute('data-testid') === 'user-message') break;
if (parent.closest('nav')) break;
// Prüfe ob der Parent-Container [READY] enthält und
// immer noch mit "Claude sagt:" beginnt
if (parentText.startsWith('Claude sagt:') ||
parentText.includes('[READY]') ||
parent.classList.contains('prose') ||
parent.classList.contains('markdown')) {
container = parent;
}
parent = parent.parentElement;
}
msgs.push(container);
} }
} }
// Dedupliziere: Behalte nur die INNERSTEN Elemente // Dedupliziere: Behalte nur die ÄUSSERSTEN (größten) Container
// (die den Text direkt enthalten, nicht Container) // (aber nicht zu groß - max 10000 Zeichen)
const filtered = msgs.filter(div => { const unique = [];
// Behalte dieses Element nur wenn es KEIN anderes Element enthält for (const div of msgs) {
// Prüfe ob dieses Element schon in einem anderen enthalten ist
let isDuplicate = false;
for (const other of msgs) { for (const other of msgs) {
if (other !== div && div.contains(other)) { if (other !== div && other.contains(div)) {
// Dieses Element enthält ein anderes -> verwerfen (zu groß) // Dieses Element ist in einem anderen enthalten
return false; isDuplicate = true;
break;
}
}
if (!isDuplicate && !unique.includes(div)) {
unique.push(div);
} }
} }
return true;
});
return filtered; return unique;
""") or [] """) or []
if found: if found:
claude_elements = found claude_elements = found
@ -1059,6 +1094,56 @@ class ClaudeChatInterface:
logger.info(f"[READY] in bestehender Claude-Nachricht gefunden!") logger.info(f"[READY] in bestehender Claude-Nachricht gefunden!")
return True return True
# FALLBACK 2: Direkte DOM-Suche nach [READY]
# Claude.ai rendert [READY] manchmal in einem separaten Element
# das nicht als Teil der "Claude sagt:" Nachricht erkannt wird
try:
ready_found = self.driver.execute_script("""
// Suche nach einem Element das EXAKT "[READY]" enthält
// WICHTIG: Muss NICHT in user-message sein und NICHT in den Instruktionen
const allElements = document.querySelectorAll('*');
for (const elem of allElements) {
// Nur Blatt-Elemente (keine Container mit Kindern)
if (elem.children.length > 0) continue;
const text = (elem.innerText || elem.textContent || '').trim();
// Muss [READY] enthalten
if (!text.includes('[READY]')) continue;
// Prüfe dass es NICHT in user-message ist
if (elem.closest('[data-testid="user-message"]')) continue;
// Prüfe dass es NICHT in der Sidebar ist
if (elem.closest('nav')) continue;
if (elem.closest('[class*="sidebar"]')) continue;
// Wichtig: Text darf NICHT mit "## WICHTIG" beginnen
// (das wäre ein Heading in den Instruktionen)
if (text.startsWith('## WICHTIG') || text.startsWith('**WICHTIG')) continue;
// Text darf nicht "Bestätige mit [READY]" enthalten
// (das wäre eine Anweisung, keine Bestätigung)
if (text.includes('Bestätige mit')) continue;
if (text.includes('antworte mit')) continue;
if (text.includes('Format muss EXAKT')) continue;
// Wenn der Text kurz ist (<100 Zeichen), ist es wahrscheinlich
// Claudes echte [READY] Bestätigung
// Wenn er lang ist, ist es wahrscheinlich ein Container der Instruktionen enthält
if (text.length > 200) continue;
console.log('Found [READY] in:', text.substring(0, 50));
return true;
}
return false;
""")
if ready_found:
logger.info(f"[READY] via direkte DOM-Suche gefunden!")
return True
except Exception as e:
logger.debug(f"DOM-Suche nach [READY] fehlgeschlagen: {e}")
# Kurz warten bevor nächster Check # Kurz warten bevor nächster Check
time.sleep(1) time.sleep(1)