Add documentation for data processor and helpers
This commit is contained in:
190
readme.md
190
readme.md
@@ -49,7 +49,7 @@ Dieses Projekt automatisiert die Anreicherung von Unternehmensdaten aus einem D3
|
||||
## 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 Datensätze für die Neu-Anreicherung.
|
||||
* **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.
|
||||
|
||||
@@ -90,3 +90,191 @@ Die Logik des Skripts wird durch mehrere Konstanten am Anfang der Datei gesteuer
|
||||
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`.
|
||||
Reference in New Issue
Block a user