From 2c6ef64c7ccf73f5e27b5ecaab2afd15c5541bea Mon Sep 17 00:00:00 2001 From: Floke Date: Tue, 29 Jul 2025 11:27:23 +0000 Subject: [PATCH] =?UTF-8?q?build=5Fknowledge=5Fbase.py=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build_knowledge_base.py | 157 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 build_knowledge_base.py diff --git a/build_knowledge_base.py b/build_knowledge_base.py new file mode 100644 index 00000000..0af3047c --- /dev/null +++ b/build_knowledge_base.py @@ -0,0 +1,157 @@ +# build_knowledge_base.py + +import os +import yaml +import logging +import time +import openai +import argparse +from config import Config + +# --- Konfiguration --- +OUTPUT_FILE = "marketing_wissen_final.yaml" +MODEL_TO_USE = "gpt-4o" +DOSSIER_FOLDER = "industries" # Der Ordner für die generierten Branchen-Dossiers + +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + +def call_openai_with_retry(prompt, is_extraction=False, max_retries=3, delay=5): + """Ruft die OpenAI API auf.""" + # ... (Diese Funktion bleibt unverändert, ich füge sie hier der Vollständigkeit halber ein) ... + for attempt in range(max_retries): + try: + logging.info(f"Sende Prompt an OpenAI (Länge: {len(prompt)} Zeichen)...") + response_format = {"type": "json_object"} if is_extraction else {"type": "text"} + response = openai.ChatCompletion.create( + model=MODEL_TO_USE, + response_format=response_format, + messages=[{"role": "user", "content": prompt}], + temperature=0.3, + max_tokens=2048 + ) + content = response.choices[0].message['content'].strip() + return content + except Exception as e: + logging.error(f"Fehler bei OpenAI-API-Aufruf: {e}") + if attempt < max_retries - 1: + time.sleep(delay) + else: + return None + +def generate_research_prompt(branch_name, branch_info): + """Erstellt den Prompt, um ein Branchen-Dossier zu erstellen, basierend auf dem reichen Kontext.""" + + context_parts = [f"Branche: '{branch_name}'"] + if branch_info.get("definition"): + context_parts.append(f"Fokus / Abgrenzung: {branch_info['definition']}") + if branch_info.get("beispiele"): + context_parts.append(f"Beispielunternehmen: {branch_info['beispiele']}") + context_str = "\n".join(context_parts) + + return ( + f"Erstelle ein prägnantes Branchen-Dossier (ca. 300-400 Wörter) für die folgende, spezifische Branche:\n\n" + f"--- BRanchen-Kontext ---\n{context_str}\n\n" + "Struktur des Dossiers:\n" + "1. **Geschäftsmodelle & Field Service:** Beschreibe die typischen Geschäftsmodelle und die Rolle des Außendienstes, basierend auf dem oben genannten Fokus.\n" + "2. **Herausforderungen & Trends:** Nenne die wichtigsten Herausforderungen und Trends für den Service-Bereich in diesem spezifischen Segment.\n" + "3. **Branchenspezifisches Wording:** Liste typische Fachbegriffe auf, die in diesem Kontext üblich sind." + ) + +def generate_extraction_prompt(dossier_content): + """Erstellt den Prompt, um die strukturierten Daten aus dem Dossier zu extrahieren.""" + return ( + "Du bist ein Branchenanalyst mit dem Spezialgebiet Field Service Management. Deine Aufgabe ist es, aus einem Branchen-Dossier die Kernaussagen zu extrahieren.\n" + "Gib das Ergebnis ausschließlich als sauberes JSON-Objekt mit den Schlüsseln 'summary', 'pain_points' (eine Liste von 5 operativen Schmerzpunkten des Außendienstes) und 'key_terms' (eine Liste von 5-7 Begriffen) aus.\n\n" + "WICHTIGE REGELN FÜR 'pain_points':\n" + "- Extrahiere 5 **operative Schmerzpunkte, die direkt den technischen Außendienst betreffen**.\n" + "- Formuliere sie als konkrete Probleme, die ein Service-Leiter lösen muss (z.B. 'Sicherstellung der Anlagenverfügbarkeit', 'Lückenlose Dokumentation für Audits').\n" + "- Vermeide allgemeine Management-Themen wie 'Komplexität der Geschäftsmodelle' oder reine HR-Themen wie 'Fachkräftemangel'.\n\n" + "--- DOSSIER ---\n" + f"{dossier_content}" + ) + +def main(branches_to_process=None): + """Baut die komplette Wissensbasis auf, basierend auf den Definitionen in config.py.""" + logging.info("Starte den Aufbau der vollständigen Wissensbasis...") + + Config.load_api_keys() + openai.api_key = Config.API_KEYS.get('openai') + if not openai.api_key: + logging.critical("OpenAI API Key nicht gefunden.") + return + + # Die finale Wissensbasis wird von Grund auf neu erstellt + knowledge_base = { + 'Positionen': { + 'Field Service Management': {'name_DE': 'Leiter Kundenservice / Field Service', 'pains_DE': ['Das Team ist zu klein, überlastet und gestresst, was zu hoher Fluktuation führen kann.', 'Zu viele Anrufe und ungeplante Einsätze mit zu wenigen verfügbaren Ressourcen.', 'Ineffiziente, undurchsichtige und komplexe Prozesse bei der Einsatzplanung.']}, + 'IT': {'name_DE': 'IT-Leiter', 'pains_DE': ['Hoher Implementierungsaufwand und unklare Gesamtkosten (TCO) bei neuen Systemen.', 'Sicherheitsbedenken und die nahtlose Integration in die bestehende IT-Infrastruktur.', 'Mangelhafte Dokumentation oder unzureichende APIs neuer Softwarelösungen.']}, + 'Management / GF / C-Level': {'name_DE': 'Geschäftsführer / C-Level', 'pains_DE': ['Die richtigen, zukunftssicheren Investitionsentscheidungen treffen, um wettbewerbsfähig zu bleiben.', 'Den Überblick über die operative Effizienz behalten, um Wachstum und Profitabilität zu steuern.', 'Im "War for Talents" gute Mitarbeiter finden und durch moderne Werkzeuge langfristig halten.']}, + 'Procurement / Einkauf': {'name_DE': 'Einkaufsleiter', 'pains_DE': ['Unklare Amortisationszeit (ROI) und versteckte Kosten einer neuen Softwarelösung.', 'Sicherstellen, dass das Preis-Leistungs-Verhältnis das beste auf dem Markt ist.', 'Das Risiko einer Fehlinvestition minimieren und vertragliche Sicherheit gewährleisten.']}, + 'Finanzen': {'name_DE': 'Finanzleiter / CFO', 'pains_DE': ['Schwierigkeit, die Service-Einsätze verursachungsgerecht und präzise abzurechnen.', 'Mangelnde Transparenz über die tatsächliche Profitabilität einzelner Service-Aufträge.', 'Hoher manueller Aufwand bei der Reisekostenabrechnung und Materialbuchung der Techniker.']} + }, + 'Branchen': {} + } + + all_branches_from_config = Config.BRANCH_GROUP_MAPPING + + if branches_to_process: + target_branches = {k: v for k, v in all_branches_from_config.items() if k in branches_to_process} + if not target_branches: + logging.error("Keine der angegebenen Branchen ist gültig. Bitte prüfen Sie die Schreibweise.") + return + logging.info(f"Verarbeite die {len(target_branches)} explizit angegebenen Branchen...") + else: + target_branches = all_branches_from_config + logging.info(f"Es werden alle {len(target_branches)} Branchen aus der Config verarbeitet...") + + os.makedirs(DOSSIER_FOLDER, exist_ok=True) + + for branch_name, branch_info in target_branches.items(): + logging.info(f"\n--- Verarbeite Branche: {branch_name} ---") + + research_prompt = generate_research_prompt(branch_name, branch_info) + dossier = call_openai_with_retry(research_prompt) + if not dossier: continue + + try: + sanitized_branch_name = branch_name.replace('/', '-').replace('\\', '-') + dossier_filepath = os.path.join(DOSSIER_FOLDER, f"{sanitized_branch_name}.txt") + with open(dossier_filepath, 'w', encoding='utf-8') as f: f.write(dossier) + logging.info(f" -> Dossier erfolgreich in '{dossier_filepath}' gespeichert.") + except Exception as e: + logging.error(f" -> Fehler beim Speichern des Dossiers für {branch_name}: {e}") + + time.sleep(1) + + extraction_prompt = generate_extraction_prompt(dossier) + extracted_data_str = call_openai_with_retry(extraction_prompt, is_extraction=True) + if not extracted_data_str: continue + + try: + if extracted_data_str.startswith("```"): + extracted_data_str = extracted_data_str.split('\n', 1)[1].rsplit('```', 1)[0] + + extracted_data = yaml.safe_load(extracted_data_str) + # Referenzen direkt aus der Config übernehmen + extracted_data['references_DE'] = branch_info.get('beispiele', '[KEINE REFERENZEN IN CONFIG GEFUNDEN]') + extracted_data['references_GB'] = '[HIER ENGLISCHE REFERENZKUNDEN EINTRAGEN]' + knowledge_base['Branchen'][branch_name] = extracted_data + logging.info(f" -> {branch_name} erfolgreich zur Wissensbasis hinzugefügt.") + except Exception as e: + logging.error(f" Fehler beim Parsen der extrahierten Daten für {branch_name}: {e}") + + time.sleep(1) + + try: + with open(OUTPUT_FILE, 'w', encoding='utf-8') as f: + yaml.dump(knowledge_base, f, allow_unicode=True, sort_keys=False, width=120) + logging.info(f"\nErfolgreich! Die finale Wissensbasis wurde in '{OUTPUT_FILE}' gespeichert.") + except Exception as e: + logging.error(f"Fehler beim Speichern der finalen YAML-Datei: {e}") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Baut die komplette Marketing-Wissensbasis auf.") + parser.add_argument("--branches", nargs='+', type=str, help="Eine oder mehrere spezifische Branchen, die verarbeitet werden sollen.") + args = parser.parse_args() + + main(branches_to_process=args.branches) \ No newline at end of file