# 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`. ## google_sheet_handler.py ### Hauptfunktion Das Modul `google_sheet_handler.py` dient als zentraler Wrapper für sämtliche Interaktionen mit dem Google Sheet, das als primärer Datenspeicher für das Projekt fungiert. Es abstrahiert die Komplexität der `gspread` API und stellt eine robuste, wiederverwendbare Schnittstelle für Lese- und Schreibvorgänge bereit. Die Klasse `GoogleSheetHandler` kapselt die Verbindungslogik, die Authentifizierung über Service-Accounts und bietet Methoden für spezifische Datenmanipulationen. ### Methodenbeschreibung - `__init__(self, sheet_url=None)`: Der Konstruktor initialisiert den Handler. Er übernimmt optional eine `sheet_url`. Wenn keine URL angegeben wird, greift er auf den Wert aus der `config.py` zurück. - `load_data(self)`: Stellt die Verbindung zum Google Sheet her (falls noch nicht geschehen) und lädt den gesamten Inhalt des Haupt-Arbeitsblatts in den internen Speicher der Klasse. Diese Methode ist mit einem Retry-Decorator versehen, um bei temporären Netzwerkproblemen robust zu sein. - `get_sheet_as_dataframe(self, sheet_name)`: Liest ein spezifisches Arbeitsblatt (über `sheet_name` identifiziert) aus dem Google Sheet und gibt dessen Inhalt als Pandas DataFrame zurück. Dies ist nützlich für datenanalytische Aufgaben. - `append_rows(self, sheet_name, values)`: Fügt eine oder mehrere neue Zeilen am Ende eines bestimmten Arbeitsblatts an. `values` ist dabei eine Liste von Listen (jede innere Liste repräsentiert eine Zeile). - `clear_and_write_data(self, sheet_name, data)`: Löscht den gesamten Inhalt eines Arbeitsblatts und schreibt anschließend neue Daten hinein. Dies ist nützlich, um ein Sheet vollständig zu synchronisieren. - `batch_update_cells(self, update_data)`: Führt eine Stapelverarbeitung von Zell-Updates durch. Diese Methode ist wesentlich performanter als einzelne Zell-Updates, da sie mehrere Änderungen in einer einzigen API-Anfrage bündelt. - `get_main_sheet_name(self)`: Gibt den Namen des Haupt-Arbeitsblatts (typischerweise 'Tabelle1') zurück.