Files
Brancheneinstufung2/readme.md

280 lines
24 KiB
Markdown

# Projekt: Automatisierte Unternehmensbewertung & Lead-Generierung v2.2.1
## 1. Projektübersicht
Dieses Repository enthält eine Suite von Python-Skripten zur automatisierten Anreicherung und Analyse von Unternehmensdaten. Das System ist modular aufgebaut und für den Betrieb in einem Docker-Container ausgelegt.
* **`brancheneinstufung.py`:** Das Kernmodul zur Datenanreicherung (Web, Wikipedia, KI-Analyse).
* **`duplicate_checker.py`:** Ein Modul zur intelligenten Duplikatsprüfung.
* **`generate_marketing_text.py`:** Eine Engine zur Erstellung personalisierter Marketing-Texte.
* **`app.py` & Docker:** Eine fernsteuerbare Schnittstelle via Google Sheets.
## 2. Aktueller Status: **KRITISCHER FEHLER (BLOCKER)**
Das gesamte System ist derzeit **nicht lauffähig**. Ein Inkompatibilitätsproblem zwischen dem bestehenden Code und der installierten Version der `openai`-Python-Bibliothek führt zu einem `ModuleNotFoundError` bei jedem Versuch, eine KI-Funktion aufzurufen. Dies verhindert jegliche Weiterentwicklung und Nutzung.
## 3. Nächster Schritt
**Priorität 1:** Behebung des `openai`-Abhängigkeitskonflikts. Die gewählte Strategie ist ein gezieltes Downgrade der `openai`-Bibliothek auf eine mit dem Code kompatible Version, um die Funktionalität schnellstmöglich wiederherzustellen.
planning.md (v2.2.1)
code
Markdown
# Projektplanung v2.2.1
## 1. Aktueller Stand
* **[X] Architektur & Module:** Alle Kernmodule sind konzipiert und implementiert.
* **[!] System-Blocker:** Ein Versionskonflikt der `openai`-Bibliothek legt das gesamte System lahm. Alle Funktionen, die auf die KI zugreifen, stürzen mit einem `ModuleNotFoundError` ab.
## 2. Strategischer Plan
**Phase 1: Stabilität wiederherstellen (Hotfix)**
* **[ ]** **Schritt 1.1 (Analyse):** Überprüfung aller Code-Stellen, die `openai`-Fehlerklassen importieren oder verwenden, um den Umfang des Problems zu bestätigen.
* **[ ]** **Schritt 1.2 (Downgrade):** Modifikation der `requirements.txt`, um die `openai`-Bibliothek auf eine stabile, kompatible Version (z.B. `0.28.0`) festzuschreiben.
* **[ ]** **Schritt 1.3 (Anwendung):** Neubau des Docker-Images (`docker build`), um die Installation der korrekten Bibliotheksversion zu erzwingen.
* **[ ]** **Schritt 1.4 (Validierung):** Durchführung eines Testlaufs (z.B. `reclassify_branches`), um zu bestätigen, dass der `ModuleNotFoundError` behoben ist und die KI-Aufrufe wieder funktionieren.
**Phase 2: Geplante Weiterentwicklung (nach Hotfix)**
* **[ ]** Finalisierung des Duplikats-Checks.
* **[ ]** Vervollständigung der Wissensbasis und Generierung aller Marketing-Texte.
* **[ ]** (Zukünftig) Planung des Code-Refactorings, um die neue `openai` v1.x API zu unterstützen.
# Automatisierte Unternehmensbewertung & Lead-Generierung
**Version:** 2.1.0 (nach Implementierung des Sync-Moduls)
## Projektbeschreibung
Dieses Projekt automatisiert die Anreicherung von Unternehmensdaten aus einem D365-CRM-System. Es nutzt externe APIs (Google, Wikipedia, OpenAI) und Web-Scraping, um Stammdaten zu validieren, zu ergänzen und neue, marketing-relevante Informationen (z.B. FSM-Pitches) zu generieren. Die Verarbeitung und Speicherung der angereicherten Daten erfolgt in einem Google Sheet.
## Aktueller Status (August 2025)
* **Systemstabilität:** Das System ist nach der Behebung von Inkompatibilitäten mit der OpenAI-Bibliothek stabil und voll lauffähig.
* **Daten-Import:** Ein robuster, intelligenter Synchronisations-Mechanismus (`sync_manager.py`) wurde implementiert. Er gleicht einen vollständigen D365-Excel-Export mit dem Google Sheet ab, aktualisiert Stammdaten nach definierten Fachregeln und markiert Datätze für die Neu-Anreicherung.
* **Kernfunktionen:** Datenanreicherung (Wikipedia, Website-Scraping) und KI-basierte Analysen (Brancheneinstufung, Text-Zusammenfassungen) sind operational.
* **Nächster Schritt:** Implementierung des Daten-Exports aus dem Google Sheet zur Aktualisierung des D365-Systems.
## Duplicate Checker (duplicate_checker_old.py)
### Hauptfunktion
Das Skript `duplicate_checker_old.py` (Version 2.15) ist ein spezialisiertes Werkzeug zur Identifizierung von potenziellen Duplikaten zwischen zwei Unternehmenslisten in Google Sheets: einer Matching-Liste (`Matching_Accounts`) und einer Referenz-CRM-Liste (`CRM_Accounts`). Es verwendet einen gewichteten, heuristischen Algorithmus, um für jeden Eintrag in der Matching-Liste den wahrscheinlichsten Treffer im CRM-Bestand zu finden und bewertet diesen mit einem numerischen Score.
### Abhängigkeiten
- **`pandas`**: Zur Datenmanipulation und -analyse.
- **`thefuzz`**: Für Fuzzy-String-Vergleiche zur Bewertung der Namensähnlichkeit.
- **`gspread`, `oauth2client`**: Für die Interaktion mit der Google Sheets API.
- **Lokale Module**:
- `helpers.py`: Stellt Normalisierungsfunktionen (`normalize_company_name`, `simple_normalize_url`) und eine optionale Web-Suche (`serp_website_lookup`) bereit.
- `config.py`: Zentralisiert Konfigurationswerte und API-Schlüssel.
- `google_sheet_handler.py`: Kapselt die Logik für den Zugriff auf Google Sheets.
### Konfiguration
Die Logik des Skripts wird durch mehrere Konstanten am Anfang der Datei gesteuert:
- **Sheet-Namen**: `CRM_SHEET_NAME` und `MATCHING_SHEET_NAME`.
- **Score-Schwellenwerte**: `SCORE_THRESHOLD` (Standard: 80) und `SCORE_THRESHOLD_WEAK` (95), ein strengerer Wert für Treffer ohne starke Indikatoren wie Domain- oder Standortübereinstimmung.
- **Penalties**: `CITY_MISMATCH_PENALTY` (30) und `COUNTRY_MISMATCH_PENALTY` (40) werden vom Score abgezogen, wenn Standorte voneinander abweichen.
- **Prefiltering**: `PREFILTER_MIN_PARTIAL` (70) und `PREFILTER_LIMIT` (30) zur Vorauswahl potenzieller Kandidaten, um die Performance zu verbessern.
- **Stop-Wörter**: `STOP_TOKENS_BASE` und `CITY_TOKENS` (dynamisch generiert) enthalten Begriffe, die bei Namensvergleichen ignoriert werden, um die Signalqualität zu erhöhen.
### Ablauf-Logik
1. **Initialisierung**: Das Skript richtet das Logging ein, lädt API-Schlüssel (optional für SerpAPI) und initialisiert den `GoogleSheetHandler`.
2. **Daten laden**: Die Daten aus den beiden Google Sheets (`CRM_Accounts` und `Matching_Accounts`) werden in Pandas DataFrames geladen.
3. **SerpAPI-Fallback (Optional)**: Für Einträge in der Matching-Liste ohne Website wird versucht, über die SerpAPI eine URL zu finden. Das Vertrauen in die gefundene URL wird bewertet (`hoch`, `mittel`, `niedrig`).
4. **Normalisierung**: Unternehmensnamen, Domains, Orte und Länder in beiden DataFrames werden standardisiert (z.B. Kleinschreibung, Entfernung von Rechtsformzusätzen).
5. **Index-Erstellung**: Zur Optimierung der Suche werden mehrere "Blocking"-Indizes aus den CRM-Daten erstellt:
- Ein `domain_index` für schnelle Suchen über die Website-Domain.
- Ein `token_index` für die Suche nach einzelnen Namensbestandteilen.
- Eine `token_freq` Zählung, um seltene und damit aussagekräftige Namensbestandteile zu identifizieren.
6. **Iteratives Matching**: Das Skript durchläuft jeden Datensatz der Matching-Liste:
a. **Kandidatenauswahl**: Anstatt jeden Eintrag mit der gesamten CRM-Liste zu vergleichen, wird eine kleine, relevante Untergruppe von Kandidaten ausgewählt. Die Auswahl erfolgt priorisiert: zuerst über Domain-Übereinstimmung, dann über den seltensten Namens-Token und zuletzt über einen allgemeinen Prefilter.
b. **Scoring**: Jeder Kandidat wird mit dem aktuellen Matching-Datensatz verglichen. Die Funktion `calculate_similarity` berechnet einen Score basierend auf einer gewichteten Formel, die Namensähnlichkeit, Domain-Match, Standortübereinstimmung, Boni und Strafen berücksichtigt.
c. **Bester Treffer**: Der Kandidat mit dem höchsten Score wird als potenzielles Duplikat ausgewählt.
7. **Ergebnis-Aggregation**: Die Ergebnisse (bester Treffer, Score, Begründung der Bewertung) werden gesammelt.
8. **Daten zurückschreiben**: Die Matching-Liste wird um die Ergebnisspalten (`Match`, `Score`, `Match_Grund`) erweitert und vollständig in das Google Sheet `Matching_Accounts` zurückgeschrieben. Ein lokales CSV-Backup wird ebenfalls erstellt.
## brancheneinstufung2.py
### Hauptfunktion
Das Skript `brancheneinstufung2.py` ist der zentrale Einstiegspunkt und Orchestrator für die Datenanreicherungs-Pipeline. Es dient nicht der direkten Implementierung der Verarbeitungslogik, sondern dem Parsen von Kommandozeilen-Argumenten, der Initialisierung von Handler-Klassen (`GoogleSheetHandler`, `WikipediaScraper`, `DataProcessor`, `SyncManager`) und dem Starten des vom Benutzer ausgewählten Verarbeitungsmodus. Das Skript ist hochgradig modular und delegiert die eigentliche Arbeit an die `DataProcessor`-Klasse.
### Abhängigkeiten
- **Standardbibliotheken**: `logging`, `os`, `argparse`, `time`, `datetime`.
- **Lokale Module**:
- `config.py`: Stellt globale Konfigurationsparameter und die Projektversion bereit.
- `helpers.py`: Bietet Hilfsfunktionen, z.B. für das Erstellen von Log-Dateinamen und das Initialisieren des Branchenschemas.
- `google_sheet_handler.py`: Kapselt die gesamte Kommunikation mit der Google Sheets API.
- `wikipedia_scraper.py`: Stellt Methoden zum Suchen und Parsen von Wikipedia-Artikeln bereit.
- `data_processor.py`: Enthält die Kernlogik für alle Datenverarbeitungsschritte.
- `sync_manager.py`: Implementiert die Logik zum Abgleich von CRM-Exporten mit dem Google Sheet.
### Wichtige Funktionen/Methoden
Die Logik des Skripts ist primär in der `main()`-Funktion enthalten und lässt sich in folgende Schritte unterteilen:
1. **Argumenten-Parsing**: Mittels `argparse` wird die Kommandozeile ausgewertet. Der wichtigste Parameter ist `--mode`, der den auszuführenden Prozess festlegt (z.B. `sync`, `full_run`, `reeval`, `predict_technicians`). Weitere Parameter wie `--limit` oder `--start_sheet_row` erlauben eine feingranulare Steuerung der zu verarbeitenden Datenmenge.
2. **Interaktiver Modus**: Wird kein `--mode` übergeben, startet ein interaktiver Modus, in dem der Benutzer aus einer Liste aller verfügbaren Modi auswählen kann.
3. **Initialisierung**: Basierend auf dem gewählten Modus werden die notwendigen Klassen instanziiert. Für die meisten Anreicherungs-Modi wird ein `DataProcessor`-Objekt erstellt, das wiederum Instanzen des `GoogleSheetHandler` und `WikipediaScraper` erhält. Für den `sync`-Modus wird der `SyncManager` verwendet.
4. **Modus-Dispatching**: Eine `if/elif/else`-Struktur leitet die Ausführung an die passende Methode weiter.
- **`sync` / `simulate_sync`**: Ruft den `SyncManager` auf, um einen D365-Excel-Export mit dem Google Sheet abzugleichen.
- **`full_run`**: Startet einen sequentiellen Anreicherungsprozess für Zeilen, die noch nicht verarbeitet wurden.
- **`reeval`**: Verarbeitet Zeilen, die explizit für eine Neubewertung markiert wurden.
- **`reclassify_branches`**: Führt eine Neubewertung der Branchenzuordnung für alle oder eine Teilmenge der Zeilen durch.
- **`train_technician_model` / `predict_technicians`**: Steuert das Training und die Anwendung eines Machine-Learning-Modells zur Vorhersage von Techniker-Anzahlen.
- **Dynamische Aufrufe**: Viele Modi (z.B. `wiki_verify`, `website_scraping`) werden dynamisch aufgerufen, indem Methoden des `DataProcessor`-Objekts ausgeführt werden, deren Namen dem Modus entsprechen (z.B. `process_wiki_verify`).
5. **Fehlerbehandlung und Logging**: Das gesamte Skript ist von einem `try...except...finally`-Block umschlossen, der Fehler abfängt, protokolliert und sicherstellt, dass das Logging am Ende sauber beendet wird.
## Kernlogik (data_processor.py)
Die Klasse `DataProcessor` ist das Herzstück der Anreicherungslogik und enthält alle Methoden zur schrittweisen Verarbeitung von Unternehmensdaten.
### `setup()`
- **Zweck:** Initialisiert den `DataProcessor`, indem das Ziel-Branchenschema geladen und das trainierte Machine-Learning-Modell für die Technikerschätzung in den Speicher geladen wird.
- **Input:** Keine direkten Argumente, greift aber auf die Konfigurationsdateien (`ziel_Branchenschema.csv`, `technician_decision_tree_model.pkl` etc.) zu.
- **Output:** Gibt `True` bei Erfolg zurück und setzt das interne Flag `is_setup_complete`. Bei Fehlern wird `False` zurückgegeben und das Skript beendet.
### `process_rows_sequentially(...)`
- **Zweck:** Führt den vollständigen, schrittweisen Anreicherungsprozess für einen definierten Bereich von Zeilen im Google Sheet aus. Dies ist der Hauptmodus für die initiale Verarbeitung neuer Daten.
- **Input:** `start_sheet_row` (Startzeile), `num_to_process` (Anzahl der Zeilen), sowie boolesche Flags (`process_wiki_steps`, `process_chatgpt_steps`, etc.) zur Steuerung der auszuführenden Anreicherungsschritte.
- **Output:** Die Methode hat keinen direkten Rückgabewert, aber ihr Seiteneffekt ist die Aktualisierung der verarbeiteten Zeilen im Google Sheet mit den angereicherten Daten.
### `process_reevaluation_rows(...)`
- **Zweck:** Führt den vollständigen Anreicherungsprozess gezielt für Zeilen aus, die im Google Sheet manuell mit einem 'x' in der "ReEval Flag"-Spalte markiert wurden. Vor der Neubewertung werden alle zuvor abgeleiteten Daten in der Zeile gelöscht.
- **Input:** `row_limit` (maximale Anzahl zu verarbeitender Zeilen), `clear_flag` (ob das 'x'-Flag nach der Verarbeitung entfernt werden soll) und die booleschen Flags zur Schritt-Steuerung.
- **Output:** Aktualisiert die markierten Zeilen im Google Sheet mit neu angereicherten Daten.
### `process_website_scraping(...)`
- **Zweck:** Führt einen Batch-Prozess ausschließlich für das Scrapen von Websites durch. Die Methode identifiziert Zeilen, in denen der "Website Scrape Timestamp" fehlt, und extrahiert parallel den Rohtext und die Meta-Details der jeweiligen Unternehmens-Websites.
- **Input:** `start_sheet_row`, `end_sheet_row`, `limit` zur Eingrenzung des Verarbeitungsbereichs.
- **Output:** Schreibt den extrahierten Rohtext, Meta-Details, einen Status zur URL-Prüfung und einen Zeitstempel in die entsprechenden Spalten im Google Sheet.
### `process_summarize_website(...)`
- **Zweck:** Führt einen Batch-Prozess zur Zusammenfassung von bereits extrahierten Website-Rohtexten mittels KI durch.
- **Input:** `start_sheet_row`, `end_sheet_row`, `limit`. Die Methode verarbeitet Zeilen, bei denen der Rohtext vorhanden, aber die Zusammenfassung noch leer ist.
- **Output:** Schreibt die KI-generierte Zusammenfassung in die Spalte "Website Zusammenfassung" im Google Sheet.
### `process_branch_batch(...)` / `reclassify_all_branches(...)`
- **Zweck:** Führt eine (Neu-)Bewertung der Branchenzugehörigkeit für einen Zeilenbereich im Batch-Verfahren durch. Die Methode sammelt relevante Informationen (CRM-Daten, Website-Zusammenfassung, Wikipedia-Inhalte) und sendet sie gebündelt an die KI, um eine effiziente und konsistente Brancheneinstufung zu erhalten.
- **Input:** `start_sheet_row`, `end_sheet_row`, `limit`.
- **Output:** Aktualisiert die Spalten zur KI-basierten Brancheneinstufung ("Chat Vorschlag Branche", Konfidenz, Begründung etc.) im Google Sheet.
### `process_wiki_verify(...)`
- **Zweck:** Verifiziert in einem Batch-Prozess, ob der in einer Zeile hinterlegte Wikipedia-Artikel thematisch zum Unternehmen passt. Nutzt KI, um die Konsistenz zu prüfen und ggf. einen passenderen Artikel vorzuschlagen.
- **Input:** `start_sheet_row`, `end_sheet_row`, `limit`. Verarbeitet Zeilen, die eine Wiki-URL, aber noch keinen Verifizierungs-Timestamp haben.
- **Output:** Schreibt das Ergebnis der KI-Prüfung (OK, X), eine Begründung und ggf. einen Alternativvorschlag in die entsprechenden Spalten im Google Sheet.
### `process_find_wiki_serp(...)`
- **Zweck:** Sucht für große Unternehmen (definiert über Mindestumsatz/-mitarbeiter), bei denen noch keine Wikipedia-URL bekannt ist, über eine Google-Suche (SerpAPI) nach einem passenden Wikipedia-Artikel.
- **Input:** `start_sheet_row`, `end_sheet_row`, `limit`, `min_employees`, `min_umsatz`.
- **Output:** Wenn eine passende URL gefunden wird, wird diese in die "Wiki URL"-Spalte eingetragen und die Zeile für eine Neubewertung (`ReEval Flag`) markiert.
### `process_contact_search(...)`
- **Zweck:** Führt eine Suche nach LinkedIn-Kontakten für bestimmte Positionen (z.B. Serviceleiter, IT-Leiter) bei den Unternehmen im Sheet durch.
- **Input:** `start_sheet_row`, `end_sheet_row`, `limit`. Verarbeitet Zeilen, die noch keinen "Contact Search Timestamp" haben.
- **Output:** Schreibt die Anzahl der gefundenen Kontakte pro Kategorie in die "Linked... gefunden"-Spalten und speichert detaillierte Kontaktinformationen in einem separaten "Contacts"-Tabellenblatt.
### `train_technician_model()`
- **Zweck:** Bereitet die vorhandenen Daten auf, trainiert ein Machine-Learning-Modell (RandomForest) zur Vorhersage von Servicetechniker-Anzahlen, führt ein Hyperparameter-Tuning durch und speichert das trainierte Modell sowie den zugehörigen Imputer als `.pkl`-Dateien.
- **Input:** Keine direkten Argumente. Die Methode liest die Trainingsdaten aus dem konfigurierten Google Sheet.
- **Output:** Erstellt und speichert die `technician_decision_tree_model.pkl`- und `median_imputer.pkl`-Dateien sowie eine JSON-Datei mit den verwendeten Features.
### `process_predict_technicians(...)`
- **Zweck:** Wendet das trainierte ML-Modell auf Zeilen an, für die noch keine Techniker-Schätzung vorliegt, aber die notwendigen Input-Features (Umsatz, Mitarbeiter, Branche) vorhanden sind.
- **Input:** `start_sheet_row`, `end_sheet_row`, `limit`.
- **Output:** Schreibt den vorhergesagten Techniker-Bucket (z.B. "Techniker_Klein (0-49)") in die Spalte "Geschaetzter Techniker Bucket".
## Hilfsfunktionen (helpers.py)
Diese Datei enthält eine Sammlung von globalen, wiederverwendbaren Hilfsfunktionen, die in verschiedenen Modulen des Projekts verwendet werden.
### Decorators
#### `retry_on_failure(func)`
- **Zweck:** Ein Decorator, der eine Funktion bei bestimmten, temporären Fehlern (z.B. Netzwerkprobleme, API-Rate-Limits) automatisch mehrmals ausführt. Er verwendet eine exponentielle Backoff-Strategie, um die Wartezeit zwischen den Versuchen zu erhöhen.
- **Input:** Eine Funktion, die dekoriert werden soll.
- **Output:** Das Ergebnis der dekorierten Funktion oder löst eine Ausnahme aus, wenn alle Wiederholungsversuche fehlschlagen.
### Logging & Token Counting
#### `token_count(text, model=None)`
- **Zweck:** Zählt die Anzahl der Tokens in einem gegebenen Text. Verwendet die `tiktoken`-Bibliothek für eine genaue Zählung, falls verfügbar, andernfalls schätzt sie die Anzahl basierend auf Leerzeichen.
- **Input:** `text` (der zu analysierende String), `model` (optional, das zu verwendende KI-Modell).
- **Output:** Eine Ganzzahl, die die Anzahl der Tokens darstellt.
#### `create_log_filename(mode)`
- **Zweck:** Erstellt einen standardisierten, zeitgestempelten Dateinamen für Log-Dateien.
- **Input:** `mode` (ein String, der den aktuellen Ausführungsmodus beschreibt, z.B. 'full_run').
- **Output:** Ein String, der den vollständigen Pfad zur Log-Datei enthält (z.B. `Log/2025-11-07_10-30_v221_Modus-full_run.txt`).
### Text-, String- & URL-Utilities
#### `simple_normalize_url(url)`
- **Zweck:** Bereinigt und normalisiert eine URL auf ihre Kern-Domain (z.B. `https://www.beispiel.de/path` -> `beispiel.de`).
- **Input:** `url` (ein String mit einer URL).
- **Output:** Ein normalisierter Domain-String oder "k.A." bei ungültiger Eingabe.
#### `normalize_string(s)`
- **Zweck:** Standardisiert einen String, indem Umlaute (ä -> ae) und gängige Sonderzeichen ersetzt werden.
- **Input:** `s` (ein beliebiger String).
- **Output:** Der normalisierte String.
#### `clean_text(text)`
- **Zweck:** Bereinigt einen Text von unerwünschten Artefakten, die typischerweise beim Scrapen von Websites oder Wikipedia auftreten (z.B. `[1]`, `[Bearbeiten]`, überflüssige Leerzeichen).
- **Input:** `text` (ein String).
- **Output:** Der bereinigte Text.
#### `normalize_company_name(name)`
- **Zweck:** Normalisiert einen Firmennamen, indem gängige Rechtsformzusätze (GmbH, AG, etc.) und andere generische Begriffe entfernt werden, um Vergleiche zu erleichtern.
- **Input:** `name` (ein Firmenname als String).
- **Output:** Der normalisierte Firmenname in Kleinbuchstaben.
#### `extract_numeric_value(raw_value, is_umsatz=False)`
- **Zweck:** Extrahiert und normalisiert einen numerischen Wert aus einem unstrukturierten String. Kann Einheiten wie "Mio.", "Mrd." oder "Tsd." interpretieren und in einen Basiswert umrechnen.
- **Input:** `raw_value` (ein String, z.B. "ca. 250 Mio. EUR"), `is_umsatz` (ein Flag, das die Umrechnung für Umsätze steuert, z.B. Rückgabe in Millionen).
- **Output:** Ein String mit der normalisierten Zahl (z.B. "250") oder "k.A.".
### API Wrappers & Externe Dienste
#### `call_openai_chat(...)`
- **Zweck:** Eine zentrale Wrapper-Funktion für Aufrufe an die OpenAI Chat-API. Kapselt die Authentifizierung, die Fehlerbehandlung und den eigentlichen API-Aufruf.
- **Input:** `prompt` (der an die KI gesendete Text), `temperature` (steuert die Kreativität der Antwort), `model` (das zu verwendende KI-Modell).
- **Output:** Der von der KI generierte Antwort-Text als String.
#### `summarize_website_content(raw_text, company_name)`
- **Zweck:** Nutzt die KI, um den Rohtext einer Website zu analysieren und eine strukturierte Zusammenfassung des Geschäftsmodells und des Potenzials für Field Service Management (FSM) zu erstellen.
- **Input:** `raw_text` (der Inhalt der Website), `company_name` (Name des Unternehmens).
- **Output:** Ein formatierter String, der das Geschäftsmodell, das FSM-Potenzial und Belegsätze enthält.
#### `evaluate_branche_chatgpt(...)`
- **Zweck:** Führt eine KI-basierte Brancheneinstufung für ein einzelnes Unternehmen durch. Sendet ein Unternehmensprofil und ein vordefiniertes Branchenschema an die KI.
- **Input:** `company_name`, `website_summary`, `wiki_absatz`.
- **Output:** Ein Dictionary mit der vorgeschlagenen "Branche", "Konfidenz" und "Begruendung".
#### `evaluate_branches_batch(companies_data)`
- **Zweck:** Führt die Brancheneinstufung für eine Liste von Unternehmen in einem einzigen API-Aufruf durch, um die Effizienz zu steigern.
- **Input:** `companies_data` (eine Liste von Dictionaries, die Unternehmensprofile enthalten).
- **Output:** Eine Liste von Dictionaries mit den Ergebnissen für jedes Unternehmen.
#### `generate_fsm_pitch(...)`
- **Zweck:** Generiert einen hochpersonalisierten, einleitenden Satz für eine Marketing-E-Mail (FSM-Pitch), basierend auf den gesammelten Unternehmensdaten.
- **Input:** Diverse Unternehmensdaten wie Name, Branche, Zusammenfassungen und Mitarbeiter-/Technikerzahlen.
- **Output:** Ein einzelner, prägnanter Satz als String.
#### `serp_website_lookup(company_name)`
- **Zweck:** Verwendet die SerpAPI (Google-Suche), um die offizielle Website eines Unternehmens zu finden. Filtert dabei unzuverlässige Quellen wie soziale Medien oder Nachrichtenportale heraus.
- **Input:** `company_name`.
- **Output:** Die normalisierte URL der gefundenen Website oder "k.A.".
#### `search_linkedin_contacts(...)`
- **Zweck:** Führt eine gezielte Google-Suche über die SerpAPI durch, um LinkedIn-Profile von Mitarbeitern in bestimmten Positionen (z.B. "Serviceleiter") bei einem Unternehmen zu finden.
- **Input:** `company_name`, `website`, `position_query` (z.B. "Leiter Kundendienst"), `crm_kurzform`.
- **Output:** Eine Liste von Dictionaries, die die gefundenen Kontakte mit Namen, Position und LinkedIn-URL enthalten.
### Website Scraping & Validierung
#### `get_website_raw(url, ...)`
- **Zweck:** Lädt den reinen Textinhalt von einer Webseite. Die Funktion ist gehärtet, um mit verschiedenen Fehlern (SSL, Timeout, Connection Errors) umzugehen und versucht, Cookie-Banner intelligent zu entfernen.
- **Input:** `url` (die zu scrapende URL).
- **Output:** Der extrahierte Text der Website als String oder ein Fehlerhinweis (z.B. "k.A. (Timeout)").
#### `is_valid_wikipedia_article_url(url)`
- **Zweck:** Überprüft, ob eine gegebene URL tatsächlich auf einen existierenden Wikipedia-Artikel verweist und nicht auf eine "Seite existiert nicht"-Seite.
- **Input:** `url` (die zu prüfende Wikipedia-URL).
- **Output:** `True`, wenn der Artikel existiert, andernfalls `False`.