diff --git a/brancheneinstufung.py b/brancheneinstufung.py index 4cdd545d..48360b12 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -4667,13 +4667,12 @@ class DataProcessor: # --- 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 + wiki_processing_needed_based_on_status = self._needs_wiki_processing(row_data, force_reeval) if run_wiki_step and wiki_processing_needed_based_on_status: any_processing_done = True - # ---- KORREKTE VARIABLENERSTELLUNG UND VERWENDUNG FÜR LOGGING ---- - grund_message_parts_wiki_list = [] # Liste für die Teile der Nachricht + grund_message_parts_wiki_list = [] if force_reeval: grund_message_parts_wiki_list.append('Re-Eval') if not self._get_cell_value_safe(row_data, "Wikipedia Timestamp").strip(): @@ -4681,170 +4680,156 @@ class DataProcessor: if self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip().upper() == "X (URL COPIED)": grund_message_parts_wiki_list.append("AC (Chat Wiki Konsistenzpruefung)='X (URL COPIED)'") - # Baue die Log-Nachricht zusammen - grund_message_wiki_str = ", ".join(filter(None, grund_message_parts_wiki_list)) # Variable umbenannt zu _str + grund_message_wiki_str = ", ".join(filter(None, grund_message_parts_wiki_list)) if not grund_message_wiki_str: - grund_message_wiki_str = "Bedingung für Wiki-Bearbeitung erfüllt (Details im Debug)" + grund_message_wiki_str = "Bedingung für Wiki-Bearbeitung erfüllt (siehe Debug)" - # Verwende die korrekte Variable `grund_message_wiki_str` self.logger.info(f"Zeile {row_num_in_sheet}: Fuehre WIKI Schritte aus (Grund: {grund_message_wiki_str})...") - # ---- ENDE KORREKTUR ---- - current_wiki_url_in_sheet_for_daughter = self._get_cell_value_safe(row_data, "Wiki URL").strip() - system_suggested_parent_name_o = self._get_cell_value_safe(row_data, "System Vorschlag Parent Account").strip() - # parent_account_name_d wird bereits weiter oben in der Funktion gelesen + current_wiki_url_r = self._get_cell_value_safe(row_data, "Wiki URL").strip() + system_suggested_parent_o = self._get_cell_value_safe(row_data, "System Vorschlag Parent Account").strip() + # parent_account_name_d ist bereits oben in _process_single_row gelesen worden - url_to_validate_and_extract = None - name_for_wiki_article_validation = company_name - source_of_wiki_data_origin_log_msg = "Tochter (Standard)" + url_for_extraction = None # Wird die URL sein, von der wir versuchen zu extrahieren + # name_for_validation_for_log = company_name # Für Logging, welcher Name für Validierung genutzt wurde + source_of_wiki_data_origin_log_msg = "Tochter (Initial)" additional_info_for_af_col = "" - artikel_ist_valide_fuer_extraktion = False - - # --- START: LOGIK FÜR PARENT-ACCOUNT (O oder D) UND WIKI-URL DER TOCHTER (R) --- - # (Hier folgt der Codeblock, den wir für die Parent-Wiki-Suche und Validierung entwickelt haben) - # Dieser Block sollte `url_to_validate_and_extract`, `name_for_wiki_article_validation`, - # `source_of_wiki_data_origin_log_msg` und `artikel_ist_valide_fuer_extraktion` setzen. - # Wichtig: Er muss `serp_wikipedia_lookup` verwenden, wie besprochen. - # Beispielhafte Struktur (basierend auf unserem vereinfachten Ansatz): - # 1. Prüfung Parent D (manuell/CRM) - if (not current_wiki_url_in_sheet_for_daughter or current_wiki_url_in_sheet_for_daughter.lower() == 'k.a.') and \ + # --- Logik zur Bestimmung der zu verwendenden Wiki-URL --- + # Priorität 1: Manuell gepflegter Parent in D, wenn Tochter-Wiki R leer ist + if (not current_wiki_url_r or current_wiki_url_r.lower() == 'k.a.') and \ (parent_account_name_d and parent_account_name_d.lower() != 'k.a.'): - self.logger.info(f" Zeile {row_num_in_sheet}: R leer, D ('{parent_account_name_d}') gesetzt. Suche Wiki für Parent D.") + self.logger.info(f" Zeile {row_num_in_sheet}: R leer, D ('{parent_account_name_d}') gesetzt. Suche Wiki für Parent D via SerpAPI.") try: potential_url = serp_wikipedia_lookup(parent_account_name_d, website=None) if potential_url and potential_url.lower() not in ["k.a.", "kein artikel gefunden"] and not potential_url.startswith("FEHLER"): - url_to_validate_and_extract = potential_url - name_for_wiki_article_validation = parent_account_name_d + url_for_extraction = potential_url source_of_wiki_data_origin_log_msg = f"Parent D ('{parent_account_name_d}')" - # Da wir dieser Quelle vertrauen, setzen wir Validierung für Extraktion direkt - artikel_ist_valide_fuer_extraktion = True - self.logger.info(f" -> Wiki-Artikel für Parent D '{parent_account_name_d}' gefunden und als valide angenommen: {url_to_validate_and_extract}") updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Wiki Konsistenzpruefung"] + 1)}{row_num_in_sheet}', 'values': [["INFO_PARENT_AUS_D"]]}) - additional_info_for_af_col = f"INFO: Wiki-Daten von Parent (aus D): {parent_account_name_d} direkt übernommen. " + additional_info_for_af_col = f"INFO: Wiki-URL von Parent (aus D): {parent_account_name_d} via SerpAPI. " else: - self.logger.warning(f" -> Kein Wiki-Artikel für Parent D '{parent_account_name_d}' gefunden.") + self.logger.warning(f" -> Kein Wiki-Artikel für Parent D '{parent_account_name_d}' gefunden.") + additional_info_for_af_col = f"WARN: Kein Wiki für Parent D '{parent_account_name_d}' gefunden. " + # Setze final_wiki_data hier nicht, da die Tochter-Suche noch folgen kann except Exception as e_d_lookup_re: self.logger.error(f"Fehler bei Wiki-Suche für Parent D '{parent_account_name_d}': {e_d_lookup_re}") + additional_info_for_af_col = f"ERR: Suche Parent D '{parent_account_name_d}' fehlgeschlagen. " - # 2. Prüfung Parent O (Systemvorschlag), wenn D nicht erfolgreich oder leer war - if (url_to_validate_and_extract is None) and \ - (not current_wiki_url_in_sheet_for_daughter or current_wiki_url_in_sheet_for_daughter.lower() == 'k.a.') and \ + # Priorität 2: Systemvorschlag Parent O, wenn R leer UND D nicht erfolgreich war/leer ist + if (url_for_extraction is None) and \ + (not current_wiki_url_r or current_wiki_url_r.lower() == 'k.a.') and \ (system_suggested_parent_name_o and system_suggested_parent_name_o.lower() != 'k.a.'): - self.logger.info(f" Zeile {row_num_in_sheet}: R leer, D nicht genutzt/erfolglos, O ('{system_suggested_parent_name_o}') gesetzt. Suche Wiki für Parent O.") + self.logger.info(f" Zeile {row_num_in_sheet}: R leer, D nicht genutzt/erfolglos. O ('{system_suggested_parent_name_o}') gesetzt. Suche Wiki für Parent O via SerpAPI.") try: potential_url = serp_wikipedia_lookup(system_suggested_parent_name_o, website=None) if potential_url and potential_url.lower() not in ["k.a.", "kein artikel gefunden"] and not potential_url.startswith("FEHLER"): - url_to_validate_and_extract = potential_url - name_for_wiki_article_validation = system_suggested_parent_name_o + url_for_extraction = potential_url source_of_wiki_data_origin_log_msg = f"Parent O ('{system_suggested_parent_name_o}')" - # Hier validieren wir den gefundenen Artikel gegen den Namen aus O - page_obj_o = wikipedia.page(url=url_to_validate_and_extract, auto_suggest=False, preload=False) # oder title=, je nachdem was serp_lookup liefert - if self.wiki_scraper._validate_article(page_obj_o, name_for_wiki_article_validation, website_url, is_parent_context=True): - artikel_ist_valide_fuer_extraktion = True - url_to_validate_and_extract = page_obj_o.url # Kanonische URL - self.logger.info(f" -> Wiki-Artikel für Parent O '{system_suggested_parent_name_o}' gefunden und validiert: {url_to_validate_and_extract}") - updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Wiki Konsistenzpruefung"] + 1)}{row_num_in_sheet}', 'values': [["INFO_PARENT_AUS_O"]]}) - additional_info_for_af_col = f"INFO: Wiki-Daten von Parent (aus O): {system_suggested_parent_name_o} übernommen. " - else: - self.logger.warning(f" -> Gefundener Wiki-Artikel für Parent O '{system_suggested_parent_name_o}' ({url_to_validate_and_extract}) nicht validiert.") - additional_info_for_af_col = f"WARNUNG: Artikel für Parent O '{url_to_validate_and_extract}' nicht valide. " - final_wiki_data['url'] = url_to_validate_and_extract # URL speichern, aber nicht extrahieren - # ... Rest auf k.A. setzen ... - wiki_data_updated_in_this_run = True # Da URL in R geschrieben wird - url_to_validate_and_extract = None # Verhindert Extraktion + updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Wiki Konsistenzpruefung"] + 1)}{row_num_in_sheet}', 'values': [["INFO_PARENT_AUS_O"]]}) + additional_info_for_af_col += f"INFO: Wiki-URL von Parent (aus O): {system_suggested_parent_name_o} via SerpAPI. " else: self.logger.warning(f" -> Kein Wiki-Artikel für Parent O '{system_suggested_parent_name_o}' gefunden.") + additional_info_for_af_col += f"WARN: Kein Wiki für Parent O '{system_suggested_parent_name_o}' gefunden. " except Exception as e_o_lookup_re: - self.logger.error(f"Fehler bei Wiki-Suche/Validierung für Parent O '{system_suggested_parent_name_o}': {e_o_lookup_re}") - url_to_validate_and_extract = f"Fehler Suche Parent O: {str(e_o_lookup_re)[:50]}" + self.logger.error(f"Fehler bei Wiki-Suche für Parent O '{system_suggested_parent_name_o}': {e_o_lookup_re}") + additional_info_for_af_col += f"ERR: Suche Parent O '{system_suggested_parent_name_o}' fehlgeschlagen. " - - # 3. Standard Tochter-Wiki-Logik (wenn url_to_validate_and_extract immer noch None ist) - if url_to_validate_and_extract is None or url_to_validate_and_extract.startswith("Fehler"): - self.logger.debug(f" Zeile {row_num_in_sheet}: Keine gültige Parent-Wiki-URL. Standard Tochter-Wiki-Logik...") - # ... (Ihre bestehende Logik, um url_to_validate_and_extract für die Tochter zu setzen) - # Diese Logik muss name_for_wiki_article_validation = company_name und - # source_of_wiki_data_origin = "Tochter (...)" setzen. - # Und am Ende muss artikel_ist_valide_fuer_extraktion gesetzt werden. - # Beispiel (sehr vereinfacht): - if current_wiki_url_in_sheet_for_daughter and current_wiki_url_in_sheet_for_daughter.lower() not in ['k.a.'] and not current_wiki_url_in_sheet_for_daughter.startswith("Fehler"): - url_to_validate_and_extract = current_wiki_url_in_sheet_for_daughter - # ... Validierung für Tochter ... - else: # Neue Suche für Tochter + # Priorität 3: Standard Tochter-Wiki-Logik (wenn keine Parent-URL ermittelt wurde oder R schon gefüllt war) + if url_for_extraction is None or (current_wiki_url_r and current_wiki_url_r.lower() != 'k.a.' and not current_wiki_url_r.startswith("FEHLER")): + # Wenn R schon eine URL hat (und keine Parent-URL gefunden wurde), diese verwenden. + # Oder wenn R leer war und Parent-Suchen fehlschlugen, dann neu für Tochter suchen. + if current_wiki_url_r and current_wiki_url_r.lower() not in ['k.a.'] and not current_wiki_url_r.startswith("FEHLER") and \ + not (force_reeval or self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip().upper() == "X (URL COPIED)"): + url_for_extraction = current_wiki_url_r + source_of_wiki_data_origin_log_msg = "Tochter (aus R, unverändert)" + self.logger.info(f" Zeile {row_num_in_sheet}: Nutze bestehende Tochter-URL aus R: {url_for_extraction}") + else: # R ist leer oder Re-Eval/Reparse -> Suche für Tochter + self.logger.info(f" Zeile {row_num_in_sheet}: Suche Wiki-Artikel für Tochter '{company_name}'...") try: page_obj_tochter = self.wiki_scraper.search_company_article(company_name, website_url) if page_obj_tochter: - url_to_validate_and_extract = page_obj_tochter.url - # Validierung hier: - if self.wiki_scraper._validate_article(page_obj_tochter, company_name, website_url, is_parent_context=False): - artikel_ist_valide_fuer_extraktion = True - source_of_wiki_data_origin_log_msg = "Tochter (Suche & Valide)" - else: - # ... Behandlung wenn Tochter-Artikel nicht valide ... - pass + url_for_extraction = page_obj_tochter.url + source_of_wiki_data_origin_log_msg = "Tochter (Suche erfolgreich)" + self.logger.info(f" -> Suche für Tochter '{company_name}' erfolgreich, URL: {url_for_extraction}") else: - url_to_validate_and_extract = "Kein Artikel gefunden" - except Exception as e_tochter_suche_re: - url_to_validate_and_extract = f"Fehler Suche Tochter: {str(e_tochter_suche_re)[:50]}" - - - # --- DATENEXTRAKTION (nur wenn artikel_ist_valide_fuer_extraktion True ist) --- - if artikel_ist_valide_fuer_extraktion and url_to_validate_and_extract and \ - not url_to_validate_and_extract.lower() in ["k.a.", "kein artikel gefunden"] and \ - not url_to_validate_and_extract.startswith("FEHLER"): - self.logger.debug(f" -> Extrahiere Wiki-Daten von validierter URL ({source_of_wiki_data_origin_log_msg}): {url_to_validate_and_extract[:100]}...") + url_for_extraction = "Kein Artikel gefunden" + self.logger.warning(f" -> Kein Wiki-Artikel für Tochter '{company_name}' gefunden.") + except Exception as e_tochter_suche_psr: + self.logger.error(f"Fehler bei Wiki-Suche für Tochter '{company_name}': {e_tochter_suche_psr}") + url_for_extraction = f"Fehler Suche Tochter: {str(e_tochter_suche_psr)[:50]}" + + # --- DATENEXTRAKTION --- + if url_for_extraction and isinstance(url_for_extraction, str) and \ + url_for_extraction.lower() not in ["k.a.", "kein artikel gefunden"] and \ + not url_for_extraction.startswith("FEHLER"): + self.logger.info(f" -> Extrahiere Wiki-Daten von URL ({source_of_wiki_data_origin_log_msg}): {url_for_extraction[:100]}...") try: - extracted_data = self.wiki_scraper.extract_company_data(url_to_validate_and_extract) - # ... (Rest der Extraktionslogik und Updates für final_wiki_data) ... - if extracted_data and extracted_data.get('url') != 'k.A.': - final_wiki_data = extracted_data + # Für Parent-Artikel machen wir keine weitere explizite Validierung hier, + # wir vertrauen dem serp_wikipedia_lookup. + # Für Tochter-Artikel hat search_company_article bereits validiert. + extracted_data = self.wiki_scraper.extract_company_data(url_for_extraction) + + if extracted_data and isinstance(extracted_data, dict) and extracted_data.get('url') != 'k.A.': + final_wiki_data = extracted_data wiki_data_updated_in_this_run = True - # ... (Logik für AC-Status Reset, wenn Tochter-URL geändert oder Re-Eval) ... - except Exception as e_extract_final: - self.logger.error(f"FEHLER bei Wikipedia Datenextraktion von {url_to_validate_and_extract[:100]}...: {e_extract_final}") - # ... (Fehlerbehandlung für final_wiki_data) ... - elif url_to_validate_and_extract: # War "Kein Artikel..." oder "Fehler..." oder nicht valide - final_wiki_data['url'] = url_to_validate_and_extract + self.logger.info(f" -> Datenextraktion von {url_for_extraction[:100]}... erfolgreich.") + + # AC und abhängige Spalten zurücksetzen, wenn es sich um eine Tochter-URL handelt + # und diese neu ist oder reevaluiert wurde. + # Wenn es eine Parent-URL war, wurde AC schon oben gesetzt. + current_ac_val = self._get_cell_value_safe(row_data, "Chat Wiki Konsistenzpruefung").strip() + if not source_of_wiki_data_origin_log_msg.startswith("Parent") and \ + (force_reeval or current_wiki_url_r != url_for_extraction or current_ac_val.upper() == "X (URL COPIED)"): + self.logger.info(f" -> Setze AC auf '?' und leere AA, AD, AE für Tochter-Wiki-Update.") + 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': [['']]}) + 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': [['']]}) + else: + self.logger.error(f" -> Fehler bei Datenextraktion von {url_for_extraction[:100]} (Extraktion leer/ungültig).") + final_wiki_data['url'] = url_for_extraction + 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)' + wiki_data_updated_in_this_run = True + except Exception as e_wiki_extract_final_psr: + self.logger.error(f"FEHLER bei Wikipedia Datenextraktion von {url_for_extraction[:100]}...: {e_wiki_extract_final_psr}") + final_wiki_data['url'] = url_for_extraction # Zumindest die (ggf. fehlerhafte) URL speichern + 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 Extr.)' + wiki_data_updated_in_this_run = True + + elif url_for_extraction: # War "Kein Artikel..." oder "Fehler..." + self.logger.info(f" -> Keine valide Wiki-URL zur Extraktion vorhanden: '{url_for_extraction}'. Setze Wiki-Felder auf k.A.") + final_wiki_data['url'] = url_for_extraction 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 - + wiki_data_updated_in_this_run = True # Es gab einen Versuch/Änderung + # Updates für R-Y und Z (immer ausführen, wenn wiki_data_updated_in_this_run) if wiki_data_updated_in_this_run: - # ... (Schreiben von final_wiki_data und Timestamps Z, AB, AF und Reset von AC, AA, AD, AE) ... 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.')]]}) - # usw. für R-Y + 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.')]]}) + updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Wikipedia Timestamp"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]}) # Z + + if additional_info_for_af_col: + current_af_val = self._get_cell_value_safe(row_data, "Begründung bei Abweichung").strip() + 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]]}) + + # SerpAPI Timestamp (AB) setzen, wenn eine SerpAPI-Suche für Parent D oder O durchgeführt wurde + if source_of_wiki_data_origin_log_msg.startswith("Parent D") or source_of_wiki_data_origin_log_msg.startswith("Parent O"): + updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["SerpAPI Wiki Search Timestamp"] + 1)}{row_num_in_sheet}', 'values': [[now_timestamp]]}) + - # --- 2b. System Vorschlag Parent Account (O, P, Q) --- - # (Dieser Block bleibt wie im vorherigen Vorschlag, ruft Ihre _suggest_parent_account_openai_task über eine Batch-Methode - # oder, falls Sie es direkt in _process_single_row wollen, eine adaptierte Version davon auf) - # Wichtig: Wenn Sie Parent-Vorschläge *innerhalb* des Wiki-Schritts von _process_single_row machen wollen, - # dann muss die Logik für den Aufruf von _suggest_parent_account_openai_task hier platziert werden. - # Mein vorheriger Vorschlag war, dies in einem separaten Batch-Modus zu machen. - # Für _process_single_row, wenn wir es hier machen wollen würden (nicht empfohlen für viele Zeilen): - - # if 'parent_suggest' in steps_to_run: # Wenn ein spezifischer Schritt dafür da ist - # 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() - # needs_parent_suggestion_in_psr = (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_in_psr = True - # - # if needs_parent_suggestion_in_psr: - # self.logger.info(f" Zeile {row_num_in_sheet}: Versuche Parent-Account vorzuschlagen (via OpenAI Task)...") - # task_data_for_o = { # Daten für _suggest_parent_account_openai_task zusammenstellen - # "row_num": row_num_in_sheet, "crm_name": company_name, ... - # } - # # Direkter, synchroner Aufruf hier (nicht ideal für Performance) - # # openai_semaphore_dummy = threading.Semaphore(1) # Dummy-Semaphore für direkten Aufruf - # # parent_suggestion_result = self._suggest_parent_account_openai_task(task_data_for_o, openai_semaphore_dummy) - # # ... (Ergebnis verarbeiten und O, P, Q updaten) ... - # # Besser: Dies in einem eigenen Batch-Modus belassen (process_parent_suggestion_batch) - # --- Ende des Wikipedia-Blocks --- # Der nächste Block wäre ChatGPT-Evaluationen - # ====================================================================== # --- 3. ChatGPT Evaluationen (Branch, FSM, Emp, Umsatz Schaetzungen etc.) --- run_chat_step = 'chat' in steps_to_run @@ -8372,22 +8357,19 @@ class DataProcessor: processed_rows_count += 1 # Batch-Update auslösen, wenn Limit erreicht - if processed_rows_count % update_batch_limit_config == 0 and all_sheet_updates: - self.logger.info(f"Sende Plausi-Check & Konsolidierungs Batch-Update ({len(all_sheet_updates) / 9:.0f} Zeilen)...") # Ca. 9 Updates pro Zeile - success = self.sheet_handler.batch_update_cells(all_sheet_updates) - if success: - self.logger.info(f" Sheet-Update für Plausi-Batch erfolgreich.") - all_sheet_updates = [] # Liste leeren - time.sleep(0.5) # Kurze Pause - - # Letzten Batch senden, falls noch Updates vorhanden sind - if all_sheet_updates: - self.logger.info(f"Sende finalen Plausi-Check & Konsolidierungs Batch-Update ({len(all_sheet_updates) / 9:.0f} Zeilen)...") - success = self.sheet_handler.batch_update_cells(all_sheet_updates) - if success: - self.logger.info(f" Finales Sheet-Update für Plausi-Batch erfolgreich.") - - self.logger.info(f"Modus 'plausi_check_data' abgeschlossen. {processed_rows_count} Zeilen mit Konsolidierung und Plausi-Checks versehen.") + # --- 6. Batch Update fuer diese EINE Zeile --- + if updates: # 'updates' ist die Liste, die innerhalb von _process_single_row für die aktuelle Zeile gefüllt wurde + self.logger.info(f"Zeile {row_num_in_sheet}: Sende Batch-Update mit {len(updates)} Operationen für diese Zeile...") + success = self.sheet_handler.batch_update_cells(updates) + if not success: + self.logger.error(f"Zeile {row_num_in_sheet}: ENDGUELTIGER FEHLER beim Batch-Update nach Retries.") + else: + if not any_processing_done: # any_processing_done wurde am Anfang auf False gesetzt und bei jeder Aktion auf True + self.logger.debug(f"Zeile {row_num_in_sheet}: Keine Updates zum Schreiben (alle relevanten Schritte übersprungen oder nicht angefordert).") + + pause_duration = max(0.05, getattr(Config, 'RETRY_DELAY', 5) / 20.0) + time.sleep(pause_duration) + self.logger.info(f"--- Verarbeitung fuer Zeile {row_num_in_sheet} abgeschlossen ---") # ========================================================================== # === Batch Processing Methods (Parent Account Suggestion) ==============