bugfix
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user