From d83b777e981765e0372c97450eb814b478969a8e Mon Sep 17 00:00:00 2001 From: Floke Date: Sat, 10 May 2025 08:16:23 +0000 Subject: [PATCH] bugfix --- brancheneinstufung.py | 63 ++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/brancheneinstufung.py b/brancheneinstufung.py index 1b8359ddb..a5953615d 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -2369,18 +2369,11 @@ def is_valid_wikipedia_article_url(url_to_check, lang=None): # Wenn sie in DataProcessor ist, ändern Sie `sheet` zu `self.sheet_handler.sheet` # und fügen `self` als erstes Argument der Methode hinzu. -def alignment_demo(sheet): # Behält Argument bei, falls global - """ - Schreibt die vordefinierte Header-Struktur (Zeilen 1-5) ins angegebene Google Sheet. - Dies dient als "Alignment" der Spalten und zur Dokumentation im Sheet selbst. - """ - logger = logging.getLogger(__name__) # Logger holen +def alignment_demo(sheet): + logger = logging.getLogger(__name__) - # Header-Texte fuer die ersten 5 Zeilen - # Die Reihenfolge der Spalten muss EXAKT mit der Reihenfolge der Schluessel in COLUMN_MAP uebereinstimmen. - # Aktuell 51 Spalten (Index 0-50, A-AY). new_headers = [ - [ # Zeile 1: Spaltenname (Muss mit COLUMN_MAP Schluesseln uebereinstimmen) + [ # Zeile 1: Spaltenname "ReEval Flag", "CRM Name", "CRM Kurzform", "CRM Website", "CRM Ort", "CRM Beschreibung", "CRM Branche", "CRM Beschreibung Branche extern", "CRM Anzahl Techniker", "CRM Umsatz", "CRM Anzahl Mitarbeiter", "CRM Vorschlag Wiki URL", "Wiki URL", "Wiki Absatz", "Wiki Branche", "Wiki Umsatz", "Wiki Mitarbeiter", "Wiki Kategorien", "Chat Wiki Konsistenzpruefung", "Chat Begründung Wiki Inkonsistenz", "Chat Vorschlag Wiki Artikel", "Begründung bei Abweichung", @@ -2393,7 +2386,8 @@ def alignment_demo(sheet): # Behält Argument bei, falls global "Contact Search Timestamp", "Wikipedia Timestamp", "Timestamp letzte Prüfung", "Version", "Tokens", "Website Rohtext", "Website Zusammenfassung", "Website Scrape Timestamp", "Geschaetzter Techniker Bucket", "Finaler Umsatz (Wiki>CRM)", "Finaler Mitarbeiter (Wiki>CRM)", - "Wiki Verif. Timestamp", "SerpAPI Wiki Search Timestamp" + "Wiki Verif. Timestamp", "SerpAPI Wiki Search Timestamp", + "Website Meta-Details" # <<< NEUE SPALTE AZ ], [ # Zeile 2: Quelle der Daten "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", @@ -2408,7 +2402,8 @@ def alignment_demo(sheet): # Behält Argument bei, falls global "System", "System", "System", "System", "System", "Web Scraper", "ChatGPT API", "System", "ML Modell / Skript", "Skript (Wiki/CRM Logik)", "Skript (Wiki/CRM Logik)", - "System", "System" + "System", "System", + "Web Scraper (Modus 'website_details')" # <<< NEUE SPALTE AZ ], [ # Zeile 3: Feldkategorie "Prozess", "Firmenname", "Firmenname", "Website", "Ort", "Beschreibung (Text)", "Branche", "Branche", "Anzahl Servicetechniker", "Umsatz", "Anzahl Mitarbeiter", "Wikipedia Artikel URL", @@ -2423,27 +2418,28 @@ def alignment_demo(sheet): # Behält Argument bei, falls global "Timestamp", "Timestamp", "Timestamp", "Skript Version", "API Tokens", "Website-Content", "Website-Content (Zusammenfassung)", "Timestamp", "Anzahl Servicetechniker (Bucket ML)", "Umsatz (Konsolidiert)", "Anzahl Mitarbeiter (Konsolidiert)", - "Timestamp", "Timestamp" + "Timestamp", "Timestamp", + "Website-Content (Meta)" # <<< NEUE SPALTE AZ ], [ # Zeile 4: Kurze Beschreibung "Systemspalte, irrelevant für den Prompt. Wird genutzt um die manuelle Neuprüfung dieses Accounts durchzuführen ('x' setzen).", - "Enthält den Firmennamen nach bestem Gewissen. Firmennamen sind manchmal herausfordernd, insbesondere was unterschiedliche Schreibweisen, Firmierung, Tochter/Mutterfirmen etc. anbelangt. Zur besseren Trefferquote in der Wikipedia-Suche normalisieren wir den Firmennamen und entfernen sämtliche Firmenformen, wie z.B. AG, GmbH, SE etc.", - "Enthält eine manuell gepflegte (normalisierte) Kurzform des Firmennamens, wie auch ein Mensch die Firma nennen würde. Dies bedeutet insbesondere, dass die Firmenform wie z.B. GmbH oder AG aus dem Namen entfernt wird. Meist entspricht die Kurzform den ersten beiden Worten des Firmennamens. Manchmal sind auch Worte nötig, wenn die ersten beiden worte zu wenig Aussagekraft haben. Beispiele dafür sind beispielsweise Firmen wie 'Schmidt & Söhne', bei denen 'Schmidt &' wenig Sinn machen würde, oder 'Philip Morris Tabakwaren' - weil in diesem Fall 'Philip Morris' zu generisch wäre bzw. wenig eindeutig.", + "Enthält den Firmennamen nach bestem Gewissen...", # (wie gehabt) + "Enthält eine manuell gepflegte (normalisierte) Kurzform des Firmennamens...", # (wie gehabt) "Von uns ermittelte Website des Unternehmens, sofern verfügbar. Kann durch Modi 'website_lookup' oder 'check_urls' aktualisiert werden.", "Von uns ermittelter Ort des Unternehmens.", "Kurze Beschreibung des Unternehmens aus CRM.", "Aktuelle Branchenzuweisung entsprechend unserem Ziel-Branchenschema (manuell oder aus Altsystem).", - "Von Dealfront gelieferte externe Beschreibung der Branche. Diese Branchenbeschreibung sollte in den allermeisten Fällen sehr zutreffend sein und ist vermutlich verlässlicher als die aktuelle Branche aus Spalte G.", - "Von uns Recherchierte Anzahl der Servicetechniker. Diese ist in den meisten Fällen korrekt. Dieser Wert gilt als guter Lernwert um zu verstehen, wie ein Unternehmen aussieht, das viele bzw. wenige Techniker hat. Dies ist je nach Branche und Art des Unternehmens unterschiedlich. Es gibt Unternehmen, die hauptsächlich auf die Produktion fokussiert sind, bei denen Service nur einen kleinen Anteil am Geschäft ausmacht und wiederum andere Unternehmen, die fast nur von Kundenservice leben (z.B. Dienstleister). Es gibt allerdings keine 100% verlässliche Faustformel. Das System soll später seine eigene Schätzung mit den von uns recherchierten Werten vergleichen, um dadurch selbst zu lernen Unternehmen besser einzuschätzen.", + "Von Dealfront gelieferte externe Beschreibung der Branche...", # (wie gehabt) + "Von uns Recherchierte Anzahl der Servicetechniker...", # (wie gehabt) "Von uns recherchierter Umsatz in Mio. € (aus CRM).", "Von uns recherchierte Anzahl der Mitarbeiter (aus CRM).", - "Enthält aus einer alten Recherche Vorschläge für die Wikipedia URL zum Unternehmen. Dieser muss aber nicht stimmen. Sollte als Ausgangs- und Vergleichspunkt für die nachgelagerte Wikipedia-Suche dienen. Der Wert soll mit den üblichen Methoden geprüft werden z.B. kommt die normalisierte Website vor, Ähnlichkeitsprüfung des Firmennamens mit dem Artikelnamen von Wikipedia etc.", + "Enthält aus einer alten Recherche Vorschläge für die Wikipedia URL zum Unternehmen...", # (wie gehabt) "Finale Wikipedia URL des Unternehmens. Quelle: Wikipedia-Scraper (Suche/Extraktion), SerpAPI (Neusuche), ChatGPT (Vorschlag U nach Prüfung), oder manuelle Eingabe.", "Erster aussagekräftiger Absatz des Wikipedia-Artikels (M).", "Aus der Wikipedia-Infobox extrahierte Branche(n).", "Aus der Wikipedia-Infobox extrahierter Umsatz (normalisiert in Mio. €).", "Aus der Wikipedia-Infobox extrahierte Mitarbeiterzahl (normalisiert).", - "Komma-separierte Liste der Kategorien, denen der Artikel in Wikipedia zugewiesen wurde. Hier ist auch häufig eine Branche enthalten, häufig auch noch weitere Informationen etwa zur Gründung, ob sie etwa im DAX gelistet ist etc. Guter Anhaltspunkt zur Differenzierung von Unternehmenseinträgen und Wikipedia-Seiten, die kein Unternehmen beschreiben und fälschlicherweise zugewiesen wurden. Bei jeder Unternehmensseite MUSS das Wort unternehmen in irgendeiner Art und Weise vorkommen. NEGATIVSIGNAL: EHEMALIGES UNTERNEHMEN -> Weist darauf hin, dass das Unternehmen nicht mehr besteht.", + "Komma-separierte Liste der Kategorien, denen der Artikel in Wikipedia zugewiesen wurde...", # (wie gehabt) "Ergebnis der ChatGPT-Prüfung, ob der Wiki-Artikel (M) zum Unternehmen passt. Mögliche Werte: 'OK', 'X', '?' (Verifizierung ausstehend/erneut nötig), 'X (URL Copied)', 'X (Invalid Suggestion)', 'FEHLER'.", "Von ChatGPT generierte Begründung, falls der Wiki-Artikel (M) als inkonsistent zum Unternehmen bewertet wurde.", "Von ChatGPT vorgeschlagene alternative Wikipedia-URL, falls der Artikel in M als unpassend bewertet wurde. Kann auch 'Kein passender Artikel gefunden' enthalten.", @@ -2476,12 +2472,13 @@ def alignment_demo(sheet): # Behält Argument bei, falls global "Konsolidierter Umsatzwert in Mio. €. Priorisiert den Wert aus Wikipedia (P), falls vorhanden und numerisch, ansonsten den Wert aus CRM (J).", "Konsolidierte Mitarbeiterzahl. Priorisiert den Wert aus Wikipedia (Q), falls vorhanden und numerisch, ansonsten den Wert aus CRM (K).", "Zeitstempel der letzten Wikipedia-Artikel-Verifizierung durch ChatGPT (Spalten S-U).", - "Zeitstempel des letzten Versuchs, eine fehlende Wikipedia-URL (M) über SerpAPI zu suchen (Modi `find_wiki_serp` oder `check_urls`)." + "Zeitstempel des letzten Versuchs, eine fehlende Wikipedia-URL (M) über SerpAPI zu suchen (Modi `find_wiki_serp` oder `check_urls`).", + "Extrahierte Meta-Daten der Website: Title, Meta-Description, H1-H3 Überschriften. Wird vom Modus 'website_details' befüllt." # <<< NEUE SPALTE AZ ], [ # Zeile 5: Aufgabe / Funktion "Datenquelle/Prozesssteuerung: 'x' markiert Zeile für Re-Evaluation in Modus 'reeval'.", - "Datenquelle: Firmenname aus CRM.", - "Datenquelle: Manuell gepflegte Kurzform des Firmennamens, primär für API-Suchen (LinkedIn, SerpAPI) genutzt.", + "Datenquelle: Firmenname aus CRM.", # (wie gehabt) + "Datenquelle: Manuell gepflegte Kurzform des Firmennamens, primär für API-Suchen (LinkedIn, SerpAPI) genutzt.", # (wie gehabt) "Datenquelle/Ziel: Website des Unternehmens. Kann durch 'website_lookup' oder 'check_urls' aktualisiert werden.", "Datenquelle: Ort des Unternehmens aus CRM.", "Datenquelle: Beschreibung aus CRM. Input für KI-Analysen.", @@ -2491,7 +2488,7 @@ def alignment_demo(sheet): # Behält Argument bei, falls global "Datenquelle: Umsatz aus CRM. Input für Konsolidierung und ML.", "Datenquelle: Mitarbeiterzahl aus CRM. Input für Konsolidierung und ML.", "Datenquelle: Alte/vorgeschlagene Wiki-URL aus CRM. Dient als initialer Input für Wiki-Prozess.", - "Ziel/Quelle: Finale, als relevant erachtete Wikipedia-URL. Wird von verschiedenen Modi befüllt/genutzt.", + "Ziel/Quelle: Finale, als relevant erachtete Wikipedia-URL. Quelle: Wikipedia-Scraper (Suche/Extraktion), SerpAPI (Neusuche), ChatGPT (Vorschlag U nach Prüfung) oder manuelle Eingabe.", "Quelle: Erster Absatz des Wikipedia-Artikels (M). Input für KI-Analysen, z.B. Wiki-Verifizierung.", "Quelle: Aus Wikipedia-Infobox extrahierte Branche(n). Input für KI-Branchenbewertung.", "Quelle: Aus Wikipedia-Infobox extrahierter Umsatz. Input für Konsolidierung und ML.", @@ -2529,21 +2526,23 @@ def alignment_demo(sheet): # Behält Argument bei, falls global "Ziel: Konsolidierter Umsatz (Wiki-Wert > CRM-Wert). Input für ML-Modell.", "Ziel: Konsolidierte Mitarbeiterzahl (Wiki-Wert > CRM-Wert). Input für ML-Modell.", "System: Timestamp der letzten Wiki-Verifizierung durch ChatGPT (Modus 'wiki_verify'). Steuert Wiederholung.", - "System: Timestamp der letzten SerpAPI-Suche nach einer fehlenden Wiki-URL (Modi 'find_wiki_serp', 'check_urls'). Steuert Wiederholung." + "System: Timestamp der letzten SerpAPI-Suche nach einer fehlenden Wiki-URL (Modi 'find_wiki_serp', 'check_urls'). Steuert Wiederholung.", + "Quelle/Ziel: Strukturierte Meta-Daten der Website (Title, Description, H-Tags). Wird vom Modus 'website_details' befüllt und kann für Analysen/Validierungen genutzt werden." # <<< NEUE SPALTE AZ ] ] - # Stellen Sie sicher, dass die Anzahl der Spalten in allen Header-Zeilen gleich ist + # Sicherstellen, dass die Anzahl der Spalten in allen Header-Zeilen gleich ist + # (Rest der Funktion bleibt gleich wie in meinem vorherigen Vorschlag) + # ... (colnum_string, header_range Berechnung, sheet.update call) ... + num_cols = len(new_headers[0]) if not all(len(row) == num_cols for row in new_headers): logger.critical(f"FEHLER in alignment_demo: Die Anzahl der Spalten in den Header-Zeilen ist nicht konsistent! Erwartet {num_cols} Spalten pro Zeile, aber Längen sind: {[len(row) for row in new_headers]}.") - # Finden Sie die maximale Anzahl Spalten, um den Bereich zumindest grob zu bestimmen, falls inkonsistent num_cols = max(len(row) for row in new_headers) if new_headers else 0 if num_cols == 0: logger.error("FEHLER: Konnte keine Spaltenanzahl für Alignment-Demo Header bestimmen.") return - # Hilfsfunktion zum Konvertieren des 1-basierten Spaltenindex in Buchstaben (A, B, AA, ...) def colnum_string(n): string = "" while n > 0: @@ -2551,10 +2550,18 @@ def alignment_demo(sheet): # Behält Argument bei, falls global string = chr(65 + remainder) + string return string - # Berechnen Sie den Bereich fuer das Update (z.B. A1:AY5) + end_col_letter = colnum_string(num_cols) # Sollte jetzt "AY" oder "AZ" sein, je nach Zählung + # Da wir jetzt Spalte AZ (Index 51) haben, ist die letzte Spalte AZ. + # Die Anzahl der Spalten ist 52 (Index 0 bis 51). + # colnum_string(52) sollte "AZ" ergeben. + # Wenn num_cols = 51 (für Index 0-50), dann end_col_letter = "AY" + # Wenn num_cols = 52 (für Index 0-51), dann end_col_letter = "AZ" + + # Korrekte Berechnung für den Bereich, wenn num_cols die Anzahl der Spalten ist: end_col_letter = colnum_string(num_cols) header_range = f"A1:{end_col_letter}{len(new_headers)}" + logger.info(f"Schreibe Alignment-Demo Header in Bereich {header_range}...") try: sheet.update(values=new_headers, range_name=header_range, value_input_option='USER_ENTERED')