diff --git a/brancheneinstufung.py b/brancheneinstufung.py index ca7c552d..6050cc8f 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -391,41 +391,20 @@ def is_valid_company_article(wiki_categories): def load_target_schema(csv_filepath="ziel_Branchenschema.csv"): """ - Liest das Ziel-Branchenschema aus der CSV-Datei ein. - Die CSV-Datei sollte in Spalte A den externen (Wikipedia-)Branchenbegriff - und in Spalte B den zugehörigen Zielwert enthalten. - - Returns: - mapping (dict): Ein Dictionary, das externe Branchenbegriffe (lowercase) auf - die zugehörigen Zielwerte (lowercase) abbildet. - schema_string (str): Eine formattierte Zeichenkette als Aufzählung der gültigen - Zielbranchen, die im Prompt übergeben werden kann. - allowed_targets (list): Eine sortierte Liste der eindeutigen Zielwerte. + Baut das Ziel-Branchenschema als String aus der CSV-Datei. + Gibt ein Tupel zurück: (mapping, schema_string, allowed_targets) """ - import csv - mapping = {} - valid_targets = set() - try: - with open(csv_filepath, encoding="utf-8") as f: - reader = csv.reader(f, delimiter=";") - for row in reader: - if len(row) >= 2: - external = row[0].strip().lower() - target = row[1].strip().lower() - if target: - mapping[external] = target - valid_targets.add(target) - except Exception as e: - debug_print("Fehler beim Einlesen des Ziel-Branchenschemas: " + str(e)) + mapping, allowed_branches = load_target_branches(csv_filepath) + if allowed_branches: + schema_string = ( + "Ziel-Branchenschema: Folgende Branchenbereiche sind gültig:\n" + + "\n".join(f"- {branch}" for branch in allowed_branches) + + "\nBitte ordne das Unternehmen ausschließlich in einen dieser Bereiche ein." + ) + return mapping, schema_string, allowed_branches + else: return {}, "Ziel-Branchenschema nicht verfügbar.", [] - - sorted_targets = sorted(valid_targets, key=lambda s: s.lower()) - schema_string = ( - "Ziel-Branchenschema: Folgende Branchenbereiche sind gültig:\n" + - "\n".join(f"- {value}" for value in sorted_targets) + - "\nBitte ordne das Unternehmen ausschließlich in einen dieser Bereiche ein." - ) - return mapping, schema_string, sorted_targets + def serp_website_lookup(company_name): """ @@ -627,7 +606,7 @@ def merge_with_prefix(suggestion, crm_branch): def fuzzy_similarity(str1, str2): """ - Gibt den Ähnlichkeitswert (zwischen 0 und 1) der beiden Strings zurück. + Berechnet die Ähnlichkeit zweier Strings als Wert zwischen 0 und 1. """ return SequenceMatcher(None, str1, str2).ratio() @@ -1534,32 +1513,58 @@ class WikipediaScraper: debug_print(f"Suchfehler: {str(e)}") continue return None +# Annahme: debug_print und Config sind bereits definiert + +def load_target_branches(csv_filepath="ziel_Branchenschema.csv"): + """ + Liest das Ziel-Branchenschema aus der CSV-Datei ein. + Erwartet, dass in Spalte A der externe (Wikipedia-)Branchenbegriff + und in Spalte B der zugehörige Zielwert (z. B. "maschinenbau") enthalten ist. + Gibt ein Mapping (Dictionary) und eine sortierte Liste der erlaubten Ziel-Branchen zurück. + """ + mapping = {} + allowed_branches = set() + try: + with open(csv_filepath, encoding="utf-8") as f: + reader = csv.reader(f) + for row in reader: + if len(row) >= 2: + external = row[0].strip().lower() + target = row[1].strip().lower() + if external and target: + mapping[external] = target + allowed_branches.add(target) + allowed_branches = sorted(list(allowed_branches), key=lambda s: s.lower()) + return mapping, allowed_branches + except Exception as e: + debug_print("Fehler beim Einlesen des Ziel-Branchenschemas: " + str(e)) + return {}, [] # ==================== NEUE FUNKTION: Angepasste evaluate_branche_chatgpt ==================== def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kategorien, website_summary): """ Ordnet das Unternehmen basierend auf den angegebenen Informationen exakt einer Branche des in der CSV-Datei hinterlegten Ziel-Branchenschemas zu. - + Der System-Prompt enthält nun den erlaubten Branchenbereich, und der von ChatGPT gegebene Vorschlag wird bereinigt und gegen die Einträge des Ziel-Schemas validiert. - + Falls der Vorschlag nicht validiert werden kann, erfolgt ein Fallback auf den CRM-Wert. - + Args: - crm_branche (str): Branche laut CRM - beschreibung (str): Unternehmensbeschreibung (CRM) - wiki_branche (str): Branche aus Wikipedia (falls vorhanden) - wiki_kategorien (str): Wikipedia-Kategorien - website_summary (str): Zusammenfassung des Website-Inhalts - + crm_branche (str): Branche laut CRM. + beschreibung (str): Unternehmensbeschreibung (CRM). + wiki_branche (str): Branche aus Wikipedia (falls vorhanden). + wiki_kategorien (str): Wikipedia-Kategorien. + website_summary (str): Zusammenfassung des Website-Inhalts. + Returns: dict: Enthält "branch", "consistency" (ok oder X) und "justification". """ # Lade Mapping und Liste der erlaubten Ziel-Branchen mapping, allowed_branches = load_target_branches() - # Baue den Text für das Ziel-Branchenschema, der im System-Prompt an ChatGPT übergeben wird + # Baue den Text für das Ziel-Branchenschema, der im System-Prompt an ChatGPT übergeben wird. schema_lines = ["Ziel-Branchenschema: Folgende Branchenbereiche sind gültig:"] for branch in allowed_branches: schema_lines.append(f"- {branch}") @@ -1619,23 +1624,23 @@ def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kateg elif lower_line.startswith("begründung:"): explanation = line.split(":", 1)[1].strip() - # Bereinige den Vorschlag: Entferne unnötige Satzzeichen und konvertiere in Kleinbuchstaben + # Bereinige den Vorschlag: Entferne unnötige Satzzeichen und konvertiere in Kleinbuchstaben. clean_suggestion = re.sub(r'[^\w\s/&-]', '', suggestion).strip().lower() - # Falls der bereinigte Vorschlag kein Hierarchie-Trennzeichen ">" enthält, übernehme den Präfix aus der CRM-Branche + # Falls der bereinigte Vorschlag kein Hierarchie-Trennzeichen ">" enthält, übernehme den Präfix aus der CRM-Branche. if ">" not in clean_suggestion and ">" in crm_branche: prefix = crm_branche.split(">")[0].strip().lower() clean_suggestion = prefix + " > " + clean_suggestion - # Prüfe, ob der bereinigte Vorschlag mit einem erlaubten Eintrag (Fuzzy Matching) übereinstimmt + # Prüfe, ob der bereinigte Vorschlag mit einem erlaubten Eintrag (Fuzzy Matching) übereinstimmt. valid = False for allowed in allowed_branches: sim = fuzzy_similarity(clean_suggestion, allowed) - if sim > 0.95: # sehr hoher Ähnlichkeitswert (anpassbar) + if sim > 0.95: # Sehr hoher Ähnlichkeitswert (anpassbar) valid = True - # Setze den Vorschlag exakt auf den Zielwert - clean_suggestion = allowed + clean_suggestion = allowed # Setze exakte Übereinstimmung break + if not valid: debug_print(f"Mapping ungültig für Vorschlag: '{clean_suggestion}'. Fallback: CRM-Branche ('{crm_branche}') verwendet.") return {"branch": crm_branche, "consistency": consistency, "justification": "Fallback: CRM-Wert verwendet aufgrund ungültiger ChatGPT-Zuweisung."}