Files
Brancheneinstufung2/config.py
Floke 82106cf636 fix(debug): Add version info and API key debugging
- Adds a version and timestamp to the orchestrator's startup logs to verify code deployment.
- Introduces extensive debug logging in config.py and helpers.py to trace the API key loading process, including exact file paths and environment variable checks. This will help diagnose the persistent 'API Key missing' error.
2026-01-03 09:06:00 +00:00

660 lines
33 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
config.py
Zentrale Konfiguration für das Projekt "Automatisierte Unternehmensbewertung".
Enthält Dateipfade, API-Schlüssel-Pfade, die globale Config-Klasse
und das Spalten-Mapping für das Google Sheet.
"""
import os
import re
import logging
# ==============================================================================
# 1. GLOBALE KONSTANTEN UND DATEIPFADE
# ==============================================================================
# --- Dateipfade (NEU: Absolute Pfade) ---
# Basisverzeichnis des Projekts, in dem sich diese config.py befindet.
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CREDENTIALS_FILE = os.path.join(BASE_DIR, "service_account.json")
API_KEY_FILE = os.path.join(BASE_DIR, "gemini_api_key.txt") # Standard für Gemini
SERP_API_KEY_FILE = os.path.join(BASE_DIR, "serpApiKey.txt")
GENDERIZE_API_KEY_FILE = os.path.join(BASE_DIR, "genderize_API_Key.txt")
BRANCH_MAPPING_FILE = None
LOG_DIR = os.path.join(BASE_DIR, "Log")
# --- ML Modell Artefakte ---
MODEL_FILE = os.path.join(BASE_DIR, "technician_decision_tree_model.pkl")
IMPUTER_FILE = os.path.join(BASE_DIR, "median_imputer.pkl")
PATTERNS_FILE_TXT = os.path.join(BASE_DIR, "technician_patterns.txt") # Alt (Optional beibehalten)
PATTERNS_FILE_JSON = os.path.join(BASE_DIR, "technician_patterns.json") # Neu (Empfohlen)
# Marker für URLs, die erneut per SERP gesucht werden sollen
URL_CHECK_MARKER = "URL_CHECK_NEEDED"
# --- User Agents für Rotation ---
USER_AGENTS = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 13_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0',
'Mozilla/5.0 (X11; Linux i686; rv:108.0) Gecko/20100101 Firefox/108.0',
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:108.0) Gecko/20100101 Firefox/108.0',
]
# ==============================================================================
# 2. VORAB-HELPER FUNKTION (wird von Config-Klasse benötigt)
# ==============================================================================
def normalize_for_mapping(text):
"""
Normalisiert einen String aggressiv für Mapping-Zwecke.
Muss VOR der Config-Klasse definiert werden, da sie dort verwendet wird.
"""
if not isinstance(text, str):
return ""
text = text.lower()
text = text.strip()
text = re.sub(r'[^a-z0-9]', '', text)
return text
# ==============================================================================
# 3. ZENTRALE KONFIGURATIONS-KLASSE
# ==============================================================================
class Config:
"""Zentrale Konfigurationseinstellungen."""
VERSION = "v2.0.0" # Version hochgezählt nach Refactoring
LANG = "de" # Sprache fuer Wikipedia etc.
# ACHTUNG: SHEET_URL ist hier ein Platzhalter. Ersetzen Sie ihn durch Ihre tatsaechliche URL.
SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo" # <<< ERSETZEN SIE DIES!
MAX_RETRIES = 5
RETRY_DELAY = 10
REQUEST_TIMEOUT = 20
SIMILARITY_THRESHOLD = 0.65
DEBUG = True
WIKIPEDIA_SEARCH_RESULTS = 5
HTML_PARSER = "html.parser"
TOKEN_MODEL = "gpt-3.5-turbo"
USER_AGENT = 'Mozilla/5.0 (compatible; UnternehmenSkript/1.0; +https://www.example.com/bot)'
# --- Konfiguration fuer Batching & Parallelisierung ---
PROCESSING_BATCH_SIZE = 20
OPENAI_BATCH_SIZE_LIMIT = 4
MAX_SCRAPING_WORKERS = 10
UPDATE_BATCH_ROW_LIMIT = 50
MAX_BRANCH_WORKERS = 10
OPENAI_CONCURRENCY_LIMIT = 3
PROCESSING_BRANCH_BATCH_SIZE = 20
SERPAPI_DELAY = 1.5
# --- Plausibilitäts-Schwellenwerte ---
PLAUSI_UMSATZ_MIN_WARNUNG = 50000
PLAUSI_UMSATZ_MAX_WARNUNG = 200000000000
PLAUSI_MA_MIN_WARNUNG_ABS = 1
PLAUSI_MA_MIN_WARNUNG_BEI_UMSATZ = 3
PLAUSI_UMSATZ_MIN_SCHWELLE_FUER_MA_CHECK = 1000000
PLAUSI_MA_MAX_WARNUNG = 1000000
PLAUSI_RATIO_UMSATZ_PRO_MA_MIN = 25000
PLAUSI_RATIO_UMSATZ_PRO_MA_MAX = 1500000
PLAUSI_ABWEICHUNG_CRM_WIKI_PROZENT = 30
# --- Mapping für Länder-Codes ---
# Übersetzt D365 Country Codes in die im GSheet verwendete Langform.
# WICHTIG: Die Schlüssel (Codes) sollten in Kleinbuchstaben sein für einen robusten Vergleich.
COUNTRY_CODE_MAP = {
'de': 'Deutschland',
'gb': 'Vereinigtes Königreich',
'ch': 'Schweiz',
'at': 'Österreich',
'it': 'Italien',
'es': 'Spanien',
'dk': 'Dänemark',
'hu': 'Ungarn',
'se': 'Schweden',
'fr': 'Frankreich',
'us': 'USA',
'br': 'Brasilien',
'cz': 'Tschechien',
'au': 'Australien',
'mx': 'Mexiko',
'nl': 'Niederlande',
'pl': 'Polen',
'be': 'Belgien',
'sk': 'Slowakei',
'nz': 'Neuseeland',
'in': 'Indien',
'li': 'Liechtenstein',
'ae': 'Vereinigte Arabische Emirate',
'ru': 'Russland',
'jp': 'Japan',
'ro': 'Rumänien',
'is': 'Island',
'lu': 'Luxemburg',
'me': 'Montenegro',
'ph': 'Philippinen',
'fi': 'Finnland',
'no': 'Norwegen',
'ma': 'Marokko',
'hr': 'Kroatien',
'ca': 'Kanada',
'ua': 'Ukraine',
'sb': 'Salomonen',
'za': 'Südafrika',
'ee': 'Estland',
'cn': 'China',
'si': 'Slowenien',
'lt': 'Litauen',
}
# --- Branchen-Gruppen Mapping (v2.0 - Angereichert mit Definitionen & Beispielen) ---
# Single Source of Truth für alle Branchen.
BRANCH_GROUP_MAPPING = {
"Maschinenbau": {
"gruppe": "Hersteller / Produzenten",
"definition": "Herstellung von zumeist größeren und komplexen Maschinen. Abgrenzung: Keine Anlagen wie z.B. Aufzüge, Rolltreppen oder komplette Produktionsstraßen.",
"beispiele": "EBM Papst, Kärcher, Winterhalter, Testo, ZwickRoell, Koch Pac, Uhlmann, BHS, Schlie, Kasto, Chiron",
"d365_branch_detail": "Maschinenbau"
},
"Automobil": {
"gruppe": "Hersteller / Produzenten",
"definition": "Hersteller von (Spezial)-Fahrzeugen, die meist in ihrer Bewegung eingeschränkt sind (z.B. Mähdrescher, Pistenraupen). Abgrenzung: Keine Autohändler oder Service an PKWs.",
"beispiele": "Kässbohrer, Aebi Schmidt, Pesko, Nova, PV Automotive",
"d365_branch_detail": "Automobil"
},
"Anlagenbau": {
"gruppe": "Hersteller / Produzenten",
"definition": "Hersteller von komplexen Anlagen, die fest beim Kunden installiert werden (z.B. Fertigungsanlagen) und oft der Herstellung nachgelagerter Erzeugnisse dienen. Abgrenzung: Keine Aufzugsanlagen, keine Rolltreppen.",
"beispiele": "Yaskawa, Good Mills, Jungheinrich, Abus, BWT",
"d365_branch_detail": "Anlagenbau"
},
"Medizintechnik": {
"gruppe": "Hersteller / Produzenten",
"definition": "Hersteller von medizinischen Geräten für Krankenhäuser, (Zahn-)Arztpraxen oder den Privatbereich. Abgrenzung: Keine reinen Dienstleister/Pflegedienste.",
"beispiele": "Carl Zeiss, MMM, Olympus, Sysmex, Henry Schein, Dental Bauer, Vitalaire",
"d365_branch_detail": "Medizintechnik"
},
"Chemie & Pharma": {
"gruppe": "Hersteller / Produzenten",
"definition": "Unternehmen, die chemische oder pharmazeutische Erzeugnisse herstellen. Abgrenzung: Keine Lebensmittel.",
"beispiele": "Brillux",
"d365_branch_detail": "Chemie & Pharma"
},
"Elektrotechnik": {
"gruppe": "Hersteller / Produzenten",
"definition": "Hersteller von Maschinen und Geräten, die sich hauptsächlich durch elektrische Komponenten auszeichnen.",
"beispiele": "Triathlon, SBS BatterieSystem",
"d365_branch_detail": "Elektrotechnik"
},
"Lebensmittelproduktion": {
"gruppe": "Hersteller / Produzenten",
"definition": "Unternehmen, die Lebensmittel im industriellen Maßstab produzieren.",
"beispiele": "Ferrero, Lohmann, Mars, Fuchs, Teekanne, Frischli",
"d365_branch_detail": "Lebensmittelproduktion"
},
"IT / Telekommunikation": {
"gruppe": "Hersteller / Produzenten",
"definition": "Hersteller von Telekommunikations-Hardware und -Equipment. Abgrenzung: Keine Telekommunikations-Netzbetreiber.",
"beispiele": "NDI Nordisk Daek Import Danmark",
"d365_branch_detail": "IT / Telekommunikation"
},
"Bürotechnik": {
"gruppe": "Hersteller / Produzenten",
"definition": "Hersteller von Geräten für die Büro-Infrastruktur wie Drucker, Kopierer oder Aktenvernichter.",
"beispiele": "Ricoh, Rosskopf",
"d365_branch_detail": "Bürotechnik"
},
"Automaten (Vending / Slot)": {
"gruppe": "Hersteller / Produzenten",
"definition": "Reine Hersteller von Verkaufs-, Service- oder Spielautomaten, die mitunter einen eigenen Kundenservice haben.",
"beispiele": "Coffema, Melitta, Tchibo, Selecta",
"d365_branch_detail": "Automaten (Vending, Slot)"
},
"Gebäudetechnik Heizung / Lüftung / Klima": {
"gruppe": "Hersteller / Produzenten",
"definition": "Reine Hersteller von Heizungs-, Lüftungs- und Klimaanlagen (HLK), die mitunter einen eigenen Kundenservice haben.",
"beispiele": "Wolf, ETA, Fröling, Ochsner, Windhager, DKA",
"d365_branch_detail": "Gebäudetechnik Heizung, Lüftung, Klima"
},
"Gebäudetechnik Allgemein": {
"gruppe": "Hersteller / Produzenten",
"definition": "Hersteller von Produkten, die fest in Gebäuden installiert werden (z.B. Sicherheitstechnik, Türen, Sonnenschutz).",
"beispiele": "Geze, Bothe Hild, Warema, Hagleitner",
"d365_branch_detail": "Gebäudetechnik Allgemein"
},
"Schädlingsbekämpfung": {
"gruppe": "Hersteller / Produzenten",
"definition": "Hersteller von Systemen und Produkten zur Schädlingsbekämpfung.",
"beispiele": "BioTec, RSD Systems",
"d365_branch_detail": "Schädlingsbekämpfung"
},
"Braune & Weiße Ware": {
"gruppe": "Hersteller / Produzenten",
"definition": "Hersteller von Haushaltsgroßgeräten (Weiße Ware) und Unterhaltungselektronik (Braune Ware).",
"beispiele": "BSH",
"d365_branch_detail": "Braune & Weiße Ware"
},
"Fenster / Glas": {
"gruppe": "Hersteller / Produzenten",
"definition": "Hersteller von Fenstern, Türen oder Glaselementen.",
"beispiele": "",
"d365_branch_detail": "Fenster / Glas"
},
"Getränke": {
"gruppe": "Hersteller / Produzenten",
"definition": "Industrielle Hersteller von Getränken.",
"beispiele": "Wesergold, Schlossquelle, Winkels",
"d365_branch_detail": "Getränke"
},
"Möbel": {
"gruppe": "Hersteller / Produzenten",
"definition": "Industrielle Hersteller von Möbeln.",
"beispiele": "mycs",
"d365_branch_detail": "Möbel"
},
"Agrar / Pellets": {
"gruppe": "Hersteller / Produzenten",
"definition": "Hersteller von landwirtschaftlichen Produkten, Maschinen oder Brennstoffen wie Holzpellets.",
"beispiele": "KWB Energiesysteme",
"d365_branch_detail": "Agrar, Pellets"
},
"Stadtwerke": {
"gruppe": "Versorger",
"definition": "Lokale Stadtwerke, die die lokale Infrastruktur für die Energieversorgung (Strom, Gas, Wasser) betreiben.",
"beispiele": "Badenova, Drewag, Stadtwerke Leipzig, Stadtwerke Kiel",
"d365_branch_detail": "Stadtwerke"
},
"Verteilnetzbetreiber": {
"gruppe": "Versorger",
"definition": "Überregionale Betreiber von Verteilnetzen (Strom, Gas), die oft keine direkten Endkundenversorger sind.",
"beispiele": "Rheinenergie, Open Grid, ENBW",
"d365_branch_detail": "Verteilnetzbetreiber"
},
"Telekommunikation": {
"gruppe": "Versorger",
"definition": "Betreiber von Telekommunikations-Infrastruktur und Netzen (z.B. Telefon, Internet, Mobilfunk).",
"beispiele": "M-Net, NetCologne, Thiele, Willy.tel",
"d365_branch_detail": "Telekommunikation"
},
"Gase & Mineralöl": {
"gruppe": "Versorger",
"definition": "Unternehmen, die Gas- oder Mineralölprodukte an Endkunden oder Unternehmen liefern.",
"beispiele": "Westfalen AG, GasCom",
"d365_branch_detail": "Gase & Mineralöl"
},
"Messdienstleister": {
"gruppe": "Service provider (Dienstleister)",
"definition": "Unternehmen, die sich auf die Ablesung und Abrechnung von Verbrauchszählern (Heizung, Wasser) spezialisiert haben. Abgrenzung: Kein Versorger.",
"beispiele": "Brunata, Ista, Telent",
"d365_branch_detail": "Messdienstleister"
},
"Facility Management": {
"gruppe": "Service provider (Dienstleister)",
"definition": "Anbieter von Dienstleistungen rund um Immobilien, von der technischen Instandhaltung bis zur Reinigung.",
"beispiele": "Wisag, Vonovia, Infraserv, Gewofag, B&O, Sprint Sanierungen, BWTS",
"d365_branch_detail": "Facility Management"
},
"Healthcare/Pflegedienste": {
"gruppe": "Service provider (Dienstleister)",
"definition": "Erbringen von reinen Dienstleistungen an medizinischen Geräten (z.B. Wartung, Lieferung) oder direkt an Menschen (Pflege). Abgrenzung: Keine Hersteller.",
"beispiele": "Sanimed, Fuchs+Möller, Strehlow, Healthcare at Home",
"d365_branch_detail": "Healthcare/Pflegedienste"
},
"Servicedienstleister / Reparatur ohne Produktion": {
"gruppe": "Service provider (Dienstleister)",
"definition": "Reine Service-Organisationen, die technische Geräte warten und reparieren, aber nicht selbst herstellen.",
"beispiele": "HSR, FFB",
"d365_branch_detail": "Servicedienstleister / Reparatur ohne Produktion"
},
"Aufzüge und Rolltreppen": {
"gruppe": "Service provider (Dienstleister)",
"definition": "Hersteller und Unternehmen, die Service, Wartung und Installation von Aufzügen und Rolltreppen anbieten.",
"beispiele": "TKE, Liftstar, Lifta",
"d365_branch_detail": "Aufzüge und Rolltreppen"
},
"Feuer- und Sicherheitssysteme": {
"gruppe": "Service provider (Dienstleister)",
"definition": "Dienstleister für die Wartung, Installation und Überprüfung von Brandmelde- und Sicherheitssystemen.",
"beispiele": "Minimax, Securiton",
"d365_branch_detail": "Feuer- und Sicherheitssysteme"
},
"Personentransport": {
"gruppe": "Service provider (Dienstleister)",
"definition": "Unternehmen, die Personen befördern (z.B. Busunternehmen, Taxi-Zentralen) und eine eigene Fahrzeugflotte warten.",
"beispiele": "Rhein-Sieg-Verkehrsgesellschaft",
"d365_branch_detail": "Personentransport"
},
"Entsorgung": {
"gruppe": "Service provider (Dienstleister)",
"definition": "Unternehmen der Abfall- und Entsorgungswirtschaft mit komplexer Logistik und Fahrzeugmanagement.",
"beispiele": "",
"d365_branch_detail": "Entsorgung"
},
"Catering Services": {
"gruppe": "Service provider (Dienstleister)",
"definition": "Anbieter von Verpflegungsdienstleistungen, oft mit komplexer Logistik und Wartung von Küchengeräten.",
"beispiele": "Café+Co International",
"d365_branch_detail": "Catering Services"
},
"Auslieferdienste": {
"gruppe": "Handel & Logistik",
"definition": "Unternehmen, deren Kerngeschäft der Transport und die Logistik von Waren zum Endkunden ist (Lieferdienste). Abgrenzung: Keine reinen Logistik-Dienstleister.",
"beispiele": "Edeka, Rewe, Saturn, Gamma Reifen",
"d365_branch_detail": "Auslieferdienste"
},
"Energie (Brennstoffe)": {
"gruppe": "Handel & Logistik",
"definition": "Unternehmen, deren Kerngeschäft der Transport und die Logistik von Brennstoffen wie Heizöl zum Endkunden ist.",
"beispiele": "Eckert & Ziegler",
"d365_branch_detail": "Energie (Brennstoffe)"
},
"Großhandel": {
"gruppe": "Handel & Logistik",
"definition": "Großhandelsunternehmen, bei denen der Transport und die Logistik eine zentrale Rolle spielen.",
"beispiele": "Hairhaus, NDI Nordisk",
"d365_branch_detail": "Großhandel"
},
"Einzelhandel": {
"gruppe": "Handel & Logistik",
"definition": "Einzelhandelsunternehmen, oft mit eigener Lieferlogistik zum Endkunden.",
"beispiele": "Cactus, mertens, Teuto",
"d365_branch_detail": "Einzelhandel"
},
"Logistik": {
"gruppe": "Handel & Logistik",
"definition": "Allgemeine Logistikdienstleister, die nicht in eine der spezifischeren Kategorien passen.",
"beispiele": "Gerdes + Landwehr, Rüdebusch, Winner",
"d365_branch_detail": "Logistik - Sonstige"
},
"Baustoffhandel": {
"gruppe": "Baubranche",
"definition": "Großhandel mit Baustoffen wie Zement, Kies, Holz oder Fliesen oft mit eigenen Fuhrparks und komplexer Filiallogistik.",
"beispiele": "Kemmler Baustoffe, Henri Benthack",
"d365_branch_detail": "Baustoffhandel"
},
"Baustoffindustrie": {
"gruppe": "Baubranche",
"definition": "Produktion von Baustoffen wie Beton, Ziegeln, Gips oder Dämmmaterial häufig mit werkseigener Logistik.",
"beispiele": "Heidelberg Materials, Saint Gobain Weber",
"d365_branch_detail": "Baustoffindustrie"
},
"Logistiker Baustoffe": {
"gruppe": "Baubranche",
"definition": "Spezialisierte Transportdienstleister für Baustoffe häufig im Nahverkehr, mit engen Zeitfenstern und Baustellenbelieferung.",
"beispiele": "C.Bergmann, HENGE Baustoff GmbH",
"d365_branch_detail": "Logistiker Baustoffe"
},
"Bauunternehmen": {
"gruppe": "Baubranche",
"definition": "Ausführung von Bauprojekten, oft mit eigenem Materialtransport hoher Koordinationsaufwand bei Fahrzeugen, Maschinen und Baustellen.",
"beispiele": "Max Bögl, Leonhard Weiss",
"d365_branch_detail": "Bauunternehmen"
},
"Versicherungsgutachten": {
"gruppe": "Gutachter / Versicherungen",
"definition": "Gutachter, die im Auftrag von Versicherungen Schäden prüfen und bewerten.",
"beispiele": "DEVK, Allianz",
"d365_branch_detail": "Versicherungsgutachten"
},
"Technische Gutachten": {
"gruppe": "Gutachter / Versicherungen",
"definition": "Sachverständige und Organisationen, die technische Prüfungen, Inspektionen und Gutachten durchführen.",
"beispiele": "TÜV, Audatex, Value, MDK",
"d365_branch_detail": "Technische Gutachten"
},
"Medizinische Gutachten": {
"gruppe": "Gutachter / Versicherungen",
"definition": "Sachverständige und Organisationen (z.B. MDK), die medizinische Gutachten erstellen.",
"beispiele": "MDK",
"d365_branch_detail": "Medizinische Gutachten"
},
"Baugutachter": {
"gruppe": "Gutachter / Versicherungen",
"definition": "Sachverständige, die Bauschäden oder den Wert von Immobilien begutachten.",
"beispiele": "",
"d365_branch_detail": "Baugutachter"
},
"Wohnungswirtschaft": {
"gruppe": "Housing",
"definition": "Wohnungsbaugesellschaften oder -genossenschaften, die ihre Immobilien instand halten.",
"beispiele": "GEWOFAG",
"d365_branch_detail": "Wohnungswirtschaft"
},
"Renovierungsunternehmen": {
"gruppe": "Housing",
"definition": "Dienstleister, die auf die Renovierung und Sanierung von Wohnimmobilien spezialisiert sind.",
"beispiele": "",
"d365_branch_detail": "Renovierungsunternehmen"
},
"Sozialbau Unternehmen": {
"gruppe": "Housing",
"definition": "Unternehmen, die im Bereich des sozialen Wohnungsbaus tätig sind.",
"beispiele": "",
"d365_branch_detail": "Anbieter für Soziales Wohnen"
},
"IT Beratung": {
"gruppe": "Sonstige",
"definition": "Beratungsunternehmen mit Fokus auf IT-Strategie und -Implementierung. Abgrenzung: Keine Systemhäuser mit eigenem Außendienst.",
"beispiele": "",
"d365_branch_detail": "IT Beratung"
},
"Unternehmensberatung": {
"gruppe": "Sonstige",
"definition": "Klassische Management- und Strategieberatungen.",
"beispiele": "",
"d365_branch_detail": "Unternehmensberatung (old)"
},
"Engineering": {
"gruppe": "Sonstige",
"definition": "Ingenieurbüros und technische Planungsdienstleister.",
"beispiele": "",
"d365_branch_detail": "Engineering"
},
"Öffentliche Verwaltung": {
"gruppe": "Sonstige",
"definition": "Behörden und öffentliche Einrichtungen, oft mit eigenen technischen Abteilungen (z.B. Bauhöfe).",
"beispiele": "",
"d365_branch_detail": "Öffentliche Verwaltung"
},
"Sonstiger Service": {
"gruppe": "Sonstige",
"definition": "Auffangkategorie für Dienstleistungen, die keiner anderen Kategorie zugeordnet werden können.",
"beispiele": "",
"d365_branch_detail": "Sonstiger Service (old)"
}
}
# Branchenübergreifende Top-Referenzen als Fallback
FALLBACK_REFERENCES = [
"Jungheinrich (weltweit >4.000 Techniker)",
"Vivawest (Kundenzufriedenheit > 95%)",
"TK Elevators (1.500 Techniker)",
"NetCologne"
]
# --- API Schlüssel Speicherung (werden in main() geladen) ---
API_KEYS = {}
@classmethod
def load_api_keys(cls):
"""Laedt API-Schluessel aus den definierten Dateien."""
logger = logging.getLogger(__name__)
logger.info("Lade API-Schluessel...")
print(f"DEBUG: Attempting to load API keys. BASE_DIR: {BASE_DIR}") # Debug print
cls.API_KEYS['openai'] = cls._load_key_from_file(API_KEY_FILE)
cls.API_KEYS['serpapi'] = cls._load_key_from_file(SERP_API_KEY_FILE)
cls.API_KEYS['genderize'] = cls._load_key_from_file(GENDERIZE_API_KEY_FILE)
if cls.API_KEYS.get('openai'):
openai.api_key = cls.API_KEYS['openai']
logger.info("OpenAI API Key erfolgreich geladen.")
else:
logger.warning("OpenAI API Key konnte nicht geladen werden. OpenAI-Funktionen sind deaktiviert.")
if not cls.API_KEYS.get('serpapi'):
logger.warning("SerpAPI Key konnte nicht geladen werden. Suchfunktionen sind deaktiviert.")
if not cls.API_KEYS.get('genderize'):
logger.warning("Genderize API Key konnte nicht geladen werden. Geschlechtserkennung ist eingeschraenkt.")
@staticmethod
def _load_key_from_file(filepath):
"""Hilfsfunktion zum Laden eines Schluessels aus einer Datei."""
logger = logging.getLogger(__name__)
abs_path = os.path.abspath(filepath)
try:
with open(abs_path, "r", encoding="utf-8") as f:
key = f.read().strip()
if key:
return key
else:
logger.warning(f"API key file is empty: '{abs_path}'")
return None
except FileNotFoundError:
logger.warning(f"API key file not found at path: '{abs_path}'")
return None
except Exception as e:
logger.error(f"Error reading key file '{abs_path}': {e}")
return None
# ==============================================================================
# 4. GLOBALE DATENSTRUKTUR-VARIABLEN
# ==============================================================================
# NEU: Definiert die exakte und garantierte Reihenfolge der Spalten.
# Dies ist die neue "Single Source of Truth" für alle Index-Berechnungen.
COLUMN_ORDER = [
"ReEval Flag", "CRM Name", "CRM Kurzform", "Parent Account Name", "CRM Website", "CRM Ort", "CRM Land",
"CRM Beschreibung", "CRM Branche", "CRM Beschreibung Branche extern", "CRM Anzahl Techniker", "CRM Umsatz",
"CRM Anzahl Mitarbeiter", "CRM Vorschlag Wiki URL", "System Vorschlag Parent Account", "Parent Vorschlag Status",
"Parent Vorschlag Timestamp", "Wiki URL", "Wiki Sitz Stadt", "Wiki Sitz Land", "Wiki Absatz", "Wiki Branche",
"Wiki Umsatz", "Wiki Mitarbeiter", "Wiki Kategorien", "Wikipedia Timestamp", "Wiki Verif. Timestamp",
"SerpAPI Wiki Search Timestamp", "Chat Wiki Konsistenzpruefung", "Chat Begründung Wiki Inkonsistenz",
"Chat Vorschlag Wiki Artikel", "Begründung bei Abweichung", "Website Rohtext", "Website Zusammenfassung",
"Website Meta-Details", "Website Scrape Timestamp", "URL Prüfstatus", "Chat Vorschlag Branche",
"Chat Branche Konfidenz", "Chat Konsistenz Branche", "Chat Begruendung Abweichung Branche",
"Chat Prüfung FSM Relevanz", "Chat Begründung für FSM Relevanz", "Chat Schätzung Anzahl Mitarbeiter",
"Chat Konsistenzprüfung Mitarbeiterzahl", "Chat Begruendung Abweichung Mitarbeiterzahl",
"Chat Einschätzung Anzahl Servicetechniker", "Chat Begründung Abweichung Anzahl Servicetechniker",
"Chat Schätzung Umsatz", "Chat Begründung Abweichung Umsatz", "FSM Pitch", "FSM Pitch Timestamp",
"Linked Serviceleiter gefunden", "Linked It-Leiter gefunden", "Linked Management gefunden",
"Linked Disponent gefunden", "Contact Search Timestamp", "Finaler Umsatz (Wiki>CRM)",
"Finaler Mitarbeiter (Wiki>CRM)", "Geschaetzter Techniker Bucket", "Plausibilität Umsatz",
"Plausibilität Mitarbeiter", "Plausibilität Umsatz/MA Ratio", "Abweichung Umsatz CRM/Wiki",
"Abweichung MA CRM/Wiki", "Plausibilität Begründung", "Plausibilität Prüfdatum",
"Archiviert", "SyncConflict", "Timestamp letzte Pruefung", "Version", "Tokens", "CRM ID"
]
# --- Spalten-Mapping (Single Source of Truth) ---
# Version 1.8.0 - 68 Spalten (A-BP)
COLUMN_MAP = {
# A-E: Stammdaten & Prozesssteuerung
"ReEval Flag": {"Titel": "A", "index": 0},
"CRM Name": {"Titel": "B", "index": 1},
"CRM Kurzform": {"Titel": "C", "index": 2},
"Parent Account Name": {"Titel": "D", "index": 3},
"CRM Website": {"Titel": "E", "index": 4},
# F-M: CRM-Daten
"CRM Ort": {"Titel": "F", "index": 5},
"CRM Land": {"Titel": "G", "index": 6},
"CRM Beschreibung": {"Titel": "H", "index": 7},
"CRM Branche": {"Titel": "I", "index": 8},
"CRM Beschreibung Branche extern": {"Titel": "J", "index": 9},
"CRM Anzahl Techniker": {"Titel": "K", "index": 10},
"CRM Umsatz": {"Titel": "L", "index": 11},
"CRM Anzahl Mitarbeiter": {"Titel": "M", "index": 12},
# N-Q: System & Parent Vorschläge
"CRM Vorschlag Wiki URL": {"Titel": "N", "index": 13},
"System Vorschlag Parent Account": {"Titel": "O", "index": 14},
"Parent Vorschlag Status": {"Titel": "P", "index": 15},
"Parent Vorschlag Timestamp": {"Titel": "Q", "index": 16},
# R-AB: Wikipedia Extraktion
"Wiki URL": {"Titel": "R", "index": 17},
"Wiki Sitz Stadt": {"Titel": "S", "index": 18},
"Wiki Sitz Land": {"Titel": "T", "index": 19},
"Wiki Absatz": {"Titel": "U", "index": 20},
"Wiki Branche": {"Titel": "V", "index": 21},
"Wiki Umsatz": {"Titel": "W", "index": 22},
"Wiki Mitarbeiter": {"Titel": "X", "index": 23},
"Wiki Kategorien": {"Titel": "Y", "index": 24},
"Wikipedia Timestamp": {"Titel": "Z", "index": 25},
"Wiki Verif. Timestamp": {"Titel": "AA", "index": 26},
"SerpAPI Wiki Search Timestamp": {"Titel": "AB", "index": 27},
# AC-AF: ChatGPT Wiki Verifizierung
"Chat Wiki Konsistenzpruefung": {"Titel": "AC", "index": 28},
"Chat Begründung Wiki Inkonsistenz": {"Titel": "AD", "index": 29},
"Chat Vorschlag Wiki Artikel": {"Titel": "AE", "index": 30},
"Begründung bei Abweichung": {"Titel": "AF", "index": 31},
# AG-AK: Website Scraping
"Website Rohtext": {"Titel": "AG", "index": 32},
"Website Zusammenfassung": {"Titel": "AH", "index": 33},
"Website Meta-Details": {"Titel": "AI", "index": 34},
"Website Scrape Timestamp": {"Titel": "AJ", "index": 35},
"URL Prüfstatus": {"Titel": "AK", "index": 36},
# AL-AU: ChatGPT Branchen & FSM Analyse
"Chat Vorschlag Branche": {"Titel": "AL", "index": 37},
"Chat Branche Konfidenz": {"Titel": "AM", "index": 38},
"Chat Konsistenz Branche": {"Titel": "AN", "index": 39},
"Chat Begruendung Abweichung Branche": {"Titel": "AO", "index": 40},
"Chat Prüfung FSM Relevanz": {"Titel": "AP", "index": 41},
"Chat Begründung für FSM Relevanz": {"Titel": "AQ", "index": 42},
"Chat Schätzung Anzahl Mitarbeiter": {"Titel": "AR", "index": 43},
"Chat Konsistenzprüfung Mitarbeiterzahl": {"Titel": "AS", "index": 44},
"Chat Begruendung Abweichung Mitarbeiterzahl": {"Titel": "AT", "index": 45},
"Chat Einschätzung Anzahl Servicetechniker": {"Titel": "AU", "index": 46},
# AV-AZ: ChatGPT Fortsetzung & FSM Pitch
"Chat Begründung Abweichung Anzahl Servicetechniker": {"Titel": "AV", "index": 47},
"Chat Schätzung Umsatz": {"Titel": "AW", "index": 48},
"Chat Begründung Abweichung Umsatz": {"Titel": "AX", "index": 49},
"FSM Pitch": {"Titel": "AY", "index": 50},
"FSM Pitch Timestamp": {"Titel": "AZ", "index": 51},
# BA-BE: LinkedIn Kontaktsuche
"Linked Serviceleiter gefunden": {"Titel": "BA", "index": 52},
"Linked It-Leiter gefunden": {"Titel": "BB", "index": 53},
"Linked Management gefunden": {"Titel": "BC", "index": 54},
"Linked Disponent gefunden": {"Titel": "BD", "index": 55},
"Contact Search Timestamp": {"Titel": "BE", "index": 56},
# BF-BH: Konsolidierte Daten & ML
"Finaler Umsatz (Wiki>CRM)": {"Titel": "BF", "index": 57},
"Finaler Mitarbeiter (Wiki>CRM)": {"Titel": "BG", "index": 58},
"Geschaetzter Techniker Bucket": {"Titel": "BH", "index": 59},
# BI-BO: Plausibilitäts-Checks
"Plausibilität Umsatz": {"Titel": "BI", "index": 60},
"Plausibilität Mitarbeiter": {"Titel": "BJ", "index": 61},
"Plausibilität Umsatz/MA Ratio": {"Titel": "BK", "index": 62},
"Abweichung Umsatz CRM/Wiki": {"Titel": "BL", "index": 63},
"Abweichung MA CRM/Wiki": {"Titel": "BM", "index": 64},
"Plausibilität Begründung": {"Titel": "BN", "index": 65},
"Plausibilität Prüfdatum": {"Titel": "BO", "index": 66},
"Archiviert": {"Titel": "BP", "index": 67},
"SyncConflict": {"Titel": "BQ", "index": 68},
# BR-BU: Metadaten (Indizes verschoben)
"Timestamp letzte Pruefung": {"Titel": "BR", "index": 69},
"Version": {"Titel": "BS", "index": 70},
"Tokens": {"Titel": "BT", "index": 71},
"CRM ID": {"Titel": "BU", "index": 72}
}
# ==============================================================================
# 5. DEALFRONT AUTOMATION CONFIGURATION
# ==============================================================================
DEALFRONT_CREDENTIALS_FILE = os.path.join(BASE_DIR, "dealfront_credentials.json")
DEALFRONT_LOGIN_URL = "https://app.dealfront.com/login"
# Die direkte URL zum 'Target'-Bereich. Dies hat sich als der robusteste Weg erwiesen.
DEALFRONT_TARGET_URL = "https://app.dealfront.com/t/prospector/companies"
# WICHTIG: Der exakte Name der vordefinierten Suche, die nach der Navigation geladen werden soll.
TARGET_SEARCH_NAME = "Facility Management" # <-- PASSEN SIE DIESEN NAMEN AN IHRE ZIEL-LISTE AN
# --- END OF FILE config.py ---