666 lines
33 KiB
Python
666 lines
33 KiB
Python
#!/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: Feste Pfade für Docker-Betrieb) ---
|
||
# Das Basisverzeichnis ist im Docker-Kontext immer /app.
|
||
BASE_DIR = "/app"
|
||
|
||
CREDENTIALS_FILE = os.path.join(BASE_DIR, "service_account.json")
|
||
API_KEY_FILE = os.path.join(BASE_DIR, "gemini_api_key.txt")
|
||
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_from_docker") # Log in den gemounteten Ordner schreiben
|
||
|
||
# --- 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"
|
||
},
|
||
"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"
|
||
},
|
||
"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...")
|
||
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'):
|
||
# Hier nehmen wir an, dass 'openai' für Gemini verwendet wird (Legacy)
|
||
# Falls in helpers.py direkt auf 'gemini' zugegriffen wird, müsste das hier auch gesetzt werden.
|
||
logger.info("Gemini API Key (via 'openai' slot) erfolgreich geladen.")
|
||
else:
|
||
logger.warning("Gemini API Key konnte nicht geladen werden. KI-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 --- |