diff --git a/brancheneinstufung.py b/brancheneinstufung.py index 7694496c..4364c7f7 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -107,7 +107,9 @@ def process_wiki_batch(main_sheet, data, start_row, end_row): """ Batch-Prozess für Wikipedia-Verifizierung (Wiki-Modus): - Verarbeitet alle Zeilen von start_row bis end_row in Gruppen (Batchgröße = Config.BATCH_SIZE). - - Ergebnisse werden in den Spalten S bis Y geschrieben. + - Für jeden Batch wird ein aggregierter Prompt erstellt und an ChatGPT geschickt. + - Die Aggregat-Ergebnisse werden zeilenweise in Spalte S (Wiki-Validierung), T (alternativer Wiki-Artikel), + U (Wiki-Erklärung) und V–Y (Platzhalter) geschrieben. """ batch_size = Config.BATCH_SIZE batches = [] @@ -133,14 +135,12 @@ def process_wiki_batch(main_sheet, data, start_row, end_row): _process_batch(main_sheet, batches, row_numbers) debug_print("Wiki batch processing completed.") - def process_website_batch(main_sheet, data, start_row, end_row): """ Batch-Prozess für Website-Scraping (Website-Modus): - - Für jede Zeile von start_row bis end_row werden Website-Rohtext (get_website_raw) und - Zusammenfassung (summarize_website_content) abgerufen. - - Ergebnisse werden in Spalte AR (Rohtext) und AS (Zusammenfassung) geschrieben. - - Am Ende jeder Zeile wird der Zeitstempel (Spalte AO) und Version (Spalte AP) gesetzt. + - Für jede Zeile von start_row bis end_row wird, falls eine CRM-Website vorhanden ist, + get_website_raw aufgerufen, um den Rohtext abzurufen, und summarize_website_content zur Zusammenfassung. + - Die Ergebnisse werden in Spalte AR (Website Rohtext) und AS (Website Zusammenfassung) geschrieben. """ for i in range(start_row, end_row + 1): row = data[i - 1] @@ -153,24 +153,19 @@ def process_website_batch(main_sheet, data, start_row, end_row): try: main_sheet.update(values=[[raw_text]], range_name=f"AR{i}") main_sheet.update(values=[[summary]], range_name=f"AS{i}") - current_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - main_sheet.update(values=[[current_timestamp]], range_name=f"AO{i}") - main_sheet.update(values=[[Config.VERSION]], range_name=f"AP{i}") - debug_print(f"Zeile {i}: Website-Daten aktualisiert | Zeitstempel: {current_timestamp}, Version: {Config.VERSION}") + debug_print(f"Zeile {i}: Website-Daten aktualisiert.") except Exception as e: debug_print(f"Fehler beim Updaten der Website-Daten in Zeile {i}: {e}") time.sleep(Config.RETRY_DELAY) debug_print("Website batch processing completed.") - def process_branch_batch(main_sheet, data, start_row, end_row): """ Batch-Prozess für Brancheneinschätzung (Branch-Modus): - - Für jede Zeile von start_row bis end_row werden relevante Felder ausgelesen und - evaluate_branche_chatgpt aufgerufen. - - Das Ergebnis (Dictionary mit "branch", "consistency", "justification") wird in - Spalte W (Branch), X (Konsistenz) und Y (Begründung) geschrieben. - - Für jede verarbeitete Zeile werden zudem der Zeitstempel (Spalte AO) und Version (Spalte AP) gesetzt. + - Für jede Zeile von start_row bis end_row werden die relevanten Felder für die Brancheneinschätzung ausgelesen. + - Es werden evaluate_branche_chatgpt aufgerufen, die das Branchenergebnis als Dictionary zurückgibt. + - Die Ergebnisse werden in Spalte W (Chat Vorschlag Branche), X (Chat Konsistenz Branche) + und Y (Chat Begründung Abweichung Branche) geschrieben. """ for i in range(start_row, end_row + 1): row = data[i - 1] @@ -178,30 +173,25 @@ def process_branch_batch(main_sheet, data, start_row, end_row): beschreibung = row[7] if len(row) > 7 else "" wiki_branche = row[14] if len(row) > 14 else "" wiki_kategorien = row[17] if len(row) > 17 else "" + # Website Zusammenfassung aus Spalte AS (Index 45, wenn vorhanden) website_summary = row[44] if len(row) > 44 else "" result = evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kategorien, website_summary) try: main_sheet.update(values=[[result["branch"]]], range_name=f"W{i}") main_sheet.update(values=[[result["consistency"]]], range_name=f"X{i}") main_sheet.update(values=[[result["justification"]]], range_name=f"Y{i}") - current_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - main_sheet.update(values=[[current_timestamp]], range_name=f"AO{i}") - main_sheet.update(values=[[Config.VERSION]], range_name=f"AP{i}") - debug_print(f"Zeile {i}: Branch-Einschätzung aktualisiert: {result} | Zeitstempel: {current_timestamp}, Version: {Config.VERSION}") + debug_print(f"Zeile {i}: Branch-Einschätzung aktualisiert: {result}") except Exception as e: debug_print(f"Fehler beim Updaten der Branch-Daten in Zeile {i}: {e}") time.sleep(Config.RETRY_DELAY) debug_print("Branch batch processing completed.") - def run_dispatcher(mode, row_limit=None): """ Dispatcher-Funktion: - - Ermittelt ab Zeile 7 die erste Zeile, in der in Spalte AO (Index 41) kein Zeitstempel steht. - - Legt den zu verarbeitenden Bereich fest: Ab diesem Startpunkt werden row_limit Zeilen (falls angegeben) - verarbeitet. - - Basierend auf dem mode-Parameter ("wiki", "website", "branch", "combined") werden die entsprechenden - Batch-Prozesse gestartet. + - Ermittelt aus dem Google Sheet ab Zeile 7 die erste Zeile, in der in Spalte AO (Index 41) kein Zeitstempel steht. + - Legt den zu verarbeitenden Bereich fest: ab diesem Startpunkt werden row_limit Zeilen (falls angegeben) verarbeitet. + - Basierend auf dem Modus-Parameter (wiki, website, branch, combined) werden die entsprechenden Batch-Prozesse gestartet. """ debug_print(f"Starte Dispatcher im Modus '{mode}' mit row_limit={row_limit}.") gc = gspread.authorize(ServiceAccountCredentials.from_json_keyfile_name( @@ -759,8 +749,7 @@ def _process_batch(main_sheet, batches, row_numbers): """ Hilfsfunktion: Bearbeitet einen Batch, indem ein aggregierter Prompt erstellt und die aggregierte Antwort zeilenweise den entsprechenden Zeilennummern zugeordnet wird. - Die Ergebnisse werden in den Spalten S bis Y geschrieben, und anschließend wird - für jede Zeile der aktuelle Zeitstempel (Spalte AO) sowie die Versionsnummer (Spalte AP) eingetragen. + Die Ergebnisse werden in Spalten S bis Y geschrieben. """ aggregated_prompt = ( "Du bist ein Experte in der Verifizierung von Wikipedia-Artikeln für Unternehmen. " @@ -827,11 +816,7 @@ def _process_batch(main_sheet, batches, row_numbers): main_sheet.update(values=[[alt_article]], range_name=f"T{current_row}") main_sheet.update(values=[[wiki_explanation]], range_name=f"U{current_row}") main_sheet.update(values=[["", "", "", ""]], range_name=f"V{current_row}:Y{current_row}") - # Neu: Setze Zeitstempel in Spalte AO und Version in Spalte AP - current_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - main_sheet.update(values=[[current_timestamp]], range_name=f"AO{current_row}") - main_sheet.update(values=[[Config.VERSION]], range_name=f"AP{current_row}") - debug_print(f"Zeile {current_row} verifiziert: Antwort: {answer} | Zeitstempel: {current_timestamp}, Version: {Config.VERSION}") + debug_print(f"Zeile {current_row} verifiziert: Antwort: {answer}") except Exception as e: debug_print(f"Fehler beim Updaten der Zeile {current_row}: {e}") time.sleep(Config.RETRY_DELAY) @@ -1406,21 +1391,17 @@ class WikipediaScraper: # ==================== NEUE FUNKTION: Angepasste evaluate_branche_chatgpt ==================== def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kategorien, website_summary): - # Ziel-Branchenschema laden (BOM entfernen) def load_target_branches(): try: - with open("ziel_Branchenschema.csv", "r", encoding="utf-8-sig") as csvfile: + with open("ziel_Branchenschema.csv", "r", encoding="utf-8") as csvfile: reader = csv.reader(csvfile) - # Nimm alle Einträge (Spalte 0), ohne leere Zeilen - branches = [row[0].strip() for row in reader if row and row[0].strip()] + branches = [row[0] for row in reader if row] return branches except Exception as e: debug_print(f"Fehler beim Laden des Ziel-Branchenschemas: {e}") return [] target_branches = load_target_branches() target_branches_str = "\n".join(target_branches) - - # Definierte Fokusbranchen (wie bisher) focus_branches = [ "Gutachter / Versicherungen > Baugutachter", "Gutachter / Versicherungen > Technische Gutachten", @@ -1439,8 +1420,6 @@ def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kateg "Versorger > Telekommunikation" ] focus_branches_str = "\n".join(focus_branches) - - # API-Key laden try: with open("api_key.txt", "r") as f: api_key = f.read().strip() @@ -1449,7 +1428,7 @@ def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kateg return {"branch": "k.A.", "consistency": "k.A.", "justification": "k.A."} openai.api_key = api_key - # Fallback: Wenn kein Wikipedia-Artikel vorhanden, verwende Website-Zusammenfassung + # Falls kein Wikipedia-Artikel vorliegt, nutze die Website-Zusammenfassung als Fallback für die Branchenbeschreibung if wiki_branche.strip().lower() == "k.a.": debug_print("Kein Wikipedia-Artikel vorhanden – verwende Website-Zusammenfassung als Branchenbeschreibung-Fallback.") used_description = website_summary @@ -1457,7 +1436,6 @@ def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kateg used_description = beschreibung debug_print(f"Verwendete Angaben: CRM-Branche='{crm_branche}', externe Beschreibung='{beschreibung}', Wiki-Branche='{wiki_branche}', Wiki-Kategorien='{wiki_kategorien}'") - # System-Prompt erstellen system_prompt = ( "Du bist ein Experte im Field Service Management. Deine Aufgabe ist es, ein Unternehmen basierend auf folgenden Angaben einer Branche zuzuordnen.\n\n" f"CRM-Branche (Spalte F): {crm_branche if crm_branche.strip() != '' else 'k.A.'}\n" @@ -1473,7 +1451,8 @@ def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kateg "1. Wikipedia-Branche (Spalte N) zusammen mit Wikipedia-Kategorien (Spalte Q) (höchste Priorität, wenn verifiziert, ansonsten erhöhte Gewichtung der Kategorien)\n" "2. Branchenbeschreibung (Spalte G) – (hier wird die Website-Zusammenfassung genutzt, wenn kein Wikipedia-Artikel vorhanden ist)\n" "3. CRM-Branche (Spalte F)\n\n" - "Ordne das Unternehmen exakt einer der oben genannten Branchen zu (keine zusätzlichen Branchen erfinden). Bitte antworte im Format:\n" + "Ordne das Unternehmen exakt einer der oben genannten Branchen zu (keine zusätzlichen Branchen erfinden). " + "Bitte antworte im Format:\n" "Branche: \nÜbereinstimmung: \nBegründung: " ) @@ -1485,48 +1464,39 @@ def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kateg ) result = response.choices[0].message.content.strip() debug_print(f"Branchenabgleich ChatGPT Antwort: '{result}'") + branch = "k.A." + consistency = "k.A." + justification = "" + for line in result.split("\n"): + if line.lower().startswith("branche:"): + branch = line.split(":", 1)[1].strip() + elif line.lower().startswith("übereinstimmung:"): + consistency = line.split(":", 1)[1].strip() + elif line.lower().startswith("begründung:"): + justification = line.split(":", 1)[1].strip() + + # Zuerst prüfen, ob der ChatGPT-Vorschlag überhaupt zum Ziel-Branchenschema gehört + if branch.lower() not in [tb.lower() for tb in target_branches]: + justification = "Vorgeschlagene Branche entspricht nicht dem Ziel-Branchenschema." + branch = "k.A." + consistency = "X" + else: + # Vergleiche die normierten Werte der CRM-Branche und des ChatGPT-Vorschlags + norm_crm = normalize_company_name(crm_branche) + norm_branch = normalize_company_name(branch) + debug_print(f"Vergleich normierter Werte: CRM='{norm_crm}' vs. ChatGPT='{norm_branch}'") + if norm_crm and norm_branch == norm_crm: + justification = "" + consistency = "ok" + else: + consistency = "X" + + debug_print(f"Endergebnis Branchenbewertung: Branche='{branch}', Übereinstimmung='{consistency}', Begründung='{justification}'") + return {"branch": branch, "consistency": consistency, "justification": justification} except Exception as e: debug_print(f"Fehler beim Aufruf der ChatGPT API für Branchenabgleich: {e}") return {"branch": "k.A.", "consistency": "k.A.", "justification": "k.A."} - - # Ergebnisse parsen - chat_branch = None - chat_consistency = None - chat_justification = "" - for line in result.split("\n"): - lower_line = line.lower() - if lower_line.startswith("branche:"): - chat_branch = line.split(":", 1)[1].strip() - elif lower_line.startswith("übereinstimmung:"): - chat_consistency = line.split(":", 1)[1].strip() - elif lower_line.startswith("begründung:"): - chat_justification = line.split(":", 1)[1].strip() - - # Überprüfung: Wird ein Branch vorgeschlagen und ist dieser im Ziel-Schema enthalten? - valid = False - if chat_branch: - # Vergleiche normiert - norm_chat = normalize_company_name(chat_branch) - norm_targets = [normalize_company_name(tb) for tb in target_branches] - if norm_chat and norm_chat in norm_targets: - valid = True - if not valid: - # Falls der Vorschlag nicht im Schema enthalten ist, gebe klar die Fehlermeldung zurück - debug_print("Vorgeschlagene Branche entspricht nicht dem Ziel-Branchenschema.") - return {"branch": "k.A.", "consistency": "X", "justification": "Vorgeschlagene Branche entspricht nicht dem Ziel-Branchenschema."} - else: - # Wenn der ChatGPT-Vorschlag gültig ist, vergleichen wir ihn mit der normierten CRM-Branche - norm_crm = normalize_company_name(crm_branche) - norm_chat = normalize_company_name(chat_branch) - debug_print(f"Vergleich normierter Werte: CRM='{norm_crm}' vs. ChatGPT='{norm_chat}'") - if norm_crm and norm_crm == norm_chat: - chat_consistency = "ok" - chat_justification = "" - else: - chat_consistency = "X" - debug_print(f"Endergebnis Branchenbewertung: Branche='{chat_branch}', Übereinstimmung='{chat_consistency}', Begründung='{chat_justification}'") - return {"branch": chat_branch, "consistency": chat_consistency, "justification": chat_justification}