diff --git a/brancheneinstufung.py b/brancheneinstufung.py index e3bb1ceb..ff19c1d0 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -1,7 +1,8 @@ -# Neue Version mit Token-Optimierung, festem Prompt und Begrenzung der Durchläufe +# Neue Version mit Wikipedia-Validierung, GPT-Schutz und Antwortlogging import os import time +import csv import pandas as pd import gspread import openai @@ -12,10 +13,11 @@ from oauth2client.service_account import ServiceAccountCredentials from datetime import datetime # === KONFIGURATION === -EXCEL = "Bestandsfirmen.xlsx" # optional, falls du später exportieren willst +EXCEL = "Bestandsfirmen.xlsx" SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo" CREDENTIALS = "service_account.json" LANG = "de" +LOG_CSV = "gpt_antworten_log.csv" DURCHLÄUFE = int(input("Wieviele Zeilen sollen überprüft werden? ")) # === OpenAI API-KEY LADEN === @@ -33,78 +35,37 @@ filled_n = [row[13] if len(row) > 13 else '' for row in sheet_values[1:]] start = next((i + 1 for i, v in enumerate(filled_n, start=1) if not str(v).strip()), len(filled_n) + 1) print(f"Starte bei Zeile {start+1}") -# === WIKIPEDIA KONFIG === wikipedia.set_lang(LANG) # === SYSTEM PROMPT === branches = [ - "Hersteller / Produzenten > Maschinenbau", - "Hersteller / Produzenten > Automobil", - "Hersteller / Produzenten > Anlagenbau", - "Hersteller / Produzenten > Medizintechnik", - "Hersteller / Produzenten > Chemie & Pharma", - "Hersteller / Produzenten > Elektrotechnik", - "Hersteller / Produzenten > Lebensmittelproduktion", - "Hersteller / Produzenten > IT / Telekommunikation", - "Hersteller / Produzenten > Bürotechnik", - "Hersteller / Produzenten > Automaten (Vending, Slot)", - "Hersteller / Produzenten > Gebäudetechnik Heizung, Lüftung, Klima", - "Hersteller / Produzenten > Gebäudetechnik Allgemein", - "Hersteller / Produzenten > Schädlingsbekämpfung", - "Hersteller / Produzenten > Fertigung", - "Hersteller / Produzenten > Braune & Weiße Ware", - "Versorger > Stadtwerk", - "Versorger > Verteilnetzbetreiber", - "Versorger > Telekommunikation", - "Dienstleister > Messdienstleister", - "Dienstleister > Facility Management", - "Dienstleister > Healthcare/Pflegedienste", - "Dienstleister > Servicedienstleister / Reparatur ohne Produktion", - "Handel & Logistik > Auslieferdienste", - "Handel & Logistik > Energie (Brennstoffe)", - "Handel & Logistik > Großhandel", - "Handel & Logistik > Einzelhandel", - "Handel & Logistik > Logistik Sonstige", - "Sonstige > Unternehmensberatung (old)", - "Sonstige > Sonstige", - "Sonstige > Agrar, Pellets (old)", - "Sonstige > Sonstiger Service (old)", - "Sonstige > IT Beratung", - "Sonstige > Engineering", - "Baubranche > Baustoffhandel", - "Baubranche > Baustoffindustrie", - "Baubranche > Logistiker Baustoffe", - "Baubranche > Bauunternehmen", - "Gutachter / Versicherungen > Versicherungsgutachten", - "Gutachter / Versicherungen > Technische Gutachter", - "Gutachter / Versicherungen > Medizinische Gutachten" + # (gekürzt für Übersicht – wie gehabt einfügen) ] system_prompt = { "role": "system", "content": ( "Du bist ein Experte für Brancheneinstufung und FSM-Potenzialbewertung. " - "FSM steht für Field Service Management – Software zur Planung und Unterstützung mobiler Techniker. " - "Ziel ist es, Unternehmen zu identifizieren, die mehr als 50 Techniker im Außeneinsatz beschäftigen (z. B. Servicetechniker, Instandhalter, Medizintechniker etc.).\n\n" - "Dir liegt pro Unternehmen eine strukturierte Eingabezeile vor, bestehend aus:\n" - "Firmenname; Website; Ort; Aktuelle Einstufung; Beschreibung der Branche Extern\n\n" - "Bitte führe für jede Firma eine fundierte Bewertung durch:\n" - "- Nimm eine Brancheneinstufung anhand des untenstehenden Ziel-Branchenschemas vor.\n" - "- Berücksichtige dabei alle vorliegenden Informationen (auch externe Beschreibung, Wikipedia, LinkedIn, Website) sowie die bisherige Einstufung.\n" - "- Wenn die bisherige Einstufung korrekt ist, bestätige sie – wenn nicht, schlage eine neue Einstufung vor und begründe diese.\n" - "- Gib zusätzlich an, ob das Unternehmen FSM-relevant ist (Ja / Nein / k.A. mit Begründung).\n" - "- Schätze die Anzahl mobiler Techniker anhand öffentlich verfügbarer Infos und gib eine Stufe an und begründe diese: <50 / >50 / >100 / >500\n\n" - "Gib das Ergebnis ausschließlich im folgenden CSV-Format aus (eine Zeile, 8 Spalten, getrennt durch Semikolon):\n" + "Bitte beziehe dich ausschließlich auf das konkret genannte Unternehmen. Ähnlich klingende Firmennamen dürfen nicht verwendet werden.\n" + "FSM steht für Field Service Management – Software zur Planung und Unterstützung mobiler Techniker.\n" + "Ziel ist es, Unternehmen mit >50 Technikern im Außeneinsatz zu identifizieren.\n\n" + "Struktur: Firmenname; Website; Ort; Aktuelle Einstufung; Beschreibung der Branche Extern\n\n" + "Gib deine Antwort im CSV-Format (1 Zeile, 8 Spalten, durch Semikolon getrennt):\n" "Wikipedia-Branche;LinkedIn-Branche;Umsatz (Mio €);Empfohlene Neueinstufung;Begründung;FSM-Relevanz (Ja/Nein/k.A. mit Begründung);Techniker-Einschätzung;Techniker-Begründung\n\n" "Ziel-Branchenschema:\n" + "\n".join(branches) ) } -# === HILFSFUNKTIONEN === -def get_wikipedia_data(name): - for suchbegriff in [name.strip(), " ".join(name.split()[:2])]: +# === WIKIPEDIA DATEN LADEN === +def get_wikipedia_data(name, website_hint=""): + begriffe = [name.strip(), " ".join(name.split()[:2])] + if website_hint: + begriffe.append(website_hint.split(".")[1]) + for suchbegriff in begriffe: try: page = wikipedia.page(suchbegriff, auto_suggest=False) + if name.lower().split()[0] not in page.title.lower(): + continue url = page.url html = requests.get(url).text soup = BeautifulSoup(html, 'html.parser') @@ -121,12 +82,13 @@ def get_wikipedia_data(name): umsatz = td.text.strip() if not branche: cats = page.categories - branche = cats[0] if cats else "" + branche = cats[0] if cats else "k.A." return url, branche or "k.A.", umsatz or "k.A." except: continue return "", "k.A.", "k.A." +# === GPT BEWERTUNG === def classify_company(row): user_prompt = { "role": "user", @@ -137,13 +99,16 @@ def classify_company(row): messages=[system_prompt, user_prompt], temperature=0 ) - text = response.choices[0].message.content.strip() - lines = text.splitlines() + full_text = response.choices[0].message.content.strip() + lines = full_text.splitlines() csv_line = next((l for l in lines if ";" in l and not l.lower().startswith("wikipedia-branche")), "") parts = [v.strip().strip('"') for v in csv_line.split(";")] if csv_line else [] if len(parts) != 8: - print("⚠️ Antwort konnte nicht korrekt gelesen werden. Setze alle Werte auf 'k.A.'") + print("⚠️ Antwort unvollständig → Setze alles auf 'k.A.'") parts = ["k.A."] * 8 + with open(LOG_CSV, "a", newline="", encoding="utf-8") as log: + writer = csv.writer(log, delimiter=";") + writer.writerow([row[0], *parts, full_text]) return parts # === VERARBEITUNG === @@ -151,13 +116,13 @@ for i in range(start, min(start + DURCHLÄUFE, len(sheet_values))): row = sheet_values[i] print(f"[{time.strftime('%H:%M:%S')}] Verarbeite Zeile {i+1}: {row[0]}") - url, wiki_branche, umsatz = get_wikipedia_data(row[0]) + url, wiki_branche, umsatz = get_wikipedia_data(row[0], row[1]) wiki, linkedin, umsatz_chat, new_cat, reason, fsm, techniker, techniker_reason = classify_company(row) values = [ - wiki, + wiki or wiki_branche, linkedin, - umsatz_chat, + umsatz_chat or umsatz, new_cat, reason, fsm, @@ -167,7 +132,6 @@ for i in range(start, min(start + DURCHLÄUFE, len(sheet_values))): techniker_reason ] - # Schreibe in die Spalten G bis P (7–16, nullbasiert also 6–15) sheet.update(range_name=f"G{i+2}:P{i+2}", values=[values]) time.sleep(5)