bugfix
This commit is contained in:
@@ -4349,211 +4349,143 @@ class DataProcessor:
|
||||
in Spalte A geloescht, wenn die Zeile verarbeitet wurde.
|
||||
Defaults to False.
|
||||
"""
|
||||
# Verwenden Sie logger, da das Logging jetzt konfiguriert ist
|
||||
self.logger.info(f"--- Starte Verarbeitung fuer Zeile {row_num_in_sheet} {'(Re-Eval)' if force_reeval else ''} (Schritte: {', '.join(steps_to_run) if steps_to_run else 'Keine ausgewählt'}) ---") # <<< GEÄNDERT
|
||||
|
||||
# Liste zur Sammlung von Sheet-Updates fuer diese Zeile
|
||||
# Updates sind Dictionaries: {'range': 'A1', 'values': [['Wert']]}
|
||||
self.logger.info(f"--- Starte Verarbeitung fuer Zeile {row_num_in_sheet} {'(Re-Eval)' if force_reeval else ''} (Schritte: {', '.join(steps_to_run) if steps_to_run else 'Keine ausgewählt'}) ---")
|
||||
updates = []
|
||||
|
||||
# Aktueller Zeitstempel fuer die Timestamp-Spalten
|
||||
now_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# Flag, ob IRGENDEINE Verarbeitung in dieser Zeile stattgefunden hat
|
||||
any_processing_done = False
|
||||
|
||||
# Flags, die den Zustand der Zeile waehrend DIESES Laufs verfolgen
|
||||
wiki_data_updated_in_this_run = False # Wurden Wiki-Daten (M-R, AN) gerade aktualisiert? (Trigger fuer Chat)
|
||||
chat_eval_just_ran = False # Liefen die ChatGPT-Evaluationen (AO) gerade? (Trigger fuer ML)
|
||||
|
||||
wiki_data_updated_in_this_run = False
|
||||
chat_eval_just_ran = False
|
||||
|
||||
# --- Initiale Werte lesen ---
|
||||
# Lesen Sie die Werte aus den Spalten, die fuer mehrere Schritte benoetigt werden.
|
||||
# Nutzt die interne Helferfunktion _get_cell_value_safe, um sicher auf Zellen zuzugreifen.
|
||||
# Stellen Sie sicher, dass alle benoetigten Spalten in COLUMN_MAP (Block 1) vorhanden sind.
|
||||
|
||||
# CRM Daten
|
||||
company_name = self._get_cell_value_safe(row_data, "CRM Name").strip()
|
||||
website_url = self._get_cell_value_safe(row_data, "CRM Website").strip() # Arbeitskopie der URL (kann sich aendern)
|
||||
original_website_url_in_sheet = website_url # Originalwert aus Sheet behalten, fuer Website Lookup Logik
|
||||
|
||||
crm_kurzform = self._get_cell_value_safe(row_data, "CRM Kurzform").strip() # Benoetigt fuer Contact Search
|
||||
website_url = self._get_cell_value_safe(row_data, "CRM Website").strip()
|
||||
original_website_url_in_sheet = website_url
|
||||
crm_kurzform = self._get_cell_value_safe(row_data, "CRM Kurzform").strip()
|
||||
crm_branche = self._get_cell_value_safe(row_data, "CRM Branche").strip()
|
||||
crm_beschreibung = self._get_cell_value_safe(row_data, "CRM Beschreibung").strip()
|
||||
# CRM Umsatz und Mitarbeiter werden direkt aus row_data geholt, wenn benoetigt (z.B. fuer Konsolidierung)
|
||||
|
||||
# NEU: Wert aus Spalte D (Parent Account Name) hier lesen
|
||||
parent_account_name_d = self._get_cell_value_safe(row_data, "Parent Account Name").strip()
|
||||
self.logger.debug(f" Zeile {row_num_in_sheet}: Gelesener Parent Account (D): '{parent_account_name_d}'")
|
||||
|
||||
|
||||
# Vorhandene Wikipedia-Daten (aus dem Sheet)
|
||||
# Dies sind die Daten, die am ANFANG im Sheet stehen. Sie werden im Wiki-Schritt (Block 21)
|
||||
# durch extrahierte Daten ersetzt, wenn der Wiki-Schritt laeuft.
|
||||
# Initialisiere mit "k.A." wenn die Zelle leer ist.
|
||||
# Vorgeschlagener Parent aus Spalte O (wird für Wiki-Suche und Parent-Vorschlagslogik benötigt)
|
||||
system_suggested_parent_name_o = self._get_cell_value_safe(row_data, "System Vorschlag Parent Account").strip() # Spalte O
|
||||
|
||||
current_wiki_data = {
|
||||
'url': self._get_cell_value_safe(row_data, "Wiki URL") or 'k.A.',
|
||||
'sitz_stadt': self._get_cell_value_safe(row_data, "Wiki Sitz Stadt") or 'k.A.',
|
||||
'sitz_land': self._get_cell_value_safe(row_data, "Wiki Sitz Land") or 'k.A.',
|
||||
'first_paragraph': self._get_cell_value_safe(row_data, "Wiki Absatz") or 'k.A.',
|
||||
'branche': self._get_cell_value_safe(row_data, "Wiki Branche") or 'k.A.',
|
||||
'umsatz': self._get_cell_value_safe(row_data, "Wiki Umsatz") or 'k.A.',
|
||||
'mitarbeiter': self._get_cell_value_safe(row_data, "Wiki Mitarbeiter") or 'k.A.',
|
||||
'categories': self._get_cell_value_safe(row_data, "Wiki Kategorien") or 'k.A.'
|
||||
}
|
||||
# Arbeitskopie fuer die Wiki-Daten. Wird im Wiki-Schritt aktualisiert.
|
||||
# Die Chat-Evaluationen (Block 22) und ML-Schaetzung (Block 23) nutzen diese finalen Daten.
|
||||
final_wiki_data = current_wiki_data.copy()
|
||||
|
||||
website_raw = self._get_cell_value_safe(row_data, "Website Rohtext") or 'k.A.'
|
||||
website_summary = self._get_cell_value_safe(row_data, "Website Zusammenfassung") or 'k.A.'
|
||||
website_meta_details = self._get_cell_value_safe(row_data, "Website Meta-Details") or 'k.A.' # Spalte AI
|
||||
url_pruefstatus = self._get_cell_value_safe(row_data, "URL Prüfstatus") or '' # Spalte AK
|
||||
|
||||
# Vorhandener Website-Rohtext und Zusammenfassung (aus dem Sheet)
|
||||
# Dies sind die Daten, die am ANFANG im Sheet stehen. Sie werden im Website-Schritt (Block 20)
|
||||
# durch gescrapte Daten ersetzt, wenn der Website-Schritt laeuft.
|
||||
# Initialisiere mit "k.A." wenn die Zelle leer ist.
|
||||
current_website_raw = self._get_cell_value_safe(row_data, "Website Rohtext") or 'k.A.'
|
||||
current_website_summary = self._get_cell_value_safe(row_data, "Website Zusammenfassung") or 'k.A.'
|
||||
# Arbeitskopien fuer die Website-Daten. Werden im Website-Schritt aktualisiert.
|
||||
# Die Chat-Evaluationen (Block 22) und ML-Schaetzung (Block 23) nutzen diese finalen Daten.
|
||||
website_raw = current_website_raw # Kann im Website-Schritt aktualisiert werden
|
||||
website_summary = current_website_summary # Kann im Website-Schritt aktualisiert werden
|
||||
|
||||
|
||||
# --- Die Logik fuer die einzelnen Verarbeitungsschritte folgt in den naechsten Bloecken ---
|
||||
# Jeder Schritt prueft, ob er in steps_to_run enthalten ist UND (ob er laut Status noetig ist ODER force_reeval True ist).
|
||||
|
||||
# ======================================================================
|
||||
# === Verarbeitungsschritte innerhalb von _process_single_row ==========
|
||||
# ======================================================================
|
||||
|
||||
# --- 1. Website Handling (Lookup, Scraping, Summarization) ---
|
||||
# Dieser Schritt wird ausgefuehrt, wenn 'web' in steps_to_run enthalten ist UND
|
||||
# (_needs_website_processing True ist ODER force_reeval True ist).
|
||||
# _needs_website_processing prueft AT. Die Lookup-Logik (D leer) ist separat.
|
||||
# Die Website-Verarbeitung umfasst Lookup (optional), Scraping und Summarization.
|
||||
# Nutzt interne Helfer: _get_cell_value_safe, _needs_website_processing.
|
||||
# Nutzt globale Helfer: COLUMN_MAP, logger, serp_website_lookup, get_website_raw, summarize_website_content, datetime, time.
|
||||
|
||||
# Pruefen Sie, ob der Website-Schritt im aktuellen Lauf angefordert wurde
|
||||
# --- 1. Website Handling (Lookup, Scraping, Summarization, Meta) ---
|
||||
run_website_step = 'web' in steps_to_run
|
||||
# Pruefen Sie, ob der Website-Schritt laut Status oder Re-Eval noetig ist
|
||||
website_processing_needed_based_on_status = self._needs_website_processing(row_data, force_reeval)
|
||||
|
||||
# Wenn der Website-Schritt angefordert wurde UND laut Status/Re-Eval noetig ist
|
||||
if run_website_step and website_processing_needed_based_on_status:
|
||||
any_processing_done = True # Markiere, dass in dieser Zeile etwas getan wird
|
||||
any_processing_done = True
|
||||
grund_message_parts_web = []
|
||||
if force_reeval: grund_message_parts_web.append('Re-Eval')
|
||||
if not self._get_cell_value_safe(row_data, "Website Scrape Timestamp").strip(): grund_message_parts_web.append('AJ (Website Scrape Timestamp) leer') # Angepasster Key
|
||||
grund_message_web = ", ".join(filter(None, grund_message_parts_web)) or "Unbekannter Grund"
|
||||
self.logger.info(f"Zeile {row_num_in_sheet}: Fuehre WEBSITE Schritte aus (Grund: {grund_message_web})...")
|
||||
|
||||
# Bestimme den Grund fuer die Ausfuehrung dieses Schritts fuer das Logging
|
||||
grund_message_parts = []
|
||||
if force_reeval: grund_message_parts.append('Re-Eval')
|
||||
if not self._get_cell_value_safe(row_data, "Website Scrape Timestamp").strip(): grund_message_parts.append('AT leer')
|
||||
grund_message = ", ".join(grund_message_parts)
|
||||
|
||||
self.logger.info(f"Zeile {row_num_in_sheet}: Fuehre WEBSITE Schritte aus (Grund: {grund_message})...") # <<< GEÄNDERT
|
||||
|
||||
# Website Lookup nur, wenn die URL in Spalte D (CRM Website) leer oder "k.A." ist
|
||||
# Nutzt die lokal gespeicherte Kopie der URL, die ggf. im Lookup ueberschrieben wird.
|
||||
# a) Website Lookup (nur wenn D leer)
|
||||
if not website_url or website_url.lower() == "k.a.":
|
||||
self.logger.debug(" -> Website URL (D) leer oder k.A., suche ueber SERP...") # <<< GEÄNDERT
|
||||
# Annahme: serp_website_lookup global definiert (Block 10) und nutzt logging/retry
|
||||
try:
|
||||
# Der serp_website_lookup Aufruf ist mit retry_on_failure dekoriert.
|
||||
# Wenn er nach Retries fehlschlaegt, wirft er eine Exception.
|
||||
new_website = serp_website_lookup(company_name) # Nutzt globalen Helfer (Block 10)
|
||||
# Wenn eine neue Website gefunden wurde
|
||||
if new_website != "k.A.":
|
||||
# Ueberschreibe die lokale Variable website_url fuer den weiteren Schritt (Scraping)
|
||||
website_url = new_website
|
||||
# Fuegen Sie das Update fuer Spalte D zur Liste der Sheet-Updates hinzu
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["CRM Website"] + 1)}{row_num_in_sheet}', 'values': [[website_url]]})
|
||||
self.logger.info(f" -> Neue Website gefunden und fuer Update D:{row_num_in_sheet} vorgemerkt: {website_url[:100]}...") # <<< GEÄNDERT
|
||||
else:
|
||||
# Wenn keine neue Website gefunden wurde
|
||||
self.logger.warning(f" -> Keine neue Website ueber SERP gefunden fuer '{company_name[:100]}...'.") # <<< GEÄNDERT
|
||||
# website_url bleibt leer oder k.A. in diesem Fall.
|
||||
self.logger.debug(" -> Website URL (E) leer oder k.A., suche ueber SERP...")
|
||||
try:
|
||||
new_website = serp_website_lookup(company_name)
|
||||
if new_website and new_website.lower() != "k.a." and not new_website.startswith("k.A. (Fehler"):
|
||||
website_url = new_website # Aktualisiere Arbeitskopie
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["CRM Website"] + 1)}{row_num_in_sheet}', 'values': [[website_url]]})
|
||||
self.logger.info(f" -> Neue Website gefunden und für Update E:{row_num_in_sheet} vorgemerkt: {website_url[:100]}...")
|
||||
url_pruefstatus = "URL_OK_SERP" # Status aktualisieren
|
||||
else:
|
||||
self.logger.warning(f" -> Keine neue Website ueber SERP gefunden für '{company_name[:100]}...'.")
|
||||
url_pruefstatus = "URL_SERP_FAILED" if not website_url or website_url.lower() == "k.a." else url_pruefstatus # Nur setzen, wenn vorher keine URL da war
|
||||
except Exception as e_serp_lookup_web:
|
||||
self.logger.error(f"FEHLER bei SERP Website Lookup für '{company_name[:100]}...': {e_serp_lookup_web}")
|
||||
url_pruefstatus = "URL_SERP_ERROR"
|
||||
|
||||
except Exception as e_serp_lookup:
|
||||
# Wenn serp_website_lookup eine Exception wirft (nach Retries)
|
||||
self.logger.error(f"FEHLER bei SERP Website Lookup fuer '{company_name[:100]}...': {e_serp_lookup}") # <<< GEÄNDERT
|
||||
# Bei Fehler bleibt website_url unveraendert (leer oder k.A.). Fahren Sie fort.
|
||||
pass # Fahren Sie fort, falls eine URL im Sheet war oder gefunden wurde
|
||||
|
||||
# Führen Sie Scraping und Zusammenfassung nur durch, wenn eine gueltige Website URL vorhanden ist (lokale Variable website_url)
|
||||
# Ueberpruefen Sie auf nicht-leere website_url und ungleich "k.A." oder Fehlerwerten.
|
||||
# b) Scrape Rohtext, Meta-Details und c) Zusammenfassung (nur wenn URL vorhanden)
|
||||
if website_url and website_url.lower() not in ["k.a.", "kein artikel gefunden", "fehler bei suche", "http:"]:
|
||||
self.logger.debug(f" -> Scrape Rohtext von {website_url[:100]}...") # <<< GEÄNDERT
|
||||
# Annahme: get_website_raw global definiert (Block 11) und nutzt logging/retry
|
||||
try:
|
||||
# Der get_website_raw Aufruf ist mit retry_on_failure dekoriert.
|
||||
# Wenn er nach Retries fehlschlaegt, wirft er eine Exception oder gibt einen Fehlerwert zurueck.
|
||||
new_website_raw = get_website_raw(website_url) # Nutzt globalen Helfer (Block 11)
|
||||
website_raw = new_website_raw # Aktualisiere die lokale Variable (AR Wert)
|
||||
self.logger.debug(f" -> Scrape Rohtext & Meta von {website_url[:100]}...")
|
||||
new_website_raw_temp = "k.A." # Temporär für diesen Scope
|
||||
try:
|
||||
new_website_raw_temp = get_website_raw(website_url) # Nutzt globale Funktion
|
||||
website_raw = new_website_raw_temp # Update der Hauptvariable
|
||||
|
||||
# Wenn get_website_raw einen URL_CHECK_MARKER zurückgibt
|
||||
if website_raw == URL_CHECK_MARKER:
|
||||
url_pruefstatus = URL_CHECK_MARKER
|
||||
self.logger.warning(f" -> get_website_raw markierte URL {website_url} als '{URL_CHECK_MARKER}'. Überspringe weitere Web-Verarbeitung.")
|
||||
website_summary = "k.A. (URL prüfen)" # Verhindere alte Zusammenfassung
|
||||
website_meta_details = "k.A. (URL prüfen)"
|
||||
elif website_raw and str(website_raw).strip().lower() not in ["k.a.", "k.a. (nur cookie-banner erkannt)", "k.a. (fehler)"]:
|
||||
url_pruefstatus = "URL_OK_SCRAPED" # Wenn Scraping (auch nur teilweise) erfolgreich war
|
||||
|
||||
# Meta-Details scrapen (experimentell)
|
||||
try:
|
||||
meta_temp = scrape_website_details(website_url)
|
||||
website_meta_details = meta_temp if meta_temp else "k.A. (Keine Meta-Details)"
|
||||
except Exception as e_meta:
|
||||
self.logger.error(f"FEHLER bei Meta-Detail Scraping für '{website_url[:100]}...': {e_meta}")
|
||||
website_meta_details = f"k.A. (Fehler Meta: {str(e_meta)[:50]})"
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Meta-Details"] + 1)}{row_num_in_sheet}', 'values': [[website_meta_details]]}) # Spalte AI
|
||||
|
||||
# Zusammenfassung nur, wenn gueltiger Rohtext extrahiert wurde.
|
||||
# Pruefen Sie auf nicht-leeren raw_text und ungleich Standard-Fehlerwerten.
|
||||
if website_raw and str(website_raw).strip().lower() not in ["k.a.", "k.a. (nur cookie-banner erkannt)", "k.a. (fehler)"]:
|
||||
self.logger.debug(f" -> Fasse Rohtext zusammen (Laenge: {len(str(website_raw))})...") # <<< GEÄNDERT
|
||||
# Annahme: summarize_website_content global definiert (Block 9) und nutzt logging/retry
|
||||
try:
|
||||
# Der summarize_website_content Aufruf ist mit retry_on_failure dekoriert.
|
||||
# Wenn er nach Retries fehlschlaegt, wirft er eine Exception oder gibt einen Fehlerwert zurueck.
|
||||
new_website_summary = summarize_website_content(website_raw) # Nutzt globalen Helfer (Block 9)
|
||||
# Aktualisiere die lokale Variable (AS Wert). Wenn das Ergebnis leer ist, setze "k.A.".
|
||||
website_summary = new_website_summary if new_website_summary and new_website_summary.strip() else "k.A. (Keine Zusammenfassung erhalten)"
|
||||
# Fuegen Sie das Update fuer Spalte AS (Website Zusammenfassung) zur Liste hinzu
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Zusammenfassung"] + 1)}{row_num_in_sheet}', 'values': [[website_summary]]})
|
||||
|
||||
except Exception as e_summary:
|
||||
# Wenn summarize_website_content eine Exception wirft (nach Retries)
|
||||
self.logger.error(f"FEHLER bei Website Zusammenfassung fuer '{company_name[:100]}...': {e_summary}") # <<< GEÄNDERT
|
||||
# Setze die lokale Variable auf einen Fehlerwert
|
||||
website_summary = f"k.A. (Fehler Zusammenfassung: {str(e_summary)[:100]}...)" # Korrektur: e statt e_summary
|
||||
# Fuegen Sie ein Update mit dem Fehlerwert fuer Spalte AS hinzu
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Zusammenfassung"] + 1)}{row_num_in_sheet}', 'values': [[website_summary]]})
|
||||
pass # Fahren Sie fort
|
||||
|
||||
else:
|
||||
# Wenn kein gueltiger Rohtext zum Zusammenfassen vorhanden war
|
||||
self.logger.debug(" -> Kein gueltiger Rohtext zum Zusammenfassen vorhanden. Zusammenfassung uebersprungen.") # <<< GEÄNDERT
|
||||
# Stellen Sie sicher, dass die lokale Variable korrekt gesetzt ist, falls nicht zusammengefasst
|
||||
website_summary = "k.A."
|
||||
# Fuege 'k.A.' Update fuer AS hinzu (nur wenn es vorher nicht k.A. war?)
|
||||
# Oder immer setzen, wenn der Schritt lief und keine Zusammenfassung erstellt wurde.
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Zusammenfassung"] + 1)}{row_num_in_sheet}', 'values': [['k.A.']]})
|
||||
# Zusammenfassung
|
||||
self.logger.debug(f" -> Fasse Rohtext zusammen (Laenge: {len(str(website_raw))})...")
|
||||
try:
|
||||
summary_temp = summarize_website_content(website_raw)
|
||||
website_summary = summary_temp if summary_temp and summary_temp.strip() else "k.A. (Keine Zusammenfassung erhalten)"
|
||||
except Exception as e_summary_web:
|
||||
self.logger.error(f"FEHLER bei Website Zusammenfassung für '{company_name[:100]}...': {e_summary_web}")
|
||||
website_summary = f"k.A. (Fehler Zusammenfassung: {str(e_summary_web)[:50]})"
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Zusammenfassung"] + 1)}{row_num_in_sheet}', 'values': [[website_summary]]}) # Spalte AH
|
||||
else: # Fehler beim Scraping oder kein sinnvoller Text
|
||||
if not website_raw.startswith("k.A. (Fehler"): # Wenn es kein expliziter Fehler war, sondern z.B. nur Cookie-Banner
|
||||
url_pruefstatus = "URL_SCRAPE_EMPTY_OR_BANNER"
|
||||
# website_raw enthält bereits den Fehler oder "k.A. (nur Cookie...)"
|
||||
website_summary = "k.A." # Keine Zusammenfassung bei fehlerhaftem/leerem Rohtext
|
||||
website_meta_details = "k.A."
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Zusammenfassung"] + 1)}{row_num_in_sheet}', 'values': [[website_summary]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Meta-Details"] + 1)}{row_num_in_sheet}', 'values': [[website_meta_details]]})
|
||||
|
||||
|
||||
# Fuegen Sie das Update fuer Spalte AR (Website Rohtext) zur Liste hinzu (auch wenn es ein Fehlerwert ist)
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Rohtext"] + 1)}{row_num_in_sheet}', 'values': [[website_raw]]})
|
||||
|
||||
except Exception as e_scrape:
|
||||
# Wenn get_website_raw eine Exception wirft (nach Retries)
|
||||
self.logger.error(f"FEHLER beim Website Scraping fuer '{company_name[:100]}' ({website_url[:100]}...): {e_scrape}") # <<< GEÄNDERT
|
||||
# Setze die lokalen Variablen auf Fehlerwerte
|
||||
website_raw = f"k.A. (Fehler Scraping: {str(e_scrape)[:100]}...)" # Korrektur: e statt e_scrape
|
||||
website_summary = "k.A. (Fehler Zusammenfassung)" # Zusammenfassung fehlschlaegt auch
|
||||
# Fuegen Sie Updates mit Fehlerwerten fuer AR und AS hinzu
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Rohtext"] + 1)}{row_num_in_sheet}', 'values': [[website_raw]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Zusammenfassung"] + 1)}{row_num_in_sheet}', 'values': [[website_summary]]})
|
||||
pass # Fahren Sie fort
|
||||
|
||||
else:
|
||||
# Wenn keine gueltige Website URL vorhanden/gefunden wurde
|
||||
self.logger.debug(f" -> Keine gueltige Website URL vorhanden/gefunden fuer '{company_name[:100]}...'. Website Verarbeitung uebersprungen.") # <<< GEÄNDERT
|
||||
# Stellen Sie sicher, dass AR und AS auf k.A. gesetzt werden, wenn der Schritt lief, aber keine URL da war.
|
||||
# Die lokalen Variablen behalten ihre initialen Werte (current_...) wenn der Schritt uebersprungen wurde,
|
||||
# aber wenn der Schritt lief, aber keine URL da war, sollten sie auf k.A. gesetzt werden.
|
||||
# Setzen Sie explizit auf k.A. oder Fehlerwerte, falls der Schritt lief aber fehlschlug wegen URL.
|
||||
website_raw = "k.A."
|
||||
website_summary = "k.A."
|
||||
# Fuegen Sie Updates fuer AR und AS hinzu, falls noetig (Vermeidung von doppelten k.A. Updates)
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Rohtext"] + 1)}{row_num_in_sheet}', 'values': [['k.A.']]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Zusammenfassung"] + 1)}{row_num_in_sheet}', 'values': [['k.A.']]})
|
||||
|
||||
|
||||
# Setzen Sie den Website Scrape Timestamp (AT), da der Website-Schritt lief (auch wenn fehlerhaft)
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Scrape Timestamp"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]})
|
||||
|
||||
# else if run_website_step:
|
||||
# Der Website Schritt war angefordert, aber nicht noetig basierend auf Status/Re-Eval.
|
||||
# Die lokalen Variablen website_raw und website_summary behalten ihre initialen Werte (current_...).
|
||||
# self.logger.debug(f"Zeile {row_num_in_sheet}: Ueberspringe WEBSITE Schritte (AT vorhanden und kein Re-Eval).") # Zu viel Laerm im Debug
|
||||
|
||||
|
||||
# --- Der Code fuer den naechsten Verarbeitungsschritt (Wikipedia) folgt im naechsten Block ---
|
||||
# Definition der Methode _process_single_row wird in der naechsten Nachricht fortgesetzt.
|
||||
except Exception as e_scrape_web:
|
||||
self.logger.error(f"FEHLER beim Website Scraping für '{company_name[:100]}' ({website_url[:100]}...): {e_scrape_web}")
|
||||
website_raw = f"k.A. (Fehler Scraping: {str(e_scrape_web)[:50]})"
|
||||
website_summary = "k.A. (Scraping fehlgeschlagen)"
|
||||
website_meta_details = "k.A. (Scraping fehlgeschlagen)"
|
||||
url_pruefstatus = "URL_SCRAPE_ERROR"
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Zusammenfassung"] + 1)}{row_num_in_sheet}', 'values': [[website_summary]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Meta-Details"] + 1)}{row_num_in_sheet}', 'values': [[website_meta_details]]})
|
||||
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Rohtext"] + 1)}{row_num_in_sheet}', 'values': [[website_raw]]}) # Spalte AG
|
||||
|
||||
else: # Keine gültige URL für Scraping
|
||||
self.logger.debug(f" -> Keine gültige Website URL für '{company_name[:100]}...' vorhanden. Web-Verarbeitung übersprungen.")
|
||||
website_raw = "k.A. (Keine URL)"
|
||||
website_summary = "k.A."
|
||||
website_meta_details = "k.A."
|
||||
# Wenn url_pruefstatus noch leer ist (weil keine URL-Suche stattfand), setze es.
|
||||
if not url_pruefstatus : url_pruefstatus = "URL_MISSING"
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Rohtext"] + 1)}{row_num_in_sheet}', 'values': [[website_raw]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Zusammenfassung"] + 1)}{row_num_in_sheet}', 'values': [[website_summary]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Meta-Details"] + 1)}{row_num_in_sheet}', 'values': [[website_meta_details]]})
|
||||
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["URL Prüfstatus"] + 1)}{row_num_in_sheet}', 'values': [[url_pruefstatus]]}) # Spalte AK
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Website Scrape Timestamp"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]}) # Spalte AJ
|
||||
|
||||
# ======================================================================
|
||||
# === 2. Wikipedia Handling (Search, Extraction, Status Reset) ==========
|
||||
@@ -4742,92 +4674,309 @@ class DataProcessor:
|
||||
|
||||
# Timestamp für Wikipedia-Extraktion (Z) immer setzen, wenn der Wiki-Schritt lief
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wikipedia Timestamp"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]})
|
||||
# --- 2. Wikipedia Handling (Search, Extraction, Status Reset) ==========
|
||||
run_wiki_step = 'wiki' in steps_to_run
|
||||
wiki_processing_needed_based_on_status = self._needs_wiki_processing(row_data, force_reeval) # Prüft Z und AC
|
||||
|
||||
# Wenn eine SerpAPI-Suche für die Tochter durchgeführt wurde, setze den SerpAPI Wiki Search Timestamp (AB)
|
||||
# Das Flag `search_for_daughter_wiki_needed` muss aus der Tochter-Logik kommen.
|
||||
# if search_for_daughter_wiki_needed:
|
||||
# updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["SerpAPI Wiki Search Timestamp"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]})
|
||||
if run_wiki_step and wiki_processing_needed_based_on_status:
|
||||
any_processing_done = True
|
||||
|
||||
grund_message_parts_wiki = [] # Für Logging des Grundes
|
||||
if force_reeval: grund_message_parts_wiki.append('Re-Eval')
|
||||
if not self._get_cell_value_safe(row_data, "Wikipedia Timestamp").strip(): grund_message_parts_wiki.append('Z (Wikipedia Timestamp) leer')
|
||||
if self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip().upper() == "X (URL COPIED)": grund_message_parts_wiki.append("AC (Chat Wiki Konsistenzpruefung)='X (URL COPIED)'")
|
||||
grund_message_wiki = ", ".join(filter(None, grund_message_parts_wiki)) or "Unbekannter Grund (Wiki)"
|
||||
self.logger.info(f"Zeile {row_num_in_sheet}: Fuehre WIKI Schritte aus (Grund: {grund_message_wiki})...")
|
||||
|
||||
# Status AC (Chat Wiki Konsistenzpruefung) und AA (Wiki Verif. Timestamp) zurücksetzen, wenn Neubewertung nötig
|
||||
# Dies ist insbesondere dann der Fall, wenn eine neue URL (egal ob von Parent oder Tochter) in R geschrieben wurde,
|
||||
# oder wenn Re-Eval forciert wurde.
|
||||
# Die Logik hierfür muss die `source_of_wiki_data_origin` und `url_to_extract_from` vs. `current_wiki_url_in_sheet_for_daughter` vergleichen.
|
||||
|
||||
# Vereinfachte Reset-Logik: Wenn wiki_data_updated_in_this_run True ist UND der neue Status nicht "INFO_PARENT_WIKI" ist,
|
||||
# dann setze AC auf "?" und leere AA.
|
||||
ac_current_value = self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip()
|
||||
|
||||
# Wenn eine neue URL gefunden und extrahiert wurde (egal ob Parent oder Tochter-Suche)
|
||||
# ODER wenn Re-Eval war und eine URL vorhanden ist, von der extrahiert wurde.
|
||||
reset_ac_aa = False
|
||||
if wiki_data_updated_in_this_run and \
|
||||
final_wiki_data.get('url', 'k.A.').lower() not in ["k.a.", "kein artikel gefunden", "kein artikel gefunden (parent)"] and \
|
||||
not final_wiki_data.get('url', '').startswith("FEHLER"):
|
||||
# Hole aktuellen Wiki-URL der Tochter aus Spalte R
|
||||
current_wiki_url_in_sheet_for_daughter = self._get_cell_value_safe(row_data, "Wiki URL").strip()
|
||||
|
||||
url_to_validate_and_extract = None # Die URL, die wir versuchen zu validieren und zu extrahieren
|
||||
name_for_wiki_article_validation = company_name # Standard: Validiere gegen Tochter-Namen
|
||||
source_of_wiki_data_origin = "Tochter"
|
||||
additional_info_for_af_col = "" # Für Spalte AF "Begründung bei Abweichung"
|
||||
|
||||
# --- START: LOGIK FÜR PARENT-ACCOUNT (O) UND WIKI-URL DER TOCHTER (R) ---
|
||||
if system_suggested_parent_name_o and system_suggested_parent_name_o.lower() != "k.a.":
|
||||
# Fall 1: Parent (O) ist vorgeschlagen.
|
||||
if not current_wiki_url_in_sheet_for_daughter or current_wiki_url_in_sheet_for_daughter.lower() == "k.a.":
|
||||
# Fall 1.1: O gefüllt, R (Tochter-Wiki) leer/k.A. -> Suche Wiki für Parent O
|
||||
self.logger.info(f" Zeile {row_num_in_sheet}: Parent (O) '{system_suggested_parent_name_o}' vorhanden, Wiki-URL der Tochter (R) leer. Versuche Wiki-Suche für Parent via SerpAPI...")
|
||||
try:
|
||||
parent_url_from_serp = serp_wikipedia_lookup(system_suggested_parent_name_o, website=None) # Kein spezifischer Website-Kontext für Parent-Suche
|
||||
if parent_url_from_serp:
|
||||
url_to_validate_and_extract = parent_url_from_serp
|
||||
name_for_wiki_article_validation = system_suggested_parent_name_o # Validierung gegen Parent-Namen
|
||||
source_of_wiki_data_origin = "Parent (O via SerpAPI)"
|
||||
self.logger.info(f" -> Wiki-Artikel für Parent '{system_suggested_parent_name_o}' via SerpAPI gefunden: {url_to_validate_and_extract}")
|
||||
else:
|
||||
self.logger.warning(f" -> Kein Wiki-Artikel für Parent '{system_suggested_parent_name_o}' via SerpAPI gefunden. Fahre fort mit Standard-Tochter-Suche (falls nötig).")
|
||||
# url_to_validate_and_extract bleibt None, Standard-Tochter-Suche wird unten getriggert, wenn nötig.
|
||||
except Exception as e_parent_wiki_search:
|
||||
self.logger.error(f" -> Fehler bei SerpAPI-Suche nach Wiki für Parent '{system_suggested_parent_name_o}': {e_parent_wiki_search}")
|
||||
# Standard-Tochter-Suche wird unten getriggert, wenn nötig.
|
||||
else:
|
||||
# Fall 1.2: O gefüllt, R (Tochter-Wiki) auch gefüllt.
|
||||
self.logger.info(f" Zeile {row_num_in_sheet}: Parent (O) '{system_suggested_parent_name_o}' vorhanden, aber auch Wiki-URL der Tochter (R) '{current_wiki_url_in_sheet_for_daughter}'. Tochter-Wiki (R) wird primär für Validierung/Extraktion verwendet, falls nötig.")
|
||||
url_to_validate_and_extract = current_wiki_url_in_sheet_for_daughter # Nutze die vorhandene Tochter-URL
|
||||
name_for_wiki_article_validation = company_name # Validierung gegen Tochter-Namen
|
||||
source_of_wiki_data_origin = "Tochter (aus R, Parent O ignoriert)"
|
||||
# --- ENDE: LOGIK FÜR PARENT-ACCOUNT (O) UND WIKI-URL DER TOCHTER (R) ---
|
||||
|
||||
# --- START: STANDARD-LOGIK FÜR TOCHTER-WIKI-SUCHE (falls noch keine URL von Parent O bestimmt wurde) ---
|
||||
if url_to_validate_and_extract is None: # Nur wenn noch keine URL vom Parent oder aus R (Re-Eval) kam
|
||||
search_for_daughter_wiki_needed = False
|
||||
status_ac_is_reparse = self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip().upper() == "X (URL COPIED)"
|
||||
timestamp_z_is_empty = not self._get_cell_value_safe(row_data, "Wikipedia Timestamp").strip()
|
||||
r_url_is_valid_looking = current_wiki_url_in_sheet_for_daughter and \
|
||||
"wikipedia.org/wiki/" in current_wiki_url_in_sheet_for_daughter.lower() and \
|
||||
current_wiki_url_in_sheet_for_daughter.lower() not in ["k.a.", "kein artikel gefunden", "fehler bei suche", "http:"]
|
||||
|
||||
if status_ac_is_reparse:
|
||||
self.logger.info(f" Zeile {row_num_in_sheet}: Status AC ist 'X (URL COPIED)'. Starte neue Wiki-Suche für Tochter '{company_name}'.")
|
||||
search_for_daughter_wiki_needed = True
|
||||
elif force_reeval: # Wenn Re-Eval und keine Parent-URL gefunden wurde
|
||||
if r_url_is_valid_looking:
|
||||
self.logger.info(f" Zeile {row_num_in_sheet}: Re-Eval Modus. Nutze vorhandene Tochter-URL (R): {current_wiki_url_in_sheet_for_daughter}")
|
||||
url_to_validate_and_extract = current_wiki_url_in_sheet_for_daughter
|
||||
name_for_wiki_article_validation = company_name
|
||||
source_of_wiki_data_origin = "Tochter (aus R, Re-Eval)"
|
||||
else:
|
||||
self.logger.info(f" Zeile {row_num_in_sheet}: Re-Eval Modus. Tochter-URL (R) leer/ungültig. Starte neue Wiki-Suche für Tochter '{company_name}'.")
|
||||
search_for_daughter_wiki_needed = True
|
||||
elif timestamp_z_is_empty: # Wikipedia Timestamp (Z) fehlt
|
||||
if r_url_is_valid_looking:
|
||||
self.logger.info(f" Zeile {row_num_in_sheet}: Wikipedia Timestamp (Z) fehlt. Validiere vorhandene Tochter-URL (R): {current_wiki_url_in_sheet_for_daughter}")
|
||||
url_to_validate_and_extract = current_wiki_url_in_sheet_for_daughter
|
||||
name_for_wiki_article_validation = company_name
|
||||
source_of_wiki_data_origin = "Tochter (aus R, Z leer)"
|
||||
else:
|
||||
self.logger.info(f" Zeile {row_num_in_sheet}: Wikipedia Timestamp (Z) fehlt und Tochter-URL (R) leer/ungültig. Starte neue Wiki-Suche für Tochter '{company_name}'.")
|
||||
search_for_daughter_wiki_needed = True
|
||||
elif not r_url_is_valid_looking: # Fallback, wenn Z nicht leer, aber R schlecht ist
|
||||
self.logger.info(f" Zeile {row_num_in_sheet}: Tochter-URL (R) ist ungültig ('{current_wiki_url_in_sheet_for_daughter}'). Starte neue Wiki-Suche für Tochter '{company_name}'.")
|
||||
search_for_daughter_wiki_needed = True
|
||||
|
||||
if source_of_wiki_data_origin == "Parent (O)":
|
||||
# AC wurde bereits auf "INFO_PARENT_WIKI" gesetzt, AA geleert. Hier nichts weiter tun.
|
||||
pass
|
||||
elif current_wiki_url_in_sheet_for_daughter != final_wiki_data.get('url'): # URL der Tochter hat sich geändert
|
||||
reset_ac_aa = True
|
||||
elif force_reeval: # Re-Eval und eine URL wurde verarbeitet
|
||||
reset_ac_aa = True
|
||||
elif status_ac_indicates_reparse: # AC war "X (URL COPIED)"
|
||||
reset_ac_aa = True
|
||||
if search_for_daughter_wiki_needed:
|
||||
self.logger.info(f" -> Suche nach Wikipedia-Artikel für Tochter '{company_name}' (Standard-Suche)...")
|
||||
daughter_page_object = self.wiki_scraper.search_company_article(company_name=company_name, website=website_url)
|
||||
if daughter_page_object:
|
||||
url_to_validate_and_extract = daughter_page_object.url
|
||||
name_for_wiki_article_validation = company_name
|
||||
source_of_wiki_data_origin = "Tochter (Standard-Suche)"
|
||||
self.logger.info(f" -> Suche für Tochter '{company_name}' erfolgreich, gefundene URL: {url_to_validate_and_extract}")
|
||||
else:
|
||||
self.logger.warning(f" -> Kein Wiki-Artikel für Tochter '{company_name}' via Standard-Suche gefunden.")
|
||||
url_to_validate_and_extract = "Kein Artikel gefunden" # Signalwert
|
||||
final_wiki_data['url'] = url_to_validate_and_extract # Dies wird direkt in R geschrieben
|
||||
for key_to_clear in ['sitz_stadt', 'sitz_land', 'first_paragraph', 'branche', 'umsatz', 'mitarbeiter', 'categories']:
|
||||
final_wiki_data[key_to_clear] = 'k.A.'
|
||||
wiki_data_updated_in_this_run = True
|
||||
|
||||
# Fallback, wenn immer noch keine URL zum Extrahieren, aber R valide war (z.B. bei _needs_wiki_processing=True wegen Z leer, aber R gut)
|
||||
if url_to_validate_and_extract is None and r_url_is_valid_looking :
|
||||
url_to_validate_and_extract = current_wiki_url_in_sheet_for_daughter
|
||||
name_for_wiki_article_validation = company_name
|
||||
source_of_wiki_data_origin = "Tochter (aus R, Fallback)"
|
||||
self.logger.info(f" Zeile {row_num_in_sheet}: Fallback, nutze URL aus R: {url_to_validate_and_extract} für Validierung/Extraktion.")
|
||||
# --- ENDE: STANDARD-LOGIK FÜR TOCHTER-WIKI-SUCHE ---
|
||||
|
||||
# --- START: VALIDIERUNG UND DATENEXTRAKTION DER ERMITTELTEN URL ---
|
||||
artikel_ist_valide_fuer_extraktion = False # Zurücksetzen für diesen Abschnitt
|
||||
if url_to_validate_and_extract and isinstance(url_to_validate_and_extract, str) and \
|
||||
url_to_validate_and_extract.lower() not in ["k.a.", "kein artikel gefunden"] and \
|
||||
not url_to_validate_and_extract.startswith("FEHLER"):
|
||||
|
||||
self.logger.info(f" Zeile {row_num_in_sheet}: Artikel '{url_to_validate_and_extract}' wird nun gegen '{name_for_wiki_article_validation}' validiert (Herkunft: {source_of_wiki_data_origin})...")
|
||||
page_obj_for_validation = None # Explizit initialisieren
|
||||
try:
|
||||
if url_to_validate_and_extract.startswith("http"):
|
||||
page_obj_for_validation = wikipedia.page(url=url_to_validate_and_extract, auto_suggest=False, preload=False)
|
||||
else: # Annahme: Es ist ein Titel
|
||||
page_obj_for_validation = wikipedia.page(title=url_to_validate_and_extract, auto_suggest=False, preload=False)
|
||||
|
||||
# Die Validierung verwendet die angepasste _validate_article Methode des WikiScrapers
|
||||
if self.wiki_scraper._validate_article(page_obj_for_validation, name_for_wiki_article_validation, website_url): # website_url ist immer die der Tochter
|
||||
artikel_ist_valide_fuer_extraktion = True
|
||||
url_to_validate_and_extract = page_obj_for_validation.url # Kanonische URL übernehmen
|
||||
self.logger.info(f" -> Artikel '{page_obj_for_validation.title}' (URL: {url_to_validate_and_extract}) erfolgreich gegen '{name_for_wiki_article_validation}' validiert.")
|
||||
else: # Artikel nicht valide
|
||||
self.logger.warning(f" -> Artikel '{page_obj_for_validation.title}' NICHT gegen '{name_for_wiki_article_validation}' validiert.")
|
||||
additional_info_for_af_col += f"WARNUNG: Artikel '{page_obj_for_validation.url}' nicht valide für '{name_for_wiki_article_validation}'. "
|
||||
final_wiki_data['url'] = page_obj_for_validation.url # Trotzdem URL speichern
|
||||
for key_to_clear in ['sitz_stadt', 'sitz_land', 'first_paragraph', 'branche', 'umsatz', 'mitarbeiter', 'categories']:
|
||||
final_wiki_data[key_to_clear] = 'k.A. (Artikel nicht valide)' if key_to_clear == 'first_paragraph' else 'k.A.'
|
||||
wiki_data_updated_in_this_run = True # Es gab einen Versuch, die URL zu ändern/setzen
|
||||
|
||||
if reset_ac_aa and ac_current_value != "INFO_PARENT_WIKI": # Nicht zurücksetzen, wenn es gerade erst auf Parent-Info gesetzt wurde
|
||||
self.logger.info(f" Zeile {row_num_in_sheet}: Setze AC ('Chat Wiki Konsistenzpruefung') auf '?' und leere AA ('Wiki Verif. Timestamp') aufgrund neuer/re-evaluierter Wiki-Daten.")
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Wiki Konsistenzpruefung"] + 1)}{row_num_in_sheet}', 'values': [['?']]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Verif. Timestamp"] + 1)}{row_num_in_sheet}', 'values': [['']]})
|
||||
# Auch die abhängigen Spalten AD, AE leeren
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Begründung Wiki Inkonsistenz"] + 1)}{row_num_in_sheet}', 'values': [['']]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Vorschlag Wiki Artikel"] + 1)}{row_num_in_sheet}', 'values': [['']]})
|
||||
except wikipedia.exceptions.PageError:
|
||||
self.logger.warning(f" -> Wiki-Seite für '{url_to_validate_and_extract}' nicht gefunden (PageError) bei Validierungsversuch.")
|
||||
additional_info_for_af_col += f"FEHLER: Seite '{url_to_validate_and_extract}' nicht gefunden. "
|
||||
final_wiki_data['url'] = f"Fehler: Seite '{url_to_validate_and_extract}' nicht gefunden"
|
||||
wiki_data_updated_in_this_run = True
|
||||
except wikipedia.exceptions.DisambiguationError as e_dis_val_wiki:
|
||||
self.logger.warning(f" -> Wiki-Seite für '{url_to_validate_and_extract}' ist eine Begriffsklärung: {e_dis_val_wiki.title}. Optionen: {str(e_dis_val_wiki.options)[:100]}...")
|
||||
additional_info_for_af_col += f"FEHLER: Seite '{url_to_validate_and_extract}' ist Begriffsklärung. "
|
||||
final_wiki_data['url'] = f"Fehler: Begriffsklärung ({url_to_validate_and_extract})"
|
||||
wiki_data_updated_in_this_run = True
|
||||
except Exception as e_val_load_page_wiki:
|
||||
self.logger.error(f" -> Unerwarteter Fehler beim Laden/Validieren der Wiki-Seite '{url_to_validate_and_extract}': {e_val_load_page_wiki}")
|
||||
additional_info_for_af_col += f"FEHLER: Laden/Validieren von '{url_to_validate_and_extract}' fehlgeschlagen. "
|
||||
final_wiki_data['url'] = f"Fehler Validierung: {str(e_val_load_page_wiki)[:50]}"
|
||||
wiki_data_updated_in_this_run = True
|
||||
|
||||
if artikel_ist_valide_fuer_extraktion:
|
||||
self.logger.debug(f" -> Extrahiere Wiki-Daten von validierter URL ({source_of_wiki_data_origin}): {url_to_validate_and_extract[:100]}...")
|
||||
try:
|
||||
extracted_data = self.wiki_scraper.extract_company_data(url_to_validate_and_extract)
|
||||
if extracted_data and isinstance(extracted_data, dict) and extracted_data.get('url') != 'k.A.':
|
||||
final_wiki_data = extracted_data # Überschreibe die Arbeitskopie
|
||||
wiki_data_updated_in_this_run = True
|
||||
self.logger.info(f" -> Datenextraktion von {url_to_validate_and_extract[:100]}... ({source_of_wiki_data_origin}) erfolgreich.")
|
||||
|
||||
if source_of_wiki_data_origin.startswith("Parent"):
|
||||
ac_wert_fuer_parent_wiki = "INFO_PARENT_WIKI" # Spezieller Status
|
||||
self.logger.info(f" -> Setze AC auf '{ac_wert_fuer_parent_wiki}', da Wiki-Daten von Parent.")
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Wiki Konsistenzpruefung"] + 1)}{row_num_in_sheet}', 'values': [[ac_wert_fuer_parent_wiki]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Begründung Wiki Inkonsistenz"] + 1)}{row_num_in_sheet}', 'values': [[f"Daten von Parent: {name_for_wiki_article_validation}"]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Vorschlag Wiki Artikel"] + 1)}{row_num_in_sheet}', 'values': [['']]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Verif. Timestamp"] + 1)}{row_num_in_sheet}', 'values': [['']]})
|
||||
additional_info_for_af_col = f"INFO: Wiki-Daten von Parent '{name_for_wiki_article_validation}' übernommen. " # Überschreibe, da erfolgreich
|
||||
else: # Fehler bei Extraktion oder leeres Ergebnis
|
||||
self.logger.error(f" -> Fehler bei Datenextraktion von {url_to_validate_and_extract[:100]}... (Extraktion leer/ungültig).")
|
||||
final_wiki_data['url'] = url_to_validate_and_extract
|
||||
for key_to_clear in ['sitz_stadt', 'sitz_land', 'first_paragraph', 'branche', 'umsatz', 'mitarbeiter', 'categories']:
|
||||
final_wiki_data[key_to_clear] = 'k.A. (Extraktion fehlgeschlagen)' if key_to_clear == 'first_paragraph' else 'k.A.'
|
||||
wiki_data_updated_in_this_run = True
|
||||
except Exception as e_wiki_extract_final_val:
|
||||
self.logger.error(f"FEHLER bei Wikipedia Datenextraktion von {url_to_validate_and_extract[:100]}...: {e_wiki_extract_final_val}")
|
||||
final_wiki_data['url'] = url_to_validate_and_extract
|
||||
for key_to_clear in ['sitz_stadt', 'sitz_land', 'first_paragraph', 'branche', 'umsatz', 'mitarbeiter', 'categories']:
|
||||
final_wiki_data[key_to_clear] = f'k.A. (FEHLER Extraktion)' if key_to_clear == 'first_paragraph' else 'k.A.'
|
||||
wiki_data_updated_in_this_run = True
|
||||
|
||||
# --- Sheet Updates für Wiki-Daten (R-Y) und Timestamps (Z, AA, AB) ---
|
||||
if wiki_data_updated_in_this_run: # Nur updaten, wenn sich was geändert hat oder Fehler auftrat
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki URL"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('url', 'k.A.')]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Sitz Stadt"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('sitz_stadt', 'k.A.')]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Sitz Land"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('sitz_land', 'k.A.')]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Absatz"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('first_paragraph', 'k.A.')]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Branche"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('branche', 'k.A.')]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Umsatz"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('umsatz', 'k.A.')]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Mitarbeiter"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('mitarbeiter', 'k.A.')]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Kategorien"] + 1)}{row_num_in_sheet}', 'values': [[final_wiki_data.get('categories', 'k.A.')]]})
|
||||
|
||||
# Timestamp für Wikipedia-Extraktion (Z) immer setzen, wenn der Wiki-Schritt lief
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wikipedia Timestamp"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]})
|
||||
|
||||
# Spalte AF Begründung
|
||||
current_af_val = self._get_cell_value_safe(row_data, "Begründung bei Abweichung").strip()
|
||||
if additional_info_for_af_col:
|
||||
new_af_val = (current_af_val + "; " + additional_info_for_af_col if current_af_val else additional_info_for_af_col).strip()
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Begründung bei Abweichung"] + 1)}{row_num_in_sheet}', 'values': [[new_af_val]]})
|
||||
|
||||
# Reset AC, AA, AD, AE falls nötig (Logik von oben wiederholt, angepasst)
|
||||
ac_current_value = self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip()
|
||||
reset_ac_aa_final = False
|
||||
if final_wiki_data.get('url', 'k.A.').lower() not in ["k.a.", "kein artikel gefunden"] and not final_wiki_data.get('url', '').startswith("FEHLER"):
|
||||
if source_of_wiki_data_origin.startswith("Parent") and ac_current_value != "INFO_PARENT_WIKI":
|
||||
# Für Parent-Daten wurde AC schon oben auf INFO_PARENT_WIKI gesetzt, hier nicht nochmal ändern
|
||||
pass
|
||||
elif current_wiki_url_in_sheet_for_daughter != final_wiki_data.get('url'):
|
||||
reset_ac_aa_final = True
|
||||
elif force_reeval:
|
||||
reset_ac_aa_final = True
|
||||
elif self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip().upper() == "X (URL COPIED)": # status_ac_is_reparse
|
||||
reset_ac_aa_final = True
|
||||
|
||||
if reset_ac_aa_final and ac_current_value != "INFO_PARENT_WIKI":
|
||||
self.logger.info(f" Zeile {row_num_in_sheet}: Setze AC auf '?' und leere AA, AD, AE aufgrund neuer/re-evaluierter Wiki-Daten für '{name_for_wiki_article_validation}'.")
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Wiki Konsistenzpruefung"] + 1)}{row_num_in_sheet}', 'values': [['?']]}) # AC
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wiki Verif. Timestamp"] + 1)}{row_num_in_sheet}', 'values': [['']]}) # AA
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Begründung Wiki Inkonsistenz"] + 1)}{row_num_in_sheet}', 'values': [['']]}) # AD
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Vorschlag Wiki Artikel"] + 1)}{row_num_in_sheet}', 'values': [['']]}) # AE
|
||||
|
||||
# --- 2b. System Vorschlag Parent Account (Spalte O, P, Q) ---
|
||||
# Dieser Schritt wird ausgeführt, wenn 'wiki' in steps_to_run enthalten ist (oder ein spezifischer 'parent_suggest'-Schritt)
|
||||
run_parent_suggest_step = 'wiki' in steps_to_run # Oder ein dedizierter Schritt-Key
|
||||
|
||||
# else if run_wiki_step (aber nicht processing_needed_based_on_status):
|
||||
# self.logger.debug(f"Zeile {row_num_in_sheet}: Ueberspringe WIKI Suche/Extraktion (Timestamp V vorhanden, Y nicht 'X (URL Copied)' und kein Re-Eval).")
|
||||
system_vorschlag_parent_o_value = self._get_cell_value_safe(row_data, "System Vorschlag Parent Account").strip()
|
||||
parent_vorschlag_status_p_value = self._get_cell_value_safe(row_data, "Parent Vorschlag Status").strip()
|
||||
|
||||
# --- Ende Wikipedia Handling ---
|
||||
needs_parent_suggestion = (not system_vorschlag_parent_o_value or system_vorschlag_parent_o_value.lower() == 'k.a.') and parent_vorschlag_status_p_value != '-'
|
||||
if force_reeval and parent_vorschlag_status_p_value != '-':
|
||||
needs_parent_suggestion = True # Auch wenn O schon gefüllt war, aber nicht abgelehnt
|
||||
|
||||
if run_parent_suggest_step and needs_parent_suggestion:
|
||||
any_processing_done = True # Zählt als Verarbeitung
|
||||
self.logger.info(f" Zeile {row_num_in_sheet}: Versuche Parent-Account vorzuschlagen...")
|
||||
try:
|
||||
# _suggest_parent_account braucht jetzt auch CRM-Daten und die aktuellen Wiki-Daten als Input
|
||||
suggested_parent_info = self._suggest_parent_account(
|
||||
company_name=company_name,
|
||||
website_url=website_url,
|
||||
crm_beschreibung=crm_beschreibung,
|
||||
# final_wiki_data enthält hier die möglicherweise vom Parent (O) stammenden Wiki-Daten,
|
||||
# was für die Heuristik relevant sein kann (z.B. um nicht sich selbst vorzuschlagen).
|
||||
# Es ist wichtig, dass _suggest_parent_account dies berücksichtigt.
|
||||
wiki_data_dict=final_wiki_data
|
||||
)
|
||||
|
||||
if suggested_parent_info and suggested_parent_info.get("parent_name"):
|
||||
# Nur schreiben, wenn der Vorschlag sich vom aktuellen Wert in D unterscheidet (falls D gesetzt)
|
||||
# oder D leer ist. Und wenn der Vorschlag nicht der Firmenname selbst ist.
|
||||
if suggested_parent_info["parent_name"].strip().lower() != company_name.strip().lower() and \
|
||||
(not parent_account_name_d or suggested_parent_info["parent_name"].strip().lower() != parent_account_name_d.strip().lower()):
|
||||
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["System Vorschlag Parent Account"] + 1)}{row_num_in_sheet}', 'values': [[suggested_parent_info["parent_name"]]]}) # Spalte O
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Parent Vorschlag Status"] + 1)}{row_num_in_sheet}', 'values': [['?']]}) # Spalte P, initial '?'
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Parent Vorschlag Timestamp"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]}) # Spalte Q
|
||||
self.logger.info(f" -> Parent-Vorschlag für O: '{suggested_parent_info['parent_name']}' (Grund: {suggested_parent_info.get('reason', 'N/A')})")
|
||||
else:
|
||||
self.logger.info(f" -> Parent-Vorschlag '{suggested_parent_info['parent_name']}' ist identisch mit Firma oder D. Kein Update für O.")
|
||||
# Optional: Timestamp trotzdem setzen, dass versucht wurde?
|
||||
if system_vorschlag_parent_o_value.lower() == 'k.a.' or not system_vorschlag_parent_o_value: # Wenn O vorher leer war
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Parent Vorschlag Timestamp"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]})
|
||||
|
||||
|
||||
# else if run_wiki_step:
|
||||
# Der Wiki Schritt war angefordert, aber nicht noetig basierend auf Status/Re-Eval.
|
||||
# Die lokalen Variablen final_wiki_data behaelt die initialen Werte (current_...).
|
||||
# self.logger.debug(f"Zeile {row_num_in_sheet}: Ueberspringe WIKI Suche/Extraktion (AN vorhanden, S nicht 'X (URL Copied)' und kein Re-Eval).") # Zu viel Laerm im Debug
|
||||
elif suggested_parent_info and suggested_parent_info.get("status") == "NO_SUGGESTION":
|
||||
self.logger.info(f" -> Kein Parent-Vorschlag gemacht (Grund: {suggested_parent_info.get('reason', 'N/A')}). P/Q nicht geändert, falls O leer war.")
|
||||
# Wenn O vorher leer war, Timestamp setzen, dass es versucht wurde.
|
||||
if system_vorschlag_parent_o_value.lower() == 'k.a.' or not system_vorschlag_parent_o_value:
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Parent Vorschlag Timestamp"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]})
|
||||
|
||||
|
||||
# --- Der Code fuer den naechsten Verarbeitungsschritt (ChatGPT Evaluationen) folgt im naechsten Block ---
|
||||
# Definition der Methode _process_single_row wird in der naechsten Nachricht fortgesetzt.
|
||||
else:
|
||||
self.logger.info(f" -> Kein Parent-Vorschlag von _suggest_parent_account erhalten oder ungültiges Format.")
|
||||
except Exception as e_suggest_parent:
|
||||
self.logger.error(f" -> Fehler bei _suggest_parent_account für Zeile {row_num_in_sheet}: {e_suggest_parent}")
|
||||
# --- ENDE: 2b. Parent-Account-Vorschlag ---
|
||||
|
||||
# --- Ende des Wikipedia-Blocks ---
|
||||
# Der nächste Block wäre ChatGPT-Evaluationen
|
||||
# ======================================================================
|
||||
|
||||
# --- 3. ChatGPT Evaluationen (Branch, FSM, Emp, Umsatz Schaetzungen etc.) ---
|
||||
# Dieser Schritt wird ausgefuehrt, wenn 'chat' in steps_to_run enthalten ist UND
|
||||
# (_needs_chat_evaluations True ist ODER force_reeval True ist).
|
||||
# _needs_chat_evaluations prueft BC (alt AO) oder ob Wiki-Daten in diesem Lauf gerade aktualisiert wurden.
|
||||
# Nutzt interne Helfer: _get_cell_value_safe, _needs_chat_evaluations.
|
||||
# Nutzt globale Helfer: COLUMN_MAP, logger, datetime, time,
|
||||
# evaluate_branche_chatgpt (Block 10),
|
||||
# get_numeric_filter_value (Block 5).
|
||||
# Nutzt lokale Variablen: crm_branche, crm_beschreibung, final_wiki_data, website_summary, wiki_data_updated_in_this_run.
|
||||
|
||||
run_chat_step = 'chat' in steps_to_run
|
||||
# wiki_data_updated_in_this_run wurde im Wikipedia-Block oben gesetzt
|
||||
chat_processing_needed_based_on_status = self._needs_chat_evaluations(row_data, force_reeval, wiki_data_updated_in_this_run)
|
||||
|
||||
if run_chat_step and chat_processing_needed_based_on_status:
|
||||
any_processing_done = True
|
||||
chat_eval_just_ran = True
|
||||
chat_eval_just_ran = True # Wichtig für ML-Schritt später
|
||||
|
||||
grund_message_parts = []
|
||||
if force_reeval: grund_message_parts.append('Re-Eval')
|
||||
if not self._get_cell_value_safe(row_data, "Timestamp letzte Pruefung").strip(): grund_message_parts.append('BC (Timestamp letzte Pruefung) leer') # Neuer Schlüssel BC
|
||||
if wiki_data_updated_in_this_run: grund_message_parts.append('Wiki Daten gerade aktualisiert')
|
||||
|
||||
grund_message = ", ".join(filter(None, grund_message_parts)) or "Unbekannter Grund"
|
||||
# ... (Grund Message für Log erstellen) ...
|
||||
grund_message_parts_chat = []
|
||||
if force_reeval: grund_message_parts_chat.append('Re-Eval')
|
||||
if not self._get_cell_value_safe(row_data, "Timestamp letzte Prüfung").strip(): grund_message_parts_chat.append('BN (Timestamp letzte Prüfung) leer')
|
||||
if wiki_data_updated_in_this_run: grund_message_parts_chat.append('Wiki Daten gerade aktualisiert')
|
||||
grund_message_chat = ", ".join(filter(None, grund_message_parts_chat)) or "Unbekannter Grund (Chat)"
|
||||
self.logger.info(f"Zeile {row_num_in_sheet}: Fuehre CHATGPT Evaluationen & Plausi aus (Grund: {grund_message_chat})...")
|
||||
|
||||
self.logger.info(f"Zeile {row_num_in_sheet}: Fuehre CHATGPT Evaluationen aus (Grund: {grund_message})...")
|
||||
|
||||
# --- 3a. Branchen-Einstufung (AH, AI, AJ, AK) ---
|
||||
self.logger.info(f"Zeile {row_num_in_sheet}: Starte Branchen-Einstufung ueber ChatGPT...") # Log-Level auf INFO geändert
|
||||
# --- 3a. Branchen-Einstufung (AL, AM, AN, AO) ---
|
||||
# ... (Dieser Teil bleibt wie er war, nutzt final_wiki_data, website_summary) ...
|
||||
# ... (Logik für evaluate_branche_chatgpt und Updates für AL, AM, AN, AO) ...
|
||||
self.logger.info(f"Zeile {row_num_in_sheet}: Starte Branchen-Einstufung ueber ChatGPT...")
|
||||
try:
|
||||
# final_wiki_data enthält hier ggf. die Daten des Parents
|
||||
branch_result = evaluate_branche_chatgpt(
|
||||
crm_branche,
|
||||
crm_beschreibung,
|
||||
@@ -4835,164 +4984,94 @@ class DataProcessor:
|
||||
final_wiki_data.get('categories', 'k.A.'),
|
||||
website_summary
|
||||
)
|
||||
# ... (Updates für Spalten AL, AM, AN, AO)
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Vorschlag Branche"] + 1)}{row_num_in_sheet}', 'values': [[branch_result.get("branch", "FEHLER BRANCH")]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Branche Konfidenz"] + 1)}{row_num_in_sheet}', 'values': [[branch_result.get("confidence", "N/A CONF")]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Konsistenz Branche"] + 1)}{row_num_in_sheet}', 'values': [[branch_result.get("consistency", "error CONS")]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Begruendung Abweichung Branche"] + 1)}{row_num_in_sheet}', 'values': [[branch_result.get("justification", "No JUST")]]})
|
||||
except Exception as e_branch_eval_row:
|
||||
self.logger.error(f"FEHLER bei Branchen-Einstufung für Zeile {row_num_in_sheet}: {e_branch_eval_row}")
|
||||
# ... (Fehlerwerte schreiben) ...
|
||||
|
||||
# --- 3b, 3c, 3d: Weitere ChatGPT Evaluationen (FSM, Mitarbeiter, Umsatz) ---
|
||||
# ... (Diese bleiben strukturell gleich, nutzen aber das ggf. aktualisierte final_wiki_data) ...
|
||||
# Zum Beispiel für Mitarbeiterschätzung:
|
||||
# if not final_wiki_data.get('mitarbeiter') or final_wiki_data.get('mitarbeiter', 'k.A.').lower() == 'k.a.':
|
||||
# # ... call_openai_chat für Mitarbeiterschätzung ...
|
||||
# ... etc. für andere ChatGPT-Schritte ...
|
||||
|
||||
# HIER BEGINNT DIE WICHTIGE ÄNDERUNG FÜR KONSOLIDIERUNG UND PLAUSI
|
||||
# --- 3e. Konsolidierung Umsatz/Mitarbeiter (BD, BE) ---
|
||||
self.logger.debug(f" Zeile {row_num_in_sheet}: Konsolidiere Umsatz (BD) und Mitarbeiter (BE) unter Berücksichtigung von Parent (D)...")
|
||||
final_umsatz_str_konsolidiert = "k.A."
|
||||
final_ma_str_konsolidiert = "k.A."
|
||||
try:
|
||||
crm_umsatz_val_str = self._get_cell_value_safe(row_data, "CRM Umsatz") # Spalte L
|
||||
wiki_umsatz_val_str = final_wiki_data.get('umsatz', 'k.A.') # Aus final_wiki_data (kann Parent sein), Spalte W
|
||||
crm_ma_val_str = self._get_cell_value_safe(row_data, "CRM Anzahl Mitarbeiter") # Spalte M
|
||||
wiki_ma_val_str = final_wiki_data.get('mitarbeiter', 'k.A.') # Aus final_wiki_data, Spalte X
|
||||
|
||||
self.logger.debug(f"Zeile {row_num_in_sheet}: branch_result von evaluate_branche_chatgpt: {branch_result}") # DEBUG 1
|
||||
# Numerische Werte für die Logik holen
|
||||
num_crm_umsatz = get_numeric_filter_value(crm_umsatz_val_str, is_umsatz=True)
|
||||
num_wiki_umsatz = get_numeric_filter_value(wiki_umsatz_val_str, is_umsatz=True)
|
||||
num_crm_ma = get_numeric_filter_value(crm_ma_val_str, is_umsatz=False)
|
||||
num_wiki_ma = get_numeric_filter_value(wiki_ma_val_str, is_umsatz=False)
|
||||
|
||||
# Update für "Chat Vorschlag Branche"
|
||||
vorschlag_key = "Chat Vorschlag Branche"
|
||||
vorschlag_col_idx = COLUMN_MAP.get(vorschlag_key)
|
||||
if vorschlag_col_idx is not None:
|
||||
range_str_vorschlag = f'{self.sheet_handler._get_col_letter(vorschlag_col_idx + 1)}{row_num_in_sheet}'
|
||||
wert_vorschlag = branch_result.get("branch", "FEHLER BRANCH")
|
||||
updates.append({'range': range_str_vorschlag, 'values': [[wert_vorschlag]]})
|
||||
self.logger.debug(f"Zeile {row_num_in_sheet}: Update vorbereitet für {vorschlag_key} ({range_str_vorschlag}): '{wert_vorschlag}'")
|
||||
self.logger.debug(f" Konsolidierung Input: CRM_U(L)='{num_crm_umsatz}', Wiki_U(W)='{num_wiki_umsatz}' (aus {source_of_wiki_data_origin}), CRM_M(M)='{num_crm_ma}', Wiki_M(X)='{num_wiki_ma}' (aus {source_of_wiki_data_origin}), Parent_D='{parent_account_name_d}'")
|
||||
|
||||
if parent_account_name_d and parent_account_name_d.lower() != 'k.a.':
|
||||
# Parent-Account (D) ist GEFÜLLT: Primär CRM-Daten der Tochter verwenden.
|
||||
self.logger.info(f" -> Parent D ('{parent_account_name_d}') ist gesetzt. Konsolidiere primär mit CRM-Daten der Tochter für BD/BE.")
|
||||
final_num_umsatz = num_crm_umsatz if num_crm_umsatz > 0 else num_wiki_umsatz # Wiki als Fallback, falls CRM der Tochter fehlt/0 ist
|
||||
final_num_ma = num_crm_ma if num_crm_ma > 0 else num_wiki_ma # Wiki als Fallback
|
||||
else:
|
||||
self.logger.error(f"Zeile {row_num_in_sheet}: Schlüssel '{vorschlag_key}' nicht in COLUMN_MAP gefunden!")
|
||||
|
||||
# NEU: Konfidenz-Score speichern
|
||||
konfidenz_key = "Chat Branche Konfidenz"
|
||||
konfidenz_col_idx = COLUMN_MAP.get(konfidenz_key)
|
||||
if konfidenz_col_idx is not None:
|
||||
range_str_konfidenz = f'{self.sheet_handler._get_col_letter(konfidenz_col_idx + 1)}{row_num_in_sheet}'
|
||||
wert_konfidenz = branch_result.get("confidence", "N/A CONF")
|
||||
updates.append({'range': range_str_konfidenz, 'values': [[wert_konfidenz]]})
|
||||
self.logger.debug(f"Zeile {row_num_in_sheet}: Update vorbereitet für {konfidenz_key} ({range_str_konfidenz}): '{wert_konfidenz}'")
|
||||
else:
|
||||
self.logger.error(f"Zeile {row_num_in_sheet}: Schlüssel '{konfidenz_key}' nicht in COLUMN_MAP gefunden!")
|
||||
|
||||
# Update für "Chat Konsistenz Branche"
|
||||
konsistenz_key = "Chat Konsistenz Branche"
|
||||
konsistenz_col_idx = COLUMN_MAP.get(konsistenz_key)
|
||||
if konsistenz_col_idx is not None:
|
||||
range_str_konsistenz = f'{self.sheet_handler._get_col_letter(konsistenz_col_idx + 1)}{row_num_in_sheet}'
|
||||
wert_konsistenz = branch_result.get("consistency", "error CONS")
|
||||
updates.append({'range': range_str_konsistenz, 'values': [[wert_konsistenz]]})
|
||||
self.logger.debug(f"Zeile {row_num_in_sheet}: Update vorbereitet für {konsistenz_key} ({range_str_konsistenz}): '{wert_konsistenz}'")
|
||||
else:
|
||||
self.logger.error(f"Zeile {row_num_in_sheet}: Schlüssel '{konsistenz_key}' nicht in COLUMN_MAP gefunden!")
|
||||
|
||||
# Update für "Chat Begruendung Abweichung Branche"
|
||||
begruendung_key = "Chat Begruendung Abweichung Branche"
|
||||
begruendung_col_idx = COLUMN_MAP.get(begruendung_key)
|
||||
if begruendung_col_idx is not None:
|
||||
range_str_begruendung = f'{self.sheet_handler._get_col_letter(begruendung_col_idx + 1)}{row_num_in_sheet}'
|
||||
wert_begruendung = branch_result.get("justification", "Keine Begruendung JUST")
|
||||
updates.append({'range': range_str_begruendung, 'values': [[wert_begruendung]]})
|
||||
self.logger.debug(f"Zeile {row_num_in_sheet}: Update vorbereitet für {begruendung_key} ({range_str_begruendung}): '{str(wert_begruendung)[:50]}...'")
|
||||
else:
|
||||
self.logger.error(f"Zeile {row_num_in_sheet}: Schlüssel '{begruendung_key}' nicht in COLUMN_MAP gefunden!")
|
||||
|
||||
except Exception as e_branch_eval:
|
||||
self.logger.error(f"FEHLER bei Branchen-Einstufung ueber ChatGPT fuer Zeile {row_num_in_sheet}: {e_branch_eval}")
|
||||
self.logger.debug(traceback.format_exc())
|
||||
error_msg = f"Fehler Eval: {str(e_branch_eval)[:100]}..."
|
||||
# Fehlerwerte für alle relevanten Spalten schreiben
|
||||
if COLUMN_MAP.get("Chat Vorschlag Branche") is not None:
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Vorschlag Branche"] + 1)}{row_num_in_sheet}', 'values': [['FEHLER']]})
|
||||
if COLUMN_MAP.get("Chat Branche Konfidenz") is not None:
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Branche Konfidenz"] + 1)}{row_num_in_sheet}', 'values': [['N/A (Eval Fehler)']]})
|
||||
if COLUMN_MAP.get("Chat Konsistenz Branche") is not None:
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Konsistenz Branche"] + 1)}{row_num_in_sheet}', 'values': [['error']]})
|
||||
if COLUMN_MAP.get("Chat Begruendung Abweichung Branche") is not None:
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Begruendung Abweichung Branche"] + 1)}{row_num_in_sheet}', 'values': [[error_msg]]})
|
||||
pass
|
||||
|
||||
# --- 3e. Konsolidierung Umsatz/Mitarbeiter (AY, AZ) ---
|
||||
self.logger.debug(" -> Konsolidiere Umsatz (AY) und Mitarbeiter (AZ) (Wiki > CRM Logik)...")
|
||||
final_umsatz_str_konsolidiert = "k.A." # Default
|
||||
final_ma_str_konsolidiert = "k.A." # Default
|
||||
try:
|
||||
crm_umsatz_val = self._get_cell_value_safe(row_data, "CRM Umsatz")
|
||||
wiki_umsatz_val = final_wiki_data.get('umsatz', 'k.A.')
|
||||
crm_ma_val = self._get_cell_value_safe(row_data, "CRM Anzahl Mitarbeiter")
|
||||
wiki_ma_val = final_wiki_data.get('mitarbeiter', 'k.A.')
|
||||
|
||||
# get_numeric_filter_value gibt 0.0 oder 0 zurück, wenn der Input nicht positiv numerisch ist oder leer/k.A.
|
||||
num_crm_umsatz = get_numeric_filter_value(crm_umsatz_val, is_umsatz=True)
|
||||
num_wiki_umsatz = get_numeric_filter_value(wiki_umsatz_val, is_umsatz=True)
|
||||
num_crm_ma = get_numeric_filter_value(crm_ma_val, is_umsatz=False)
|
||||
num_wiki_ma = get_numeric_filter_value(wiki_ma_val, is_umsatz=False)
|
||||
|
||||
# Logge die numerischen Werte VOR der Konsolidierung
|
||||
self.logger.debug(f" Konsolidierung Input: num_crm_umsatz={num_crm_umsatz}, num_wiki_umsatz={num_wiki_umsatz}, num_crm_ma={num_crm_ma}, num_wiki_ma={num_wiki_ma}")
|
||||
|
||||
# Konsolidierung: Wiki > CRM. Wenn Wiki keinen positiven Wert hat, nimm CRM.
|
||||
# Wenn beide keinen positiven Wert haben, bleibt es bei 0.
|
||||
final_num_umsatz = num_wiki_umsatz if num_wiki_umsatz > 0 else num_crm_umsatz
|
||||
final_num_ma = num_wiki_ma if num_wiki_ma > 0 else num_crm_ma
|
||||
# Parent-Account (D) ist LEER: Standardlogik Wiki > CRM.
|
||||
self.logger.debug(f" -> Parent D leer. Standardkonsolidierung Wiki > CRM für BD/BE.")
|
||||
final_num_umsatz = num_wiki_umsatz if num_wiki_umsatz > 0 else num_crm_umsatz
|
||||
final_num_ma = num_wiki_ma if num_wiki_ma > 0 else num_crm_ma
|
||||
|
||||
final_umsatz_str_konsolidiert = str(int(round(final_num_umsatz))) if final_num_umsatz > 0 else 'k.A.'
|
||||
final_ma_str_konsolidiert = str(int(round(final_num_ma))) if final_num_ma > 0 else 'k.A.'
|
||||
|
||||
# String-Konvertierung: "0" bedeutet "unbekannt" -> "k.A."
|
||||
# Nur echt positive Werte werden als Zahl geschrieben.
|
||||
final_umsatz_str_konsolidiert = str(int(round(final_num_umsatz))) if final_num_umsatz > 0 else 'k.A.'
|
||||
final_ma_str_konsolidiert = str(int(round(final_num_ma))) if final_num_ma > 0 else 'k.A.'
|
||||
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Finaler Umsatz (Wiki>CRM)"] + 1)}{row_num_in_sheet}', 'values': [[final_umsatz_str_konsolidiert]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Finaler Mitarbeiter (Wiki>CRM)"] + 1)}{row_num_in_sheet}', 'values': [[final_ma_str_konsolidiert]]})
|
||||
# Das Log hier sollte jetzt die String-Werte ausgeben, die auch geschrieben werden:
|
||||
self.logger.debug(f" -> Konsolidiert (Sheet-Werte): Umsatz='{final_umsatz_str_konsolidiert}', MA='{final_ma_str_konsolidiert}'")
|
||||
except Exception as e_consolidate:
|
||||
self.logger.error(f"FEHLER bei Konsolidierung Umsatz/Mitarbeiter fuer Zeile {row_num_in_sheet}: {e_consolidate}")
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Finaler Umsatz (Wiki>CRM)"] + 1)}{row_num_in_sheet}', 'values': [['FEHLER KONSO']]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Finaler Mitarbeiter (Wiki>CRM)"] + 1)}{row_num_in_sheet}', 'values': [['FEHLER KONSO']]})
|
||||
final_umsatz_str_konsolidiert = "FEHLER KONSO"
|
||||
final_ma_str_konsolidiert = "FEHLER KONSO"
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Finaler Umsatz (Wiki>CRM)"] + 1)}{row_num_in_sheet}', 'values': [[final_umsatz_str_konsolidiert]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Finaler Mitarbeiter (Wiki>CRM)"] + 1)}{row_num_in_sheet}', 'values': [[final_ma_str_konsolidiert]]})
|
||||
self.logger.debug(f" -> Konsolidiert für BD/BE (Sheet-Werte): Umsatz='{final_umsatz_str_konsolidiert}', MA='{final_ma_str_konsolidiert}'")
|
||||
except Exception as e_consolidate_row_final:
|
||||
self.logger.error(f"FEHLER bei Konsolidierung Umsatz/Mitarbeiter (BD/BE) für Zeile {row_num_in_sheet}: {e_consolidate_row_final}")
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Finaler Umsatz (Wiki>CRM)"] + 1)}{row_num_in_sheet}', 'values': [['FEHLER_KONSO']]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Finaler Mitarbeiter (Wiki>CRM)"] + 1)}{row_num_in_sheet}', 'values': [['FEHLER_KONSO']]})
|
||||
final_umsatz_str_konsolidiert = "FEHLER_KONSO" # Für Plausi-Input
|
||||
final_ma_str_konsolidiert = "FEHLER_KONSO"
|
||||
|
||||
# --- NEU: 3f. Plausibilitäts-Checks durchführen (BG-BM) ---
|
||||
self.logger.debug(f" Zeile {row_num_in_sheet}: Führe Plausibilitäts-Checks durch...")
|
||||
plausi_check_erfolgreich_durchgefuehrt = False # Flag
|
||||
# --- 3f. Plausibilitäts-Checks durchführen (BG-BM) ---
|
||||
# Der Aufruf von _check_financial_plausibility muss jetzt parent_account_name_d (Spalte D) übergeben bekommen.
|
||||
self.logger.debug(f" Zeile {row_num_in_sheet}: Führe Plausibilitäts-Checks durch (Parent D: '{parent_account_name_d}')...")
|
||||
try:
|
||||
# ... (Erstellung von plausi_input_data wie zuvor) ...
|
||||
plausi_input_data = {
|
||||
"Finaler Umsatz (Wiki>CRM)": final_umsatz_str_konsolidiert,
|
||||
"Finaler Mitarbeiter (Wiki>CRM)": final_ma_str_konsolidiert,
|
||||
"CRM Umsatz": self._get_cell_value_safe(row_data, "CRM Umsatz"),
|
||||
"Wiki Umsatz": self._get_cell_value_safe(row_data, "Wiki Umsatz"),
|
||||
"CRM Anzahl Mitarbeiter": self._get_cell_value_safe(row_data, "CRM Anzahl Mitarbeiter"),
|
||||
"Wiki Mitarbeiter": self._get_cell_value_safe(row_data, "Wiki Mitarbeiter")
|
||||
"Finaler Umsatz (Wiki>CRM)": final_umsatz_str_konsolidiert, # Aus Schritt 3e
|
||||
"Finaler Mitarbeiter (Wiki>CRM)": final_ma_str_konsolidiert, # Aus Schritt 3e
|
||||
"CRM Umsatz": self._get_cell_value_safe(row_data, "CRM Umsatz"), # Spalte L
|
||||
"Wiki Umsatz": final_wiki_data.get('umsatz', 'k.A.'), # Spalte W (kann von Parent sein)
|
||||
"CRM Anzahl Mitarbeiter": self._get_cell_value_safe(row_data, "CRM Anzahl Mitarbeiter"), # Spalte M
|
||||
"Wiki Mitarbeiter": final_wiki_data.get('mitarbeiter', 'k.A.'), # Spalte X (kann von Parent sein)
|
||||
"Parent Account Name": parent_account_name_d # WICHTIG: Spalte D übergeben
|
||||
}
|
||||
plausi_results = self._check_financial_plausibility(plausi_input_data)
|
||||
plausi_results = self._check_financial_plausibility(plausi_input_data) # Diese Methode muss D berücksichtigen
|
||||
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Umsatz"] + 1)}{row_num_in_sheet}', 'values': [[plausi_results.get("plaus_umsatz_flag", "ERR_FLAG")]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Mitarbeiter"] + 1)}{row_num_in_sheet}', 'values': [[plausi_results.get("plaus_ma_flag", "ERR_FLAG")]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Umsatz/MA Ratio"] + 1)}{row_num_in_sheet}', 'values': [[plausi_results.get("plaus_ratio_flag", "ERR_FLAG")]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Abweichung Umsatz CRM/Wiki"] + 1)}{row_num_in_sheet}', 'values': [[plausi_results.get("abweichung_umsatz_flag", "ERR_FLAG")]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Abweichung MA CRM/Wiki"] + 1)}{row_num_in_sheet}', 'values': [[plausi_results.get("abweichung_ma_flag", "ERR_FLAG")]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Abweichung Umsatz CRM/Wiki"] + 1)}{row_num_in_sheet}', 'values': [[plausi_results.get("abweichung_umsatz_flag", "ERR_FLAG")]]}) # BJ
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Abweichung MA CRM/Wiki"] + 1)}{row_num_in_sheet}', 'values': [[plausi_results.get("abweichung_ma_flag", "ERR_FLAG")]]}) # BK
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Begründung"] + 1)}{row_num_in_sheet}', 'values': [[plausi_results.get("plausi_begruendung_final", "Fehler Begr.")]]})
|
||||
|
||||
plausi_check_erfolgreich_durchgefuehrt = True # Markieren, dass der Check zumindest versucht wurde
|
||||
except Exception as e_plausi_in_single_row_chat:
|
||||
self.logger.error(f"FEHLER bei Plausibilitäts-Checks in _process_single_row (Chat-Block) für Zeile {row_num_in_sheet}: {e_plausi_in_single_row_chat}")
|
||||
# ... (Fehler-Flags für Plausi-Spalten setzen) ...
|
||||
|
||||
except Exception as e_plausi_in_single_row:
|
||||
self.logger.error(f"FEHLER bei Plausibilitäts-Checks in _process_single_row für Zeile {row_num_in_sheet}: {e_plausi_in_single_row}")
|
||||
# Fehler-Flags für Plausi-Spalten setzen
|
||||
error_val_plausi = [['FEHLER_PLAUSI_CALL']]
|
||||
for key_flag_plausi in ["Plausibilität Umsatz", "Plausibilität Mitarbeiter", "Plausibilität Umsatz/MA Ratio", "Abweichung Umsatz CRM/Wiki", "Abweichung MA CRM/Wiki"]:
|
||||
if COLUMN_MAP.get(key_flag_plausi) is not None: # Sicherstellen, dass der Key existiert
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP[key_flag_plausi] + 1)}{row_num_in_sheet}', 'values': error_val_plausi})
|
||||
if COLUMN_MAP.get("Plausibilität Begründung") is not None:
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Begründung"] + 1)}{row_num_in_sheet}', 'values': [[f"Systemfehler Plausi-Call: {str(e_plausi_in_single_row)[:50]}"]]})
|
||||
|
||||
# Plausi-Timestamp setzen, wenn der Plausi-Block (3f) erreicht wurde
|
||||
# (entweder erfolgreich oder mit Fehler im try-Block)
|
||||
if COLUMN_MAP.get("Plausibilität Prüfdatum") is not None:
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Prüfdatum"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]})
|
||||
else:
|
||||
self.logger.error("FEHLER: Schlüssel 'Plausibilität Prüfdatum' nicht in COLUMN_MAP. Kann Timestamp nicht setzen.")
|
||||
|
||||
|
||||
# Setze den "Timestamp letzte Prüfung" (BO - für ChatGPT-Evaluationen), da dieser Block lief
|
||||
if COLUMN_MAP.get("Timestamp letzte Prüfung") is not None:
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Timestamp letzte Prüfung"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]})
|
||||
else:
|
||||
self.logger.error("FEHLER: Schlüssel 'Timestamp letzte Prüfung' nicht in COLUMN_MAP. Kann Haupt-Timestamp nicht setzen.")
|
||||
|
||||
# else if run_chat_step (aber nicht processing_needed):
|
||||
# self.logger.debug(f"Zeile {row_num_in_sheet}: Ueberspringe CHATGPT Evaluationen und Plausi-Checks (Timestamp BI gesetzt, Wiki nicht aktualisiert und kein Re-Eval).")
|
||||
|
||||
# else if run_chat_step:
|
||||
# Die Chat-Schritte waren angefordert, aber nicht noetig basierend auf Status/Re-Eval/Wiki-Update.
|
||||
# Die lokalen Variablen final_wiki_data und website_summary behalten ihre initialen Werte (current_...).
|
||||
# chat_eval_just_ran bleibt False.
|
||||
# self.logger.debug(f"Zeile {row_num_in_sheet}: Ueberspringe CHATGPT Evaluationen (AO vorhanden, Wiki nicht aktualisiert und kein Re-Eval).") # Zu viel Laerm im Debug
|
||||
# Plausi-Timestamp (BM) und Haupt-Timestamp (BN) setzen
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Prüfdatum"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]})
|
||||
updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Timestamp letzte Prüfung"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]})
|
||||
|
||||
|
||||
# --- Der Code fuer den naechsten Verarbeitungsschritt (ML Prediction) folgt im naechsten Block ---
|
||||
|
||||
Reference in New Issue
Block a user