From f1bc8c175a8562a1365752c5bd67680db63f4b34 Mon Sep 17 00:00:00 2001 From: Floke Date: Wed, 2 Apr 2025 12:21:09 +0000 Subject: [PATCH] Implementiere ChatGPT-Branchenabgleich & Update Branch Mapping (v1.3.2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Neue Funktion zur Branchenzuordnung hinzugefügt. ChatGPT bewertet basierend auf CRM, Wikipedia-Daten und Fokusbranchen. Spalten V, W und X werden entsprechend aktualisiert. Versionsnummer wurde auf v1.3.2 aktualisiert. --- brancheneinstufung.py | 138 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 123 insertions(+), 15 deletions(-) diff --git a/brancheneinstufung.py b/brancheneinstufung.py index 43ba867f..f49ff86f 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -14,7 +14,7 @@ import csv # ==================== KONFIGURATION ==================== class Config: - VERSION = "v1.3.1" # v1.3.1: Validierung des Wikipedia-Artikels implementiert + VERSION = "v1.3.3" # v1.3.3: Branchenabgleich per ChatGPT integriert, Ziel-Branchenschema inkl. aller gültigen Branchen eingebunden. LANG = "de" CREDENTIALS_FILE = "service_account.json" SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo" @@ -67,7 +67,7 @@ def normalize_company_name(name): ] pattern = r'\b(' + '|'.join(forms) + r')\b' normalized = re.sub(pattern, '', name, flags=re.IGNORECASE) - normalized = re.sub(r'[\-–]', ' ', normalized) + normalized = re.sub(r'[\-–]', ' ', normalized) normalized = re.sub(r'\s+', ' ', normalized).strip() return normalized.lower() @@ -161,7 +161,6 @@ def validate_article_with_chatgpt(crm_data, wiki_data): als CSV-Text und übermittelt diesen an die ChatGPT-API, um zu validieren, ob beide Datensätze zum selben Unternehmen gehören. """ - # Erstelle den CSV-Text crm_headers = "Firmenname;Website;Ort;Beschreibung;Aktuelle Branche;Beschreibung Branche extern;Anzahl Techniker;Umsatz (CRM);Anzahl Mitarbeiter (CRM)" wiki_headers = "Wikipedia URL;Wikipedia Absatz;Wikipedia Branche;Wikipedia Umsatz;Wikipedia Mitarbeiter;Wikipedia Kategorien" prompt_text = ( @@ -169,7 +168,7 @@ def validate_article_with_chatgpt(crm_data, wiki_data): "Die erste Zeile sind Daten aus unserem CRM-System, die zweite Zeile stammen aus Wikipedia. " "Vergleiche insbesondere den Firmennamen, den Ort und die Branche. Unterschiede im Umsatz können toleriert werden, " "solange sie im Rahmen von 10% liegen. Falls die Datensätze übereinstimmen, antworte ausschließlich mit 'OK'. " - "Falls nicht, nenne bitte den wichtigsten Grund (z. B. abweichender Firmenname oder Ort). \n\n" + "Falls nicht, nenne bitte den wichtigsten Grund (z. B. abweichender Firmenname oder Ort). \n\n" f"CRM-Daten:\n{crm_headers}\n{crm_data}\n\n" f"Wikipedia-Daten:\n{wiki_headers}\n{wiki_data}\n\n" "Antwort: " @@ -194,6 +193,95 @@ def validate_article_with_chatgpt(crm_data, wiki_data): debug_print(f"Fehler beim Validierungs-API-Aufruf: {e}") return "k.A." +# ==================== BRANCHENABGLEICH PER CHATGPT ==================== +def load_target_branches(): + try: + with open("ziel_Branchenschema.csv", "r", encoding="utf-8") as csvfile: + reader = csv.reader(csvfile) + # Annahme: Jede Zeile enthält in der ersten Spalte einen gültigen Branchen-Namen + 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 [] + +# Fokusbranchen-Liste (wie definiert) +focus_branches = [ + "Gutachter / Versicherungen > Baugutachter", + "Gutachter / Versicherungen > Technische Gutachten", + "Gutachter / Versicherungen > Versicherungsgutachten", + "Gutachter / Versicherungen > Medizinische Gutachten", + "Hersteller / Produzenten > Anlagenbau", + "Hersteller / Produzenten > Automaten (Vending, Slot)", + "Hersteller / Produzenten > Gebäudetechnik Allgemein", + "Hersteller / Produzenten > Gebäudetechnik Heizung, Lüftung, Klima", + "Hersteller / Produzenten > Maschinenbau", + "Hersteller / Produzenten > Medizintechnik", + "Service provider (Dienstleister) > Aufzüge und Rolltreppen", + "Service provider (Dienstleister) > Feuer- und Sicherheitssysteme", + "Service provider (Dienstleister) > Servicedienstleister / Reparatur ohne Produktion", + "Service provider (Dienstleister) > Facility Management", + "Versorger > Telekommunikation" +] + +def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kategorien): + # Lade das Ziel-Branchenschema + target_branches = load_target_branches() + target_branches_str = "\n".join(target_branches) + focus_branches_str = "\n".join(focus_branches) + try: + with open("api_key.txt", "r") as f: + api_key = f.read().strip() + except Exception as e: + debug_print(f"Fehler beim Lesen des API-Tokens: {e}") + return {"branch": "k.A.", "consistency": "k.A.", "justification": "k.A."} + openai.api_key = api_key + + 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}\n" + f"Branchenbeschreibung (Spalte G): {beschreibung}\n" + f"Wikipedia-Branche (Spalte N): {wiki_branche}\n" + f"Wikipedia-Kategorien (Spalte Q): {wiki_kategorien}\n\n" + "Das Ziel-Branchenschema umfasst ALLE gültigen Branchen, also sowohl Fokusbranchen als auch weitere Branchen (z. B. 'Housing > Sozialbau Unternehmen').\n" + "Das vollständige Ziel-Branchenschema lautet:\n" + f"{target_branches_str}\n\n" + "Falls das Unternehmen mehreren Branchen zugeordnet werden könnte, wähle bitte bevorzugt eine Branche aus der folgenden Fokusliste, sofern zutreffend:\n" + f"{focus_branches_str}\n\n" + "Gewichtung der Angaben:\n" + "1. Wikipedia-Branche (Spalte N) zusammen mit Wikipedia-Kategorien (Spalte Q) (höchste Priorität, wenn verifiziert)\n" + "2. Branchenbeschreibung (Spalte G)\n" + "3. CRM-Branche (Spalte F)\n\n" + "Ordne das Unternehmen exakt einer der oben genannten Branchen zu (es dürfen keine zusätzlichen Branchen erfunden werden). " + "Bitte antworte in folgendem Format (ohne zusätzliche Informationen):\n" + "Branche: \n" + "Übereinstimmung: \n" + "Begründung: " + ) + try: + response = openai.ChatCompletion.create( + model="gpt-3.5-turbo", + messages=[{"role": "system", "content": system_prompt}], + temperature=0.0 + ) + result = response.choices[0].message.content.strip() + debug_print(f"Branchenabgleich ChatGPT Antwort: '{result}'") + # Parsing der Antwort + 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() + 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."} + # ==================== GOOGLE SHEET HANDLER ==================== class GoogleSheetHandler: def __init__(self): @@ -468,6 +556,7 @@ class DataProcessor: dt_range = f"AH{row_num}" ver_range = f"AI{row_num}" print(f"\n[{datetime.now().strftime('%H:%M:%S')}] Verarbeite Zeile {row_num}: {company_name}") + article = self.wiki_scraper.search_company_article(company_name, website) if article: company_data = self.wiki_scraper.extract_company_data(article.url) @@ -481,6 +570,7 @@ class DataProcessor: 'categories': 'k.A.', 'full_infobox': 'k.A.' } + wiki_values = [ "k.A.", # Vorschlag Wiki URL company_data.get('url', 'k.A.'), @@ -492,6 +582,7 @@ class DataProcessor: ] self.sheet_handler.sheet.update(values=[wiki_values], range_name=wiki_update_range) time.sleep(1) + # Umsatz-Schätzung via ChatGPT (wie bisher) wiki_umsatz = company_data.get('umsatz', 'k.A.') if wiki_umsatz != "k.A.": @@ -499,28 +590,45 @@ class DataProcessor: else: chatgpt_umsatz = "k.A." self.sheet_handler.sheet.update(values=[[chatgpt_umsatz]], range_name=chatgpt_range) + # Umsatz-Abgleich (wie bisher) crm_umsatz = row_data[8] if len(row_data) > 8 else "k.A." abgleich_result = compare_umsatz_values(crm_umsatz, company_data.get('umsatz', 'k.A.')) self.sheet_handler.sheet.update(values=[[abgleich_result]], range_name=abgleich_range) - # --- Neuer Validierungsschritt --- - # Aggregiere CRM-Daten (B bis J) und Wikipedia-Daten (L bis Q) als CSV-Text + + # Neuer Validierungsschritt (Firmenabgleich) – unverändert crm_data = ";".join(row_data[1:10]) wiki_data = ";".join(row_data[11:17]) valid_result = validate_article_with_chatgpt(crm_data, wiki_data) self.sheet_handler.sheet.update(values=[[valid_result]], range_name=valid_range) + + # Neuer Branchenabgleich per ChatGPT: + crm_branche = row_data[5] if len(row_data) > 5 else "k.A." + beschreibung_branche = row_data[6] if len(row_data) > 6 else "k.A." + wiki_branche = company_data.get('branche', 'k.A.') + wiki_kategorien = company_data.get('categories', 'k.A.') + branche_result = evaluate_branche_chatgpt(crm_branche, beschreibung_branche, wiki_branche, wiki_kategorien) + + # Update der Spalten: + # Spalte V: Vorschlag neue Branche + # Spalte W: Konsistenzprüfung Branche (ok, wenn Übereinstimmung, sonst X) + # Spalte X: Begründung bei Abweichung + branche_v_range = f"V{row_num}" + branche_w_range = f"W{row_num}" + branche_x_range = f"X{row_num}" + self.sheet_handler.sheet.update(values=[[branche_result["branch"]]], range_name=branche_v_range) + self.sheet_handler.sheet.update(values=[[branche_result["consistency"]]], range_name=branche_w_range) + self.sheet_handler.sheet.update(values=[[branche_result["justification"]]], range_name=branche_x_range) + # Timestamp und Version schreiben current_dt = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.sheet_handler.sheet.update(values=[[current_dt]], range_name=dt_range) self.sheet_handler.sheet.update(values=[[Config.VERSION]], range_name=ver_range) - print(f"✅ Aktualisiert: URL: {company_data.get('url', 'k.A.')}, Absatz: {company_data.get('first_paragraph', 'k.A.')[:30]}..., " - f"Branche: {company_data.get('branche', 'k.A.')}, Wikipedia Umsatz: {company_data.get('umsatz', 'k.A.')}, " - f"Mitarbeiter: {company_data.get('mitarbeiter', 'k.A.')}, Kategorien: {company_data.get('categories', 'k.A.')}, " - f"ChatGPT Umsatz: {chatgpt_umsatz}, Umsatz-Abgleich: {abgleich_result}, Validierung: {valid_result}") - if MODE == "2": - print("----- Vollständiger Infobox-Inhalt -----") - print(company_data.get("full_infobox", "k.A.")) - print("----------------------------------------") + + print(f"✅ Aktualisiert: URL: {company_data.get('url', 'k.A.')}, " + f"Branche: {company_data.get('branche', 'k.A.')}, " + f"ChatGPT Umsatz: {chatgpt_umsatz}, Umsatz-Abgleich: {abgleich_result}, " + f"Validierung: {valid_result}, Branchenvorschlag: {branche_result['branch']}") time.sleep(Config.RETRY_DELAY) if __name__ == "__main__": @@ -541,4 +649,4 @@ if __name__ == "__main__": num_rows = None processor = DataProcessor() processor.process_rows(num_rows) - print(f"\n✅ Wikipedia-Auswertung abgeschlossen ({Config.VERSION})") \ No newline at end of file + print(f"\n✅ Wikipedia-Auswertung abgeschlossen ({Config.VERSION})")