This commit is contained in:
2025-06-19 17:46:59 +00:00
parent e794568884
commit 0c0ee7bad3

View File

@@ -89,27 +89,9 @@ except ImportError:
print("tiktoken nicht gefunden. Token-Zaehlung wird geschaetzt.") # Debugging-Ausgabe
# ==============================================================================
# 2. GLOBALE KONSTANTEN UND KONFIGURATION
# (Logisch 'config.py')
# ==============================================================================
# --- Dateipfade ---
CREDENTIALS_FILE = "service_account.json"
API_KEY_FILE = "api_key.txt" # OpenAI
SERP_API_KEY_FILE = "serpApiKey.txt"
GENDERIZE_API_KEY_FILE = "genderize_API_Key.txt"
BRANCH_MAPPING_FILE = "ziel_Branchenschema.csv" # Enthält Zielschema
LOG_DIR = "Log"
SHEET_ID = "1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo" # <<< HINZUFÜGEN
# --- ML Modell Artefakte ---
MODEL_FILE = "technician_decision_tree_model.pkl"
IMPUTER_FILE = "median_imputer.pkl"
PATTERNS_FILE_TXT = "technician_patterns.txt" # Alt (Optional beibehalten)
PATTERNS_FILE_JSON = "technician_patterns.json" # Neu (Empfohlen)
def load_branch_mapping(file_path='Branchen.csv'):
def load_branch_mapping(file_path=Config.BRANCH_MAPPING_FILE):
"""
Lädt das Mapping von Detail-Branche zu Branchen-Gruppe aus einer CSV-Datei.
Ist extrem robust gegen Kodierungs-, Spaltennamen- und Pfad-Fehler.
@@ -164,39 +146,49 @@ def load_branch_mapping(file_path='Branchen.csv'):
# --- Globale Konfiguration Klasse ---
# ==============================================================================
# 2. GLOBALE KONSTANTEN UND KONFIGURATION (ZENTRALISIERT)
# ==============================================================================
class Config:
"""Zentrale Konfigurationseinstellungen."""
VERSION = "v1.7.8"
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 # Anzahl der Versuche (nicht Wiederholungen nach dem ersten Fehler) fuer wiederholbare Fehler
RETRY_DELAY = 10 # Basiswartezeit (Sekunden) fuer Retries (exponentieller Backoff wird im Decorator angewendet)
REQUEST_TIMEOUT = 20 # Timeout (Sekunden) fuer externe HTTP/API Anfragen (Requests)
SIMILARITY_THRESHOLD = 0.65 # Schwelle fuer Namensaaehnlichkeit bei Wikipedia Validierung
DEBUG = True # Detailliertes Logging aktivieren/deaktivieren
WIKIPEDIA_SEARCH_RESULTS = 5 # Anzahl Ergebnisse bei Wikipedia Suche ueber Bibliothek
HTML_PARSER = "html.parser" # Parser fuer BeautifulSoup ('lxml' ist schneller, erfordert aber Installation)
TOKEN_MODEL = "gpt-3.5-turbo" # OpenAI Modell fuer Token-Zaehlung/Chat (Standard fuer die meisten Calls)
USER_AGENT = 'Mozilla/5.0 (compatible; UnternehmenSkript/1.0; +https://www.example.com/bot)' # User-Agent fuer Web Scraping/Requests (Beispiel URL anpassen)
BRANCH_MAPPING_FILE = "Branchen.csv" # << Sicherstellen, dass dies der korrekte Dateiname ist
# --- Grundkonfiguration ---
VERSION = "v1.7.9" # Version auf 1.7.9 erhöht
LANG = "de"
DEBUG = True
HTML_PARSER = "html.parser"
USER_AGENT = 'Mozilla/5.0 (compatible; UnternehmenSkript/1.0; +https://www.example.com/bot)'
# --- Dateipfade & IDs ---
SHEET_ID = "1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo"
SERVICE_ACCOUNT_FILE = "service_account.json"
TOKEN_FILE = "token.json"
API_KEY_FILE = "api_key.txt"
SERP_API_KEY_FILE = "serpApiKey.txt"
GENDERIZE_API_KEY_FILE = "genderize_API_Key.txt"
SCHEMA_FILE = "ziel_Branchenschema.csv"
MODEL_FILE = 'technician_decision_tree_model.pkl'
IMPUTER_FILE = 'median_imputer.pkl'
PATTERNS_FILE_JSON = 'technician_patterns.json'
BRANCH_MAPPING_FILE = "Branchen.csv"
LOG_DIR = "Log"
# --- ML Modell Artefakte ---
MODEL_FILE = "technician_decision_tree_model.pkl"
IMPUTER_FILE = "median_imputer.pkl"
PATTERNS_FILE_JSON = "technician_patterns.json"
# --- Konfiguration fuer Batching & Parallelisierung ---
# Passen Sie diese Werte an die Leistung Ihres Systems und die API-Limits an.
PROCESSING_BATCH_SIZE = 20 # Anzahl Zeilen pro Verarbeitungs-Batch (fuer _process_single_row in Batches)
OPENAI_BATCH_SIZE_LIMIT = 4 # Max. Texte pro OpenAI Call fuer Zusammenfassung (nur fuer summarize_batch_openai)
MAX_SCRAPING_WORKERS = 10 # Threads fuer paralleles Website-Scraping
UPDATE_BATCH_ROW_LIMIT = 50 # Zeilen sammeln fuer gebuendelte Sheet Updates (effizienter)
MAX_BRANCH_WORKERS = 10 # Threads fuer parallele Branchenbewertung
OPENAI_CONCURRENCY_LIMIT = 3 # Max. gleichzeitige OpenAI Calls (Semaphore fuer Branch Evaluation)
PROCESSING_BRANCH_BATCH_SIZE = 20 # Batch-Groesse fuer Branch-Evaluierung
SERPAPI_DELAY = 1.5 # Pause zwischen einzelnen SerpAPI-Aufrufen (Sekunden)
# --- OpenAI & API Konfiguration ---
TOKEN_MODEL = "gpt-3.5-turbo"
MAX_RETRIES = 5
RETRY_DELAY = 10
REQUEST_TIMEOUT = 20
SERPAPI_DELAY = 1.5
# --- Batching & Parallelisierung ---
MAX_SCRAPING_WORKERS = 10
MAX_BRANCH_WORKERS = 10
OPENAI_CONCURRENCY_LIMIT = 3
UPDATE_BATCH_ROW_LIMIT = 50
# --- Plausibilitäts-Schwellenwerte ---
PLAUSI_UMSATZ_MIN_WARNUNG = 50000
PLAUSI_UMSATZ_MAX_WARNUNG = 200000000000
PLAUSI_MA_MIN_WARNUNG_ABS = 1
@@ -206,54 +198,39 @@ class Config:
PLAUSI_RATIO_UMSATZ_PRO_MA_MIN = 25000
PLAUSI_RATIO_UMSATZ_PRO_MA_MAX = 1500000
PLAUSI_ABWEICHUNG_CRM_WIKI_PROZENT = 30
# --- API Schluessel Speicherung (werden in main() geladen) ---
# --- API Schluessel Speicherung (wird zur Laufzeit befüllt) ---
API_KEYS = {}
@classmethod
def load_api_keys(cls):
"""Laedt API-Schluessel aus den definierten Dateien."""
print("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)
# import openai # <--- DIESER IMPORT IST NUN ENTFERNT
logger = logging.getLogger(cls.__name__) # Logger innerhalb der Methode holen
logger.info("Lade API-Schluessel...")
cls.API_KEYS['openai'] = cls._load_key_from_file(cls.API_KEY_FILE)
cls.API_KEYS['serpapi'] = cls._load_key_from_file(cls.SERP_API_KEY_FILE)
cls.API_KEYS['genderize'] = cls._load_key_from_file(cls.GENDERIZE_API_KEY_FILE)
if cls.API_KEYS.get('openai'):
# Stelle sicher, dass das 'openai' Modul hier im Scope ist,
# indem wir auf den globalen Import zugreifen.
# Da 'openai' schon global importiert wurde (ganz oben im Skript),
# ist es hier direkt verfügbar.
openai.api_key = cls.API_KEYS['openai']
print("OpenAI API Key erfolgreich geladen.")
logger.info("OpenAI API Key erfolgreich geladen.")
else:
print("WARNUNG: OpenAI API Key konnte nicht geladen werden (Datei fehlt oder ist leer?). OpenAI-Funktionen sind deaktiviert.")
if not cls.API_KEYS.get('serpapi'):
print("WARNUNG: SerpAPI Key konnte nicht geladen werden (Datei fehlt oder ist leer?). Bestimmte Suchfunktionen sind deaktiviert.")
if not cls.API_KEYS.get('genderize'):
print("WARNUNG: Genderize API Key konnte nicht geladen werden (Datei fehlt oder ist leer?). Geschlechtserkennung ist eingeschraenkt.")
logger.warning("WARNUNG: OpenAI API Key konnte nicht geladen werden.")
@staticmethod
def _load_key_from_file(filepath):
"""Hilfsfunktion zum Laden eines Schluessels aus einer Datei."""
logger = logging.getLogger(Config.__name__)
try:
# Verwenden Sie "r" fuer Textmodus und geben Sie das Encoding an
with open(filepath, "r", encoding="utf-8") as f:
key = f.read().strip()
if key:
return key
else:
print(f"WARNUNG: Datei '{filepath}' ist leer.")
return None
if key: return key
return None
except FileNotFoundError:
print(f"INFO: API-Schluesseldatei '{filepath}' nicht gefunden.")
logger.debug(f"INFO: API-Schluesseldatei '{filepath}' nicht gefunden.")
return None
except Exception as e:
print(f"FEHLER beim Lesen der Schluesseldatei '{filepath}': {e}")
logger.error(f"FEHLER beim Lesen der Schluesseldatei '{filepath}': {e}")
return None
@@ -1212,7 +1189,7 @@ TARGET_SCHEMA_STRING = "Ziel-Branchenschema nicht verfuegbar." # String-Repraese
ALLOWED_TARGET_BRANCHES = [] # Liste der erlaubten Kurzformen
def load_target_schema(csv_filepath=BRANCH_MAPPING_FILE):
def load_target_schema(csv_filepath=Config.SCHEMA_FILE):
logger = logging.getLogger(__name__)
global ALLOWED_TARGET_BRANCHES, FOCUS_TARGET_BRANCHES, TARGET_SCHEMA_STRING, FOCUS_BRANCHES_PROMPT_PART
@@ -9337,7 +9314,7 @@ class DataProcessor:
# logger, pickle, json, os,
# train_test_split, SimpleImputer, DecisionTreeClassifier,
# accuracy_score, classification_report, confusion_matrix, export_text (sklearn).
def train_technician_model(self, model_out=MODEL_FILE, imputer_out=IMPUTER_FILE, patterns_out=PATTERNS_FILE_JSON):
def train_technician_model(self, model_out=Config.MODEL_FILE, imputer_out=Config.IMPUTER_FILE, patterns_out=Config.PATTERNS_FILE_JSON):
self.logger.info("Starte Training des Servicetechniker Decision Tree Modells...")
# 1. Daten vorbereiten