v1.2.0 - Bugfix & Robuste Branchen-Regel-Erkennung

- Bugfix: Behebt den Fehler, bei dem keine branchenspezifischen Regeln generiert wurden, weil die Schwellenwerte zu restriktiv waren.
- Die Schwellenwerte für die minimale Sample-Anzahl und die prozentuale Branchen-Reinheit wurden gelockert und sind nun am Anfang des Skripts konfigurierbar.
- Verbessertes Logging: Das Skript gibt nun detailliert Auskunft, warum ein Department als branchenspezifisch eingestuft oder warum es verworfen wurde.
This commit is contained in:
2025-09-18 12:22:33 +00:00
parent 98f079f064
commit 785c9f9c9c

View File

@@ -1,6 +1,6 @@
# knowledge_base_builder.py
__version__ = "v1.1.0"
__version__ = "v1.2.0"
import logging
import json
@@ -17,13 +17,10 @@ EXACT_MATCH_OUTPUT_FILE = "exact_match_map.json"
KEYWORD_RULES_OUTPUT_FILE = "keyword_rules.json"
DEPARTMENT_PRIORITIES = {
# --- Tier 1: Ultra-spezifische Nischen (höchste Priorität) ---
"Fuhrparkmanagement": 1,
"Legal": 1,
"Baustofflogistik": 1,
"Baustoffherstellung": 1,
# --- Tier 2: Kern-Fachbereiche (sortiert nach Kontakthäufigkeit) ---
"Field Service Management / Kundenservice": 2,
"IT": 3,
"Production Maintenance / Wartung Produktion": 4,
@@ -32,21 +29,14 @@ DEPARTMENT_PRIORITIES = {
"Supply Chain Management": 7,
"Finanzen": 8,
"Technik": 8,
# --- Tier 3: Übergreifende & Allgemeine Funktionen ---
"Management / GF / C-Level": 10,
"Logistik": 11,
"Vertrieb": 12,
"Transportwesen": 13,
# --- Tier 4: Auffang-Kategorien (niedrigste Priorität) ---
"Berater": 20,
"Undefined": 99
}
# NEU: Definition von Branchen-Gruppen für die kontextsensitive Regelerstellung
# Key: Ein einfaches, normalisiertes Schlüsselwort für die Gruppe
# Value: Eine Liste von d365_branch_detail Werten aus Ihrer config.py
BRANCH_GROUP_RULES = {
"bau": [
"Baustoffhandel", "Baustoffindustrie",
@@ -63,8 +53,12 @@ BRANCH_GROUP_RULES = {
"Braune & Weiße Ware", "Fenster / Glas", "Getränke", "Möbel", "Agrar, Pellets"
]
}
# Schwellenwert: Wenn >X% der Jobtitel eines Departments in einer Branchengruppe liegen, wird es spezifisch
BRANCH_SPECIFICITY_THRESHOLD = 0.8
# --- NEU: Angepasste und konfigurierbare Schwellenwerte ---
# Ein Department muss mindestens so viele Einträge haben, um eine Branchen-Regel zu bekommen.
MIN_SAMPLES_FOR_BRANCH_RULE = 5
# Wenn >X% der Jobtitel eines Departments in EINER Branchengruppe liegen, gilt es als spezifisch.
BRANCH_SPECIFICITY_THRESHOLD = 0.7
STOP_WORDS = {
'manager', 'leiter', 'head', 'lead', 'senior', 'junior', 'direktor', 'director',
@@ -77,12 +71,7 @@ STOP_WORDS = {
def build_knowledge_base():
"""
Hauptfunktion zur Erstellung der Wissensbasis.
Liest Rohdaten, analysiert sie und erstellt JSON-Dateien für exakte und Keyword-basierte Übereinstimmungen.
Erstellt automatisch Regeln für branchenspezifische Departments.
"""
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
logger.info(f"Starte Erstellung der Wissensbasis (Version {__version__})...")
@@ -90,7 +79,7 @@ def build_knowledge_base():
df = gsh.get_sheet_as_dataframe(SOURCE_SHEET_NAME)
if df is None or df.empty:
logger.critical(f"Konnte keine Daten aus '{SOURCE_SHEET_NAME}' laden oder das Tabellenblatt ist leer. Abbruch.")
logger.critical(f"Konnte keine Daten aus '{SOURCE_SHEET_NAME}' laden. Abbruch.")
return
df.columns = [col.strip() for col in df.columns]
@@ -112,7 +101,7 @@ def build_knowledge_base():
try:
with open(EXACT_MATCH_OUTPUT_FILE, 'w', encoding='utf-8') as f:
json.dump(exact_match_map, f, indent=4, ensure_ascii=False)
logger.info(f"-> '{EXACT_MATCH_OUTPUT_FILE}' mit {len(exact_match_map)} einzigartigen Jobtiteln erfolgreich erstellt.")
logger.info(f"-> '{EXACT_MATCH_OUTPUT_FILE}' mit {len(exact_match_map)} Titeln erstellt.")
except IOError as e:
logger.error(f"Fehler beim Schreiben der Datei '{EXACT_MATCH_OUTPUT_FILE}': {e}")
return
@@ -141,7 +130,8 @@ def build_knowledge_base():
department_branches = branches_by_department.get(department, [])
total_titles_in_dept = len(department_branches)
if total_titles_in_dept > 10: # Mindestanzahl an Datenpunkten, um eine Regel zu erstellen
# Angepasste Logik mit transparentem Logging
if total_titles_in_dept >= MIN_SAMPLES_FOR_BRANCH_RULE:
branch_group_counts = Counter()
for branch_name in department_branches:
for group_keyword, d365_names in BRANCH_GROUP_RULES.items():
@@ -150,16 +140,24 @@ def build_knowledge_base():
if branch_group_counts:
most_common_group, count = branch_group_counts.most_common(1)[0]
if (count / total_titles_in_dept) > BRANCH_SPECIFICITY_THRESHOLD:
logger.info(f" -> Department '{department}' ist spezifisch für Branche '{most_common_group}' ({count/total_titles_in_dept:.0%}). Regel wird hinzugefügt.")
ratio = count / total_titles_in_dept
if ratio > BRANCH_SPECIFICITY_THRESHOLD:
logger.info(f" -> Department '{department}' ist spezifisch für Branche '{most_common_group}' ({ratio:.0%}). Regel wird hinzugefügt.")
rule["required_branch_keywords"] = [most_common_group]
else:
logger.debug(f" -> Department '{department}' nicht spezifisch genug. Dominante Branche '{most_common_group}' nur bei {ratio:.0%}, benötigt >{BRANCH_SPECIFICITY_THRESHOLD:.0%}.")
else:
logger.debug(f" -> Department '{department}' konnte keiner Branchen-Gruppe zugeordnet werden.")
else:
logger.debug(f" -> Department '{department}' hat zu wenige Datenpunkte ({total_titles_in_dept} < {MIN_SAMPLES_FOR_BRANCH_RULE}) für eine Branchen-Regel.")
keyword_rules[department] = rule
try:
with open(KEYWORD_RULES_OUTPUT_FILE, 'w', encoding='utf-8') as f:
json.dump(keyword_rules, f, indent=4, ensure_ascii=False)
logger.info(f"-> '{KEYWORD_RULES_OUTPUT_FILE}' mit Regeln für {len(keyword_rules)} Departments erfolgreich erstellt.")
logger.info(f"-> '{KEYWORD_RULES_OUTPUT_FILE}' mit Regeln für {len(keyword_rules)} Departments erstellt.")
except IOError as e:
logger.error(f"Fehler beim Schreiben der Datei '{KEYWORD_RULES_OUTPUT_FILE}': {e}")
return