From 654253e535be82d6d85b6f29887f494a7c727869 Mon Sep 17 00:00:00 2001 From: Floke Date: Wed, 16 Apr 2025 15:31:29 +0000 Subject: [PATCH] bugfix --- brancheneinstufung.py | 223 +++++++++++++++++++++--------------------- 1 file changed, 110 insertions(+), 113 deletions(-) diff --git a/brancheneinstufung.py b/brancheneinstufung.py index 6d4c9fafc..8836e2c2d 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -104,7 +104,7 @@ COLUMN_MAP = { "CRM Beschreibung": 5, # F "CRM Branche": 6, # G "CRM Beschreibung Branche extern": 7, # H - "CRM Anzahl Techniker": 8, # I - !! Wichtig für die Zielvariable !! + "CRM Anzahl Techniker": 8, # I "CRM Umsatz": 9, # J "CRM Anzahl Mitarbeiter": 10, # K "CRM Vorschlag Wiki URL": 11, # L @@ -117,7 +117,7 @@ COLUMN_MAP = { "Chat Wiki Konsistenzprüfung": 18, # S "Chat Begründung Wiki Inkonsistenz": 19, # T "Chat Vorschlag Wiki Artikel": 20, # U - "Begründung bei Abweichung": 21, # V (ungenutzt?) + "Begründung bei Abweichung": 21, # V "Chat Vorschlag Branche": 22, # W "Chat Konsistenz Branche": 23, # X "Chat Begründung Abweichung Branche": 24, # Y @@ -126,7 +126,7 @@ COLUMN_MAP = { "Chat Schätzung Anzahl Mitarbeiter": 27, # AB "Chat Konsistenzprüfung Mitarbeiterzahl": 28, # AC "Chat Begründung Abweichung Mitarbeiterzahl": 29, # AD - "Chat Einschätzung Anzahl Servicetechniker": 30, # AE (War das nicht die Schätzung? Verwechselt mit AU?) + "Chat Einschätzung Anzahl Servicetechniker": 30, # AE "Chat Begründung Abweichung Anzahl Servicetechniker": 31, # AF "Chat Schätzung Umsatz": 32, # AG "Chat Begründung Abweichung Umsatz": 33, # AH @@ -135,17 +135,17 @@ COLUMN_MAP = { "Linked Management gefunden": 36, # AK "Linked Disponent gefunden": 37, # AL "Contact Search Timestamp": 38, # AM - "Wikipedia Timestamp": 39, # AN - "Timestamp letzte Prüfung": 40, # AO + "Wikipedia Timestamp": 39, # AN (Zeitpunkt der Datenextraktion) + "Timestamp letzte Prüfung": 40, # AO (Zeitpunkt der Branch-Einschätzung) "Version": 41, # AP "Tokens": 42, # AQ "Website Rohtext": 43, # AR "Website Zusammenfassung": 44, # AS - # --- NEUE SPALTEN --- "Website Scrape Timestamp": 45, # AT "Geschätzter Techniker Bucket": 46, # AU "Finaler Umsatz (Wiki>CRM)": 47,# AV - "Finaler Mitarbeiter (Wiki>CRM)": 48 # AW + "Finaler Mitarbeiter (Wiki>CRM)": 48, # AW + "Wiki Verif. Timestamp": 49 # AX (NEU) } # Hinweis: Index ist 0-basiert, Spaltenbuchstaben sind 1-basiert (A=1, AW=49) @@ -2012,27 +2012,25 @@ def _process_batch(sheet, batches, row_numbers): def process_verification_only(sheet_handler, start_row_index_in_sheet, end_row_index_in_sheet): """ - Batch-Prozess nur für Wikipedia-Verifizierung. - Lädt Daten neu, prüft für jede Zeile im Bereich, ob Timestamp AN bereits gesetzt ist, - und überspringt diese ggf. Setzt AN für bearbeitete Zeilen. + Batch-Prozess nur für Wikipedia-Verifizierung (Spalten S-Y). + Lädt Daten neu, prüft für jede Zeile im Bereich, ob Timestamp AX (Wiki Verif.) + bereits gesetzt ist, und überspringt diese ggf. Setzt AX für bearbeitete Zeilen. + AN wird hier *nicht* mehr gesetzt, das muss ggf. _process_single_row tun. """ debug_print(f"Starte Wikipedia-Verifizierungsmodus (Batch) für Zeilen {start_row_index_in_sheet} bis {end_row_index_in_sheet}...") - # --- NEU: Daten explizit neu laden --- if not sheet_handler.load_data(): debug_print("FEHLER beim Laden der Daten in process_verification_only.") return all_data = sheet_handler.get_all_data_with_headers() - # --- Ende Daten neu laden --- - if not all_data or len(all_data) <= 5: debug_print("FEHLER/WARNUNG: Keine Daten zum Verarbeiten in process_verification_only gefunden.") return - # Hole Index für AN Timestamp - timestamp_col_key = "Wikipedia Timestamp" + # Hole Index für AX Timestamp (Wiki Verif.) + timestamp_col_key = "Wiki Verif. Timestamp" # NEUER SCHLÜSSEL timestamp_col_index = COLUMN_MAP.get(timestamp_col_key) - ts_col_letter = sheet_handler._get_col_letter(timestamp_col_index + 1) if timestamp_col_index is not None else "AN_FEHLER" + ts_col_letter = sheet_handler._get_col_letter(timestamp_col_index + 1) if timestamp_col_index is not None else "AX_FEHLER" if timestamp_col_index is None: debug_print(f"FEHLER: Spaltenschlüssel '{timestamp_col_key}' nicht in COLUMN_MAP gefunden. Breche Wiki-Verifizierung ab.") @@ -2046,30 +2044,27 @@ def process_verification_only(sheet_handler, start_row_index_in_sheet, end_row_i for i in range(start_row_index_in_sheet, end_row_index_in_sheet + 1): row_index_in_list = i - 1 - if row_index_in_list >= len(all_data): - debug_print(f"Warnung (Wiki): Zeilenindex {row_index_in_list} außerhalb des Datenbereichs ({len(all_data)} Zeilen).") - continue - + if row_index_in_list >= len(all_data): continue row = all_data[row_index_in_list] - # --- Timestamp-Prüfung für jede Zeile (AN) --- - ts_value_an = "INDEX_FEHLER" - ts_an_is_set = False + # --- Timestamp-Prüfung für jede Zeile (AX) --- + ts_value_ax = "INDEX_FEHLER" + ts_ax_is_set = False if len(row) > timestamp_col_index: - ts_value_an = row[timestamp_col_index] - ts_an_is_set = bool(str(ts_value_an).strip()) - # Debug Log (kann reduziert werden) - log_debug = (i < start_row_index_in_sheet + 5 or i > end_row_index_in_sheet - 5 or i % 500 == 0) - if log_debug: - debug_print(f"Zeile {i} (Wiki Check): Prüfe Timestamp {ts_col_letter} (Index {timestamp_col_index}). Rohwert='{ts_value_an}', Strip='{str(ts_value_an).strip()}', Überspringen? -> {ts_an_is_set}") + ts_value_ax = row[timestamp_col_index] + ts_ax_is_set = bool(str(ts_value_ax).strip()) - if ts_an_is_set: + log_debug = (i < start_row_index_in_sheet + 5 or i > end_row_index_in_sheet - 5 or i % 500 == 0 or i in range(2122, 2132)) + if log_debug: + debug_print(f"Zeile {i} (Wiki Verif. Check): Prüfe Timestamp {ts_col_letter} (Index {timestamp_col_index}). Rohwert='{ts_value_ax}', Strip='{str(ts_value_ax).strip()}', Überspringen? -> {ts_ax_is_set}") + + if ts_ax_is_set: skipped_count += 1 continue # --- Ende Timestamp-Prüfung --- - # (Restliche Logik zum Erstellen von entry_text) - company_name = row[COLUMN_MAP.get("CRM Name", 1)] if len(row) > COLUMN_MAP.get("CRM Name", 1) else '' # Füge Fallback hinzu + # Nur wenn AX leer ist, wird die Zeile für den Batch vorbereitet + company_name = row[COLUMN_MAP.get("CRM Name", 1)] if len(row) > COLUMN_MAP.get("CRM Name", 1) else '' crm_desc = row[COLUMN_MAP.get("CRM Beschreibung", 5)] if len(row) > COLUMN_MAP.get("CRM Beschreibung", 5) else '' wiki_url_idx = COLUMN_MAP.get("Wiki URL") wiki_url = row[wiki_url_idx] if wiki_url_idx is not None and len(row) > wiki_url_idx and row[wiki_url_idx].strip() not in ['', 'k.A.'] else 'k.A.' @@ -2096,7 +2091,7 @@ def process_verification_only(sheet_handler, start_row_index_in_sheet, end_row_i # Rufe _process_batch auf (schreibt S-Y) _process_batch(sheet_handler.sheet, current_batch, current_row_numbers) - # Setze den AN Timestamp für die bearbeiteten Zeilen + # Setze den AX Timestamp für die bearbeiteten Zeilen wiki_ts_updates = [] current_wiki_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") for row_num in current_row_numbers: @@ -2105,9 +2100,9 @@ def process_verification_only(sheet_handler, start_row_index_in_sheet, end_row_i if wiki_ts_updates: success_ts = sheet_handler.batch_update_cells(wiki_ts_updates) if success_ts: - debug_print(f"Wiki-Timestamp {ts_col_letter} für Batch {current_row_numbers[0]}-{current_row_numbers[-1]} gesetzt.") + debug_print(f"Wiki Verif. Timestamp {ts_col_letter} für Batch {current_row_numbers[0]}-{current_row_numbers[-1]} gesetzt.") else: - debug_print(f"FEHLER beim Setzen des Wiki-Timestamps {ts_col_letter} für Batch.") + debug_print(f"FEHLER beim Setzen des Wiki Verif. Timestamps {ts_col_letter} für Batch.") time.sleep(Config.RETRY_DELAY) @@ -2213,6 +2208,7 @@ def _process_batch(sheet, batches, row_numbers): # Komplette Funktion process_website_batch (prüft jetzt Timestamp AT mit erzwungenem Debugging) # Komplette Funktion process_website_batch (mit Vereinfachung und explizitem Skip-Log) +# Komplette Funktion process_website_batch (MIT Korrektur und Prüfung auf AT) def process_website_batch(sheet_handler, start_row_index_in_sheet, end_row_index_in_sheet): """ Batch-Prozess für Website-Scraping. Lädt Daten neu, prüft für jede Zeile @@ -2252,10 +2248,7 @@ def process_website_batch(sheet_handler, start_row_index_in_sheet, end_row_index for i in range(start_row_index_in_sheet, end_row_index_in_sheet + 1): row_index_in_list = i - 1 - if row_index_in_list >= len(all_data): - debug_print(f"Warnung (Website): Zeilenindex {row_index_in_list} außerhalb des Datenbereichs ({len(all_data)} Zeilen).") - continue - + if row_index_in_list >= len(all_data): continue row = all_data[row_index_in_list] # --- Timestamp-Prüfung für jede Zeile (AT) --- @@ -2266,25 +2259,23 @@ def process_website_batch(sheet_handler, start_row_index_in_sheet, end_row_index if str(ts_value_at).strip(): should_skip = True - # Debug Log log_debug = (i < start_row_index_in_sheet + 5 or i > end_row_index_in_sheet - 5 or i % 500 == 0 or i in range(2122, 2132)) if log_debug: debug_print(f"Zeile {i} (Website Check): Prüfe Timestamp {ts_col_letter}. Rohwert='{ts_value_at}'. Überspringen? -> {should_skip}") + # --- KORRIGIERTE if/else Struktur --- if should_skip: - # --- Explizites Logging VOR dem continue --- # debug_print(f"Zeile {i}: *** WIRD ÜBERSPRUNGEN (Timestamp AT vorhanden) ***") # Weniger Lärm skipped_count += 1 - continue # Springe zur nächsten Iteration + continue # Gehe zur nächsten Zeile in der for-Schleife else: - # --- NEU: Gesamter Verarbeitungsblock im ELSE --- + # Verarbeitung nur, wenn NICHT übersprungen wird debug_print(f"Zeile {i}: Timestamp AT nicht vorhanden oder leer. Verarbeitung wird gestartet.") website_url = row[website_col_idx] if len(row) > website_col_idx else "" if not website_url or website_url.strip().lower() == "k.a.": skipped_url_count += 1 - # Wichtig: Hier auch continue, sonst wird versucht zu updaten! - continue + continue # Gehe zur nächsten Zeile debug_print(f"Zeile {i}: Verarbeite Website {website_url}...") raw_text = get_website_raw(website_url) @@ -2308,11 +2299,12 @@ def process_website_batch(sheet_handler, start_row_index_in_sheet, end_row_index debug_print(f"FEHLER beim Schreiben der Website-Updates für Zeile {i}.") time.sleep(Config.RETRY_DELAY) - # --- Ende des ELSE-Blocks --- + # --- Ende der if/else Struktur --- debug_print(f"Website-Scraping (Batch) abgeschlossen. {processed_count} Websites gescraped, {skipped_count} Zeilen wg. Timestamp übersprungen, {skipped_url_count} Zeilen ohne URL übersprungen.") # Komplette Funktion process_branch_batch (prüft jetzt Timestamp AO mit erzwungenem Debugging) +# Komplette Funktion process_branch_batch (MIT Korrektur und Prüfung auf AO) def process_branch_batch(sheet_handler, start_row_index_in_sheet, end_row_index_in_sheet): """ Batch-Prozess für Brancheneinschätzung. Lädt Daten neu, prüft für jede Zeile @@ -2321,13 +2313,10 @@ def process_branch_batch(sheet_handler, start_row_index_in_sheet, end_row_index_ """ debug_print(f"Starte Brancheneinschätzung (Batch) für Zeilen {start_row_index_in_sheet} bis {end_row_index_in_sheet}...") - # --- NEU: Daten explizit neu laden --- if not sheet_handler.load_data(): debug_print("FEHLER beim Laden der Daten in process_branch_batch.") return all_data = sheet_handler.get_all_data_with_headers() - # --- Ende Daten neu laden --- - if not all_data or len(all_data) <= 5: debug_print("FEHLER/WARNUNG: Keine Daten zum Verarbeiten in process_branch_batch gefunden.") return @@ -2348,7 +2337,6 @@ def process_branch_batch(sheet_handler, start_row_index_in_sheet, end_row_index_ branch_x_idx = COLUMN_MAP.get("Chat Konsistenz Branche") branch_y_idx = COLUMN_MAP.get("Chat Begründung Abweichung Branche") - required_indices = [timestamp_col_index, branche_crm_idx, beschreibung_idx, branche_wiki_idx, kategorien_wiki_idx, summary_web_idx, version_col_index, branch_w_idx, branch_x_idx, branch_y_idx] @@ -2380,48 +2368,57 @@ def process_branch_batch(sheet_handler, start_row_index_in_sheet, end_row_index_ row = all_data[row_index_in_list] - # --- WIEDER AKTIVIERT: Timestamp-Prüfung für jede Zeile (AO) --- + # --- Timestamp-Prüfung für jede Zeile (AO) --- ts_value_ao = "INDEX_FEHLER" - ts_ao_is_set = False + should_skip = False if len(row) > timestamp_col_index: ts_value_ao = row[timestamp_col_index] - ts_ao_is_set = bool(str(ts_value_ao).strip()) - # Debug Log - log_debug = (i < start_row_index_in_sheet + 5 or i > end_row_index_in_sheet - 5 or i % 500 == 0) - if log_debug: - debug_print(f"Zeile {i} (Branch Check): Prüfe Timestamp {ts_col_letter} (Index {timestamp_col_index}). Rohwert='{ts_value_ao}', Strip='{str(ts_value_ao).strip()}', Überspringen? -> {ts_ao_is_set}") + if str(ts_value_ao).strip(): + should_skip = True - if ts_ao_is_set: + # Debug Log + log_debug = (i < start_row_index_in_sheet + 5 or i > end_row_index_in_sheet - 5 or i % 500 == 0 or i in range(2122, 2132)) + if log_debug: + debug_print(f"Zeile {i} (Branch Check): Prüfe Timestamp {ts_col_letter}. Rohwert='{ts_value_ao}'. Überspringen? -> {should_skip}") + + # --- KORRIGIERTE if/else Struktur --- + if should_skip: + # debug_print(f"Zeile {i}: *** WIRD ÜBERSPRUNGEN (Timestamp AO vorhanden) ***") # Weniger Lärm skipped_count += 1 continue - # --- Ende Timestamp-Prüfung --- + else: + # Verarbeitung nur, wenn NICHT übersprungen wird + debug_print(f"Zeile {i}: Timestamp AO nicht vorhanden oder leer. Verarbeitung wird gestartet.") - # (Restliche Logik zum Datenholen, Bewerten und Updaten) - crm_branche = row[branche_crm_idx] if len(row) > branche_crm_idx else "" - # ... (andere Daten holen) ... - website_summary = row[summary_web_idx] if len(row) > summary_web_idx else "" + # (Restliche Logik zum Datenholen, Bewerten und Updaten) + crm_branche = row[branche_crm_idx] if len(row) > branche_crm_idx else "" + beschreibung = row[beschreibung_idx] if len(row) > beschreibung_idx else "" + wiki_branche = row[branche_wiki_idx] if len(row) > branche_wiki_idx else "" + wiki_kategorien = row[kategorien_wiki_idx] if len(row) > kategorien_wiki_idx else "" + website_summary = row[summary_web_idx] if len(row) > summary_web_idx else "" - result = evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kategorien, website_summary) - processed_count += 1 + result = evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kategorien, website_summary) + processed_count += 1 - updates = [] - current_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - current_version = Config.VERSION + updates = [] + current_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + current_version = Config.VERSION - updates.append({'range': f'{branch_w_letter}{i}', 'values': [[result.get("branch", "Fehler")]]}) - updates.append({'range': f'{branch_x_letter}{i}', 'values': [[result.get("consistency", "Fehler")]]}) - updates.append({'range': f'{branch_y_letter}{i}', 'values': [[result.get("justification", "Fehler")]]}) - updates.append({'range': f'{ts_col_letter}{i}', 'values': [[current_timestamp]]}) # AO Timestamp - updates.append({'range': f'{version_col_letter}{i}', 'values': [[current_version]]}) # AP Version + updates.append({'range': f'{branch_w_letter}{i}', 'values': [[result.get("branch", "Fehler")]]}) + updates.append({'range': f'{branch_x_letter}{i}', 'values': [[result.get("consistency", "Fehler")]]}) + updates.append({'range': f'{branch_y_letter}{i}', 'values': [[result.get("justification", "Fehler")]]}) + updates.append({'range': f'{ts_col_letter}{i}', 'values': [[current_timestamp]]}) # AO Timestamp + updates.append({'range': f'{version_col_letter}{i}', 'values': [[current_version]]}) # AP Version - if updates: - success = sheet_handler.batch_update_cells(updates) - if success: - debug_print(f"Zeile {i}: Branch-Einschätzung erfolgreich aktualisiert.") - else: - debug_print(f"FEHLER beim Schreiben der Branch-Updates für Zeile {i}.") + if updates: + success = sheet_handler.batch_update_cells(updates) + if success: + debug_print(f"Zeile {i}: Branch-Einschätzung erfolgreich aktualisiert.") + else: + debug_print(f"FEHLER beim Schreiben der Branch-Updates für Zeile {i}.") - time.sleep(Config.RETRY_DELAY) + time.sleep(Config.RETRY_DELAY) + # --- Ende der if/else Struktur --- debug_print(f"Brancheneinschätzung (Batch) abgeschlossen. {processed_count} Zeilen eingeschätzt, {skipped_count} Zeilen wg. Timestamp übersprungen.") @@ -2938,56 +2935,56 @@ def process_contact_research(sheet_handler): # Diese Funktion ist bereits im Code vorhanden (Zeile ~1230 in der vorherigen Version) # Sie bleibt unverändert: def alignment_demo(sheet): - """Schreibt die Header-Struktur (Zeilen 1-5, jetzt bis Spalte AW) ins angegebene Sheet.""" + """Schreibt die Header-Struktur (Zeilen 1-5, jetzt bis Spalte AX) ins angegebene Sheet.""" new_headers = [ [ # Spaltenname (Zeile 1) "ReEval Flag", "CRM Name", "CRM Kurzform", "CRM Website", "CRM Ort", "CRM Beschreibung", "CRM Branche", "CRM Beschreibung Branche extern", "CRM Anzahl Techniker", "CRM Umsatz", "CRM Anzahl Mitarbeiter", "CRM Vorschlag Wiki URL", "Wiki URL", "Wiki Absatz", "Wiki Branche", "Wiki Umsatz", "Wiki Mitarbeiter", "Wiki Kategorien", "Chat Wiki Konsistenzprüfung", "Chat Begründung Wiki Inkonsistenz", "Chat Vorschlag Wiki Artikel", "Begründung bei Abweichung", "Chat Vorschlag Branche", "Chat Konsistenz Branche", "Chat Begründung Abweichung Branche", "Chat Prüfung FSM Relevanz", "Chat Begründung für FSM Relevanz", "Chat Schätzung Anzahl Mitarbeiter", "Chat Konsistenzprüfung Mitarbeiterzahl", "Chat Begründung Abweichung Mitarbeiterzahl", "Chat Einschätzung Anzahl Servicetechniker", "Chat Begründung Abweichung Anzahl Servicetechniker", "Chat Schätzung Umsatz", "Chat Begründung Abweichung Umsatz", "Linked Serviceleiter gefunden", "Linked It-Leiter gefunden", "Linked Management gefunden", "Linked Disponent gefunden", "Contact Search Timestamp", "Wikipedia Timestamp", "Timestamp letzte Prüfung", "Version", "Tokens", "Website Rohtext", "Website Zusammenfassung", - "Website Scrape Timestamp", # AT (NEU) - "Geschätzter Techniker Bucket", # AU (NEU) - "Finaler Umsatz (Wiki>CRM)", # AV (NEU) - "Finaler Mitarbeiter (Wiki>CRM)" # AW (NEU) + "Website Scrape Timestamp", # AT + "Geschätzter Techniker Bucket", # AU + "Finaler Umsatz (Wiki>CRM)", # AV + "Finaler Mitarbeiter (Wiki>CRM)", # AW + "Wiki Verif. Timestamp" # AX (NEU) ], [ # Quelle der Daten (Zeile 2) "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", "CRM", "Wikipediascraper", "Wikipediascraper", "Wikipediascraper", "Wikipediascraper", "Wikipediascraper", "Wikipediascraper", "Chat GPT API", "Chat GPT API", "Chat GPT API", "Chat GPT API", "Chat GPT API", "Chat GPT API", "Chat GPT API", "Chat GPT API", "Chat GPT API", "Chat GPT API", "Chat GPT API", "Chat GPT API", "Chat GPT API", "Chat GPT API", "Chat GPT API", "Chat GPT API", "LinkedIn (via SerpApi)", "LinkedIn (via SerpApi)", "LinkedIn (via SerpApi)", "LinkedIn (via SerpApi)", "System", "System", "System", "System", "System", "Web Scraper", "Chat GPT API", - "System", # AT (NEU) - Timestamp vom Scraping-Prozess - "ML Modell / Skript", # AU (NEU) - Ergebnis der Schätzung - "Skript (Wiki/CRM)", # AV (NEU) - Berechnet nach Priorität - "Skript (Wiki/CRM)" # AW (NEU) - Berechnet nach Priorität + "System", # AT + "ML Modell / Skript", # AU + "Skript (Wiki/CRM)", # AV + "Skript (Wiki/CRM)", # AW + "System" # AX (NEU) - Timestamp vom Wiki-Verifizierungs-Prozess ], [ # Feldkategorie (Zeile 3) "Prozess", "Firmenname", "Firmenname", "Website", "Ort", "Beschreibung (Text)", "Branche", "Branche", "Anzahl Servicetechniker", "Umsatz", "Anzahl Mitarbeiter", "Wikipedia Artikel URL", "Wikipedia Artikel", "Beschreibung (Text)", "Branche", "Umsatz", "Anzahl Mitarbeiter", "Kategorien (Text)", "Verifizierung", "Begründung bei Abweichung", "Wikipedia Artikel", "Wikipedia Artikel", "Branche", "Branche", "Branche", "FSM Relevanz", "FSM Relevanz", "Anzahl Mitarbeiter", "Anzahl Mitarbeiter", "Anzahl Mitarbeiter", "Anzahl Servicetechniker", "Anzahl Servicetechniker", "Umsatz", "Umsatz", "Kontakte zur Firma", "Kontakte zur Firma", "Kontakte zur Firma", "Kontakte zur Firma", "Timestamp", "Timestamp", "Timestamp", "Version des Skripts die verwendet wurde", "ChatGPT Tokens", "Website-Content", "Website Zusammenfassung", - "Timestamp", # AT (NEU) - "Anzahl Servicetechniker Bucket", # AU (NEU) - "Umsatz", # AV (NEU) - "Anzahl Mitarbeiter" # AW (NEU) + "Timestamp", # AT + "Anzahl Servicetechniker Bucket", # AU + "Umsatz", # AV + "Anzahl Mitarbeiter", # AW + "Timestamp" # AX (NEU) ], [ # Kurze Beschreibung (Zeile 4) - "Systemspalte, irrelevant für den Prompt. Wird zur manuellen Neuprüfung genutzt.", "Enthält den Firmennamen; Normalisierung erfolgt bei der Suche.", "Manuell gepflegte Kurzform, meist die ersten 2 Worte.", "Website des Unternehmens.", "Ort des Unternehmens.", "Kurze Beschreibung des Unternehmens.", "Aktuelle Branchenzuweisung gemäß Ziel-Branchenschema.", "Externe Branchenbeschreibung (z.B. von Dealfront).", "Recherchierte Anzahl Servicetechniker.", "Umsatz in Mio. € (CRM).", "Anzahl Mitarbeiter (CRM).", "Vorgeschlagene Wikipedia URL (Ausgangspunkt).", "Wikipedia URL (Ergebnis der Suche).", "Erster Absatz des Wikipedia-Artikels.", "Wikipedia-Branche – für den Branchenabgleich.", "Wikipedia-Umsatz – zur Validierung.", "Wikipedia-Mitarbeiterzahl – zur Validierung.", "Liste der Wikipedia-Kategorien.", "\"OK\" oder \"X\" – Ergebnis der Wikipedia-Validierung.", "Begründung bei Inkonsistenz (Wiki).", "Chat-Vorschlag Wiki Artikel: Falls kein passender Artikel gefunden, alternativ vorschlagen.", "Nicht genutzt, evtl. für zukünftige Funktionen.", "Branchenvorschlag via ChatGPT (alternativer Vorschlag).", "Vergleich: Übereinstimmung CRM vs. ChatGPT-Branche (OK/X).", "Begründung bei abweichender Branchenzuordnung.", "FSM-Relevanz: Bewertung, ob das Unternehmen für FSM geeignet ist (OK/X).", "Begründung zur FSM-Bewertung.", "Schätzung Anzahl Mitarbeiter via ChatGPT (nur falls Wiki-Daten fehlen).", "Vergleich CRM vs. Wiki vs. ChatGPT Mitarbeiterzahl (OK/X).", "Begründung bei Mitarbeiterabweichung (Prozentdifferenz).", "Schätzung Servicetechniker via ChatGPT (in Kategorien, z.B. <50, >100, >200, >500).", "Begründung bei Abweichung der Technikerzahl.", "Schätzung Umsatz via ChatGPT.", "Begründung bei Umsatzabweichung.", "Anzahl Kontakte (Serviceleiter) gefunden.", "Anzahl Kontakte (IT-Leiter) gefunden.", "Anzahl Kontakte (Management) gefunden.", "Anzahl Kontakte (Disponent) gefunden.", "Timestamp der Kontaktsuche.", "Timestamp der Wikipedia-Suche.", "Timestamp der ChatGPT-Bewertung / Letzte Prüfung der Zeile.", "Ausgabe der Skriptversion, die das Ergebnis erzeugt hat.", "Token-Zählung (separat pro Modul).", "Roh extrahierter Text der Firmenwebsite (maximal 1000 Zeichen).", "Zusammenfassung des Webseiteninhalts, fokussiert auf Tätigkeitsfeld, Produkte & Leistungen.", - "Timestamp des letzten Website-Scrapings (AR, AS).", # AT (NEU) - "Geschätzter Bucket (1-7) für Servicetechniker basierend auf ML-Modell.",# AU (NEU) - "Konsolidierter Umsatz (Mio €) nach Priorität Wiki > CRM.", # AV (NEU) - "Konsolidierte Mitarbeiterzahl nach Priorität Wiki > CRM." # AW (NEU) + "Systemspalte...", "Enthält den Firmennamen...", "Manuell gepflegte Kurzform...", "Website des Unternehmens.", "Ort des Unternehmens.", "Kurze Beschreibung...", "Aktuelle Branchenzuweisung...", "Externe Branchenbeschreibung...", "Recherchierte Anzahl...", "Umsatz in Mio. € (CRM).", "Anzahl Mitarbeiter (CRM).", "Vorgeschlagene Wikipedia URL...", "Wikipedia URL...", "Erster Absatz...", "Wikipedia-Branche...", "Wikipedia-Umsatz...", "Wikipedia-Mitarbeiterzahl...", "Liste der Wikipedia-Kategorien.", "\"OK\" oder \"X\" – Ergebnis...", "Begründung bei Inkonsistenz...", "Chat-Vorschlag Wiki Artikel...", "Nicht genutzt...", "Branchenvorschlag via ChatGPT...", "Vergleich: Übereinstimmung CRM vs. ...", "Begründung bei abweichender...", "FSM-Relevanz: Bewertung...", "Begründung zur FSM-Bewertung.", "Schätzung Anzahl Mitarbeiter...", "Vergleich CRM vs. Wiki vs. ...", "Begründung bei Mitarbeiterabweichung...", "Schätzung Servicetechniker...", "Begründung bei Abweichung...", "Schätzung Umsatz via ChatGPT.", "Begründung bei Umsatzabweichung.", "Anzahl Kontakte (Serviceleiter)...", "Anzahl Kontakte (IT-Leiter)...", "Anzahl Kontakte (Management)...", "Anzahl Kontakte (Disponent)...", "Timestamp der Kontaktsuche.", "Timestamp der Wikipedia-Suche/Extraktion.", "Timestamp der ChatGPT-Bewertung / Letzte Prüfung der Zeile.", "Ausgabe der Skriptversion...", "Token-Zählung...", "Roh extrahierter Text...", "Zusammenfassung des Webseiteninhalts...", + "Timestamp des letzten Website-Scrapings (AR, AS).", # AT + "Geschätzter Bucket (1-7) für Servicetechniker...", # AU + "Konsolidierter Umsatz (Mio €) nach Priorität Wiki > CRM.", # AV + "Konsolidierte Mitarbeiterzahl nach Priorität Wiki > CRM.", # AW + "Timestamp der letzten Wiki-Verifikation (Spalten S-Y)." # AX (NEU) ], - [ # Aufgabe / Funktion (Zeile 5) - Hier müssen wir neue Einträge hinzufügen - "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Wird durch Wikipedia Scraper bereitgestellt", "Wird zunächst nicht verwendet, kann aber zum Vergleich mit der CRM-Beschreibung genutzt werden.", "Wird u.a. zur finalen Ermittlung der Branche im Ziel-Branchenschema genutzt und mit der CRM-Branche bzw. CRM-Beschreibung Branche Extern verglichen. Stimmen alle drei Einstufungen grob überein, bestärkt dies die ursprüngliche Einstufung. Laufen diese Branchen weit auseinander, soll – sofern der Wikipedia-Artikel verifiziert ist – die Branche von Wikipedia als zuverlässigste Quelle bewertet werden, danach folgen CRM-Beschreibung Branche Extern und CRM-Branche an dritter Stelle.", "Wird u.a. mit CRM-Umsatz zur Validierung des Unternehmens verglichen bzw. zur Bewertung der Größe / Einschätzung der Technikerzahl bzw. FSM-Relevanz genutzt.", "Wird u.a. mit CRM-Anzahl Mitarbeiter zur Validierung des Unternehmens verglichen bzw. zur Bewertung der Größe / Einschätzung der Technikerzahl bzw. FSM-Relevanz genutzt.", "Wenn Website-Daten fehlen, wird in diesem Feld keine zusätzliche Information einbezogen; ansonsten als zusätzlicher Kontext.", "\"Es soll durch ChatGPT geprüft werden, ob anhand der vorliegenden Daten bestätigt werden kann, dass der Wikipedia-Eintrag das Unternehmen sicher beschreibt. Dabei können alle Daten (Website, Umsatz, Mitarbeiterzahl etc.) berücksichtigt werden. Eine gewisse Toleranz (±30%) ist erlaubt. Insbesondere bei Konzernstrukturen muss großzügig bewertet werden. Abweichungen sollen in der Spalte 'Chat Begründung Wiki Inkonsistenz' begründet werden.\"", "\"Liegt eine Inkonsistenz zwischen dem gefundenen Wikipedia-Artikel und dem Unternehmen vor, so soll dies kurz begründet werden. Wurde der Artikel als unpassend identifiziert, soll ChatGPT einen alternativen Wikipedia-Artikel vorschlagen und diesen in 'Chat Vorschlag Wiki Artikel' ausgeben.\"", "\"Sollte durch die Wikipedia-Suche kein Artikel gefunden werden oder als unpassend bewertet werden, soll ChatGPT eigenständig nach einem passenden Artikel recherchieren. Der gefundene Artikel muss vom als unpassend bewerteten Artikel abweichen. Wird kein passender Artikel gefunden, soll 'kein Artikel verfügbar' ausgegeben werden.\"", "XXX derzeit nicht verwendet, wird vermutlich gelöscht xxx", "\"ChatGPT soll anhand der vorliegenden Informationen prüfen, welcher Branche des Ziel-Branchenschemas das Unternehmen am ehesten zugeordnet werden kann. Das Ziel-Branchenschema darf nicht verändert werden, sondern die Vorschläge müssen exakt diesem Schema entsprechen.\"", "Die in Spalte CRM festgelegte Branche soll mit der von ChatGPT ermittelten Branche in 'Chat Vorschlag Branche' verglichen werden.", "Weicht die von ChatGPT ermittelte Branche von der in CRM vorliegenden ab, so soll ChatGPT die Abweichung kurz begründen.", "ChatGPT soll anhand der vorliegenden Daten prüfen, ob das Unternehmen für den Einsatz einer Field Service Management Lösung geeignet ist.", "Die in 'Chat Begründung für FSM Relevanz' angegebene Begründung soll zur Bewertung der FSM-Eignung herangezogen werden.", "Nur wenn kein Wikipedia-Eintrag vorhanden ist, soll ChatGPT basierend auf öffentlich verfügbaren Informationen die Mitarbeiterzahl schätzen. Falls keine Schätzung möglich ist, wird 'keine Schätzung möglich' ausgegeben.", "Entspricht die durch ChatGPT ermittelte Mitarbeiterzahl ungefähr den in CRM und Wikipedia ermittelten Werten (±30%), wird 'OK' ausgegeben, andernfalls 'X' und eine Begründung in 'Chat Begründung Abweichung Mitarbeiterzahl'.", "Weicht die von ChatGPT geschätzte Mitarbeiterzahl signifikant von den CRM- oder Wikipedia-Werten ab, soll dies kurz begründet werden.", "ChatGPT soll auf Basis öffentlich zugänglicher Informationen eine Schätzung der Anzahl Servicetechniker abgeben (Kategorisierung: 0, <50, >100, >200, >500). Bei Abweichungen der Recherche-Werte soll 'X' ausgegeben werden, ansonsten 'OK'.", "Weicht die von ChatGPT geschätzte Technikerzahl von den CRM-Werten ab, soll dies begründet werden.", "Nur wenn kein Wikipedia-Eintrag vorhanden ist, soll ChatGPT den Umsatz anhand der Unternehmenswebsite oder anderer Daten schätzen. Bei fehlender Schätzung soll 'keine Schätzung möglich' ausgegeben werden.", "ChatGPT soll signifikante Umsatzabweichungen zwischen den Schätzungen von Chat, Wikipedia und CRM begründen. Stimmen die Werte (±30%) überein, wird 'OK' ausgegeben.", "Über SerpAPI wird zusammen mit der in 'CRM Kurzform' enthaltenen Information nach 'Serviceleiter' gesucht.", "Über SerpAPI wird zusammen mit 'CRM Kurzform' nach 'Leiter IT' gesucht.", "Über SerpAPI wird zusammen mit 'CRM Kurzform' nach 'Geschäftsführer' gesucht.", "Über SerpAPI wird zusammen mit 'CRM Kurzform' erneut nach 'Serviceleiter' gesucht.", "Wenn die Kontaktsuche gestartet wird, wird der erste Eintrag ohne Zeitstempel gesucht; Zeilen mit vorhandenem Zeitstempel werden übersprungen.", "Wenn die Wikipedia-Suche gestartet wird, wird der erste Eintrag ohne Zeitstempel gesucht; Zeilen mit vorhandenem Zeitstempel werden übersprungen.", "Wenn die ChatGPT-Bewertung gestartet wird, wird der erste Eintrag ohne Zeitstempel gesucht; Zeilen mit vorhandenem Zeitstempel werden übersprungen.", "Wird durch das System befüllt", "Wird durch tiktoken berechnet", "Wird durch Web Scraper befüllt (z.B. Modus website)", "Wird durch ChatGPT API aus Website Rohtext generiert (z.B. Modus website)", - "Timestamp wird gesetzt, wenn Website Rohtext/Zusammenfassung geschrieben werden.", # AT (NEU) - "Ergebnis der Schätzung durch das trainierte ML-Modell (z.B. Decision Tree).", # AU (NEU) - "Vom Skript berechneter Wert, priorisiert Wiki > CRM. Dient als Input für ML-Modell und zur Transparenz.", # AV (NEU) - "Vom Skript berechneter Wert, priorisiert Wiki > CRM. Dient als Input für ML-Modell und zur Transparenz." # AW (NEU) + [ # Aufgabe / Funktion (Zeile 5) - Ergänzt um AX + "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Datenquelle", "Wird durch Wikipedia Scraper bereitgestellt", "Wird zunächst nicht verwendet...", "Wird u.a. zur finalen Ermittlung...", "Wird u.a. mit CRM-Umsatz...", "Wird u.a. mit CRM-Anzahl...", "Wenn Website-Daten fehlen...", "\"Es soll durch ChatGPT geprüft werden...", "\"Liegt eine Inkonsistenz...", "\"Sollte durch die Wikipedia-Suche...", "XXX derzeit nicht verwendet...", "\"ChatGPT soll anhand der vorliegenden...", "Die in Spalte CRM festgelegte...", "Weicht die von ChatGPT ermittelte...", "ChatGPT soll anhand der vorliegenden Daten prüfen...", "Die in 'Chat Begründung für FSM Relevanz'...", "Nur wenn kein Wikipedia-Eintrag...", "Entspricht die durch ChatGPT ermittelte...", "Weicht die von ChatGPT geschätzte...", "ChatGPT soll auf Basis öffentlich...", "Weicht die von ChatGPT geschätzte...", "Nur wenn kein Wikipedia-Eintrag...", "ChatGPT soll signifikante Umsatzabweichungen...", "Über SerpAPI wird zusammen...", "Über SerpAPI wird zusammen...", "Über SerpAPI wird zusammen...", "Über SerpAPI wird zusammen...", "Wenn die Kontaktsuche gestartet wird...", "Wenn die Wikipedia-Suche gestartet wird...", "Wenn die ChatGPT-Bewertung gestartet wird...", "Wird durch das System befüllt", "Wird durch tiktoken berechnet", "Wird durch Web Scraper...", "Wird durch ChatGPT API...", + "Timestamp wird gesetzt, wenn Website Rohtext/Zusammenfassung geschrieben werden.", # AT + "Ergebnis der Schätzung durch das trainierte ML-Modell.", # AU + "Vom Skript berechneter Wert, priorisiert Wiki > CRM...", # AV + "Vom Skript berechneter Wert, priorisiert Wiki > CRM...", # AW + "Timestamp wird gesetzt, wenn Wiki-Verifikation (S-Y) durchgeführt wurde." # AX (NEU) ] ] - # Bestimme den Bereich basierend auf der Anzahl der Spalten in der ersten Header-Zeile (jetzt AW) - num_cols = len(new_headers[0]) # Sollte 49 sein (A=1 ... AW=49) + num_cols = len(new_headers[0]) def colnum_string(n): string = "" - while n > 0: - n, remainder = divmod(n - 1, 26) - string = chr(65 + remainder) + string + while n > 0: n, remainder = divmod(n - 1, 26); string = chr(65 + remainder) + string return string - - end_col_letter = colnum_string(num_cols) # Sollte "AW" ergeben - header_range = f"A1:{end_col_letter}{len(new_headers)}" # Sollte A1:AW5 sein - + end_col_letter = colnum_string(num_cols) + header_range = f"A1:{end_col_letter}{len(new_headers)}" try: sheet.update(values=new_headers, range_name=header_range) print(f"Alignment-Demo abgeschlossen: Header in Bereich {header_range} geschrieben.")