- Beschreibt die Hauptfunktion und den Zweck des Moduls. - Dokumentiert die wichtigsten öffentlichen Methoden.
303 lines
26 KiB
Markdown
303 lines
26 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`.
|
|
|
|
## 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.
|