From 0a9775ddd72dca4a611d061c052604d23bcebca5 Mon Sep 17 00:00:00 2001 From: Floke Date: Wed, 16 Jul 2025 07:50:26 +0000 Subject: [PATCH] =?UTF-8?q?extract=5Finsights.py=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extract_insights.py | 157 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 extract_insights.py diff --git a/extract_insights.py b/extract_insights.py new file mode 100644 index 00000000..cd89ba5e --- /dev/null +++ b/extract_insights.py @@ -0,0 +1,157 @@ +# extract_insights.py + +import os +import yaml +import logging +import time +import openai +import docx # Die neue Bibliothek zur Verarbeitung von Word-Dokumenten +from config import Config + +# --- Konfiguration --- +DOCS_SOURCE_FOLDER = "industry_docs" # Der Ordner, in dem Ihre .docx-Dateien liegen +OUTPUT_FILE = "marketing_wissen_v1.yaml" +MODEL_TO_USE = "gpt-4-turbo" # Empfohlen für komplexe Extraktionsaufgaben + +# --- Logging einrichten --- +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + +def call_openai_with_retry(prompt, max_retries=3, delay=5): + """Ruft die OpenAI API mit Retry-Logik auf.""" + for attempt in range(max_retries): + try: + logging.info(f"Sende Prompt an OpenAI (Länge: {len(prompt)} Zeichen)...") + response = openai.ChatCompletion.create( + model=MODEL_TO_USE, + messages=[{"role": "user", "content": prompt}], + temperature=0.2, # Niedrige Temperatur für präzise Extraktion + max_tokens=1024 + ) + 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: + logging.info(f"Warte {delay} Sekunden vor dem nächsten Versuch...") + time.sleep(delay) + else: + logging.error("Maximale Anzahl an Wiederholungen erreicht.") + return None + +def read_docx_content(filepath): + """Liest den gesamten Textinhalt aus einer .docx-Datei, inklusive Tabellen.""" + try: + doc = docx.Document(filepath) + full_text = [] + for para in doc.paragraphs: + full_text.append(para.text) + for table in doc.tables: + for row in table.rows: + for cell in row.cells: + full_text.append(cell.text) + return "\n".join(full_text) + except Exception as e: + logging.error(f"Fehler beim Lesen der DOCX-Datei {filepath}: {e}") + return None + +def generate_extraction_prompt(content, data_to_extract): + """Erstellt einen spezialisierten Prompt, um bestimmte Daten zu extrahieren.""" + prompts = { + "pain_points": ( + "Du bist ein Branchenanalyst. Lies das folgende Dokument und extrahiere die 5 wichtigsten operativen " + "Herausforderungen (Pain Points) für Unternehmen dieser Branche im Bereich Field Service. " + "Formuliere sie als prägnante Stichpunkte.\n\n" + "Gib das Ergebnis ausschließlich als YAML-Liste unter dem Schlüssel 'pain_points:' aus. KEINE weiteren Kommentare." + ), + "key_terms": ( + "Du bist ein Fachlexikograf. Lies das folgende Dokument und extrahiere die 10 wichtigsten Fachbegriffe, " + "Abkürzungen oder Normen, die im Kontext von Service, Wartung und Technik verwendet werden.\n\n" + "Gib das Ergebnis ausschließlich als YAML-Liste unter dem Schlüssel 'key_terms:' aus." + ), + "summary": ( + "Du bist ein Chefredakteur. Lies das folgende Dokument und verfasse eine prägnante Zusammenfassung (max. 3 Sätze) " + "über die allgemeine Geschäftslage, die wichtigsten Trends und die Bedeutung des Field Service in dieser Branche.\n\n" + "Gib das Ergebnis ausschließlich als einfachen Text unter dem YAML-Schlüssel 'summary:' aus." + ) + } + + if data_to_extract not in prompts: + raise ValueError(f"Unbekannter Extraktionstyp: {data_to_extract}") + + return f"{prompts[data_to_extract]}\n\n--- DOKUMENTENINHALT ---\n\n{content}" + + +def main(): + """Liest .docx-Dateien, extrahiert Wissen per KI und speichert es als YAML.""" + logging.info("Starte die KI-gestützte Extraktion von Branchen-Wissen...") + + # API-Schlüssel laden + Config.load_api_keys() + openai.api_key = Config.API_KEYS.get('openai') + if not openai.api_key: + logging.critical("OpenAI API Key nicht in config.py gefunden. Skript wird beendet.") + return + + if not os.path.exists(DOCS_SOURCE_FOLDER): + logging.critical(f"Der Quellordner '{DOCS_SOURCE_FOLDER}' wurde nicht gefunden. Bitte erstellen und die .docx-Dateien dort ablegen.") + return + + knowledge_base = {'Branchen': {}} + + doc_files = [f for f in os.listdir(DOCS_SOURCE_FOLDER) if f.endswith('.docx')] + logging.info(f"Gefundene Dokumente zur Verarbeitung: {', '.join(doc_files)}") + + for filename in doc_files: + # Extrahiere den Branchennamen aus dem Dateinamen + # z.B. "Focus_insights_HVAC.docx" -> "Gebäudetechnik Heizung, Lüftung, Klima" + # Dies muss manuell oder durch eine Mapping-Tabelle angepasst werden. + # Für den Moment nehmen wir den Namen aus der Datei. + base_name = os.path.splitext(filename)[0].replace("Focus_insights_", "") + # Sie können hier ein Mapping zu den sauberen Namen aus Ihrer `config.py` einfügen. + # Beispiel: branch_name = MAPPING.get(base_name, base_name) + branch_name = base_name.replace("_", " ") # Einfache Normalisierung für den Start + + logging.info(f"\n--- Verarbeite Branche: {branch_name} aus Datei {filename} ---") + filepath = os.path.join(DOCS_SOURCE_FOLDER, filename) + content = read_docx_content(filepath) + + if not content: + continue + + branch_data = { + 'references_DE': '[HIER DEUTSCHE REFERENZKUNDEN EINTRAGEN]', + 'references_GB': '[HIER ENGLISCHE REFERENZKUNDEN EINTRAGEN]' + } + + # Extrahiere Pain Points, Key Terms und Summary + for data_type in ["pain_points", "key_terms", "summary"]: + logging.info(f" -> Extrahiere '{data_type}'...") + prompt = generate_extraction_prompt(content, data_type) + response_text = call_openai_with_retry(prompt) + if response_text: + try: + # Versuche, die YAML-Antwort zu parsen und dem branch_data Dict hinzuzufügen + parsed_yaml = yaml.safe_load(response_text) + branch_data.update(parsed_yaml) + except yaml.YAMLError as e: + logging.error(f" Fehler beim Parsen der YAML-Antwort für '{data_type}': {e}") + branch_data[data_type] = f"PARSING-FEHLER: {response_text}" + time.sleep(2) # Pause zwischen API-Aufrufen + + knowledge_base['Branchen'][branch_name] = branch_data + + # Persona-Daten hinzufügen (diese sind statisch) + # Hier können Sie die Persona-Daten aus der letzten Iteration einfügen. + # ... + + # Ergebnis in YAML-Datei speichern + 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 Wissensbasis wurde in '{OUTPUT_FILE}' gespeichert.") + logging.info("BITTE ÜBERPRÜFEN SIE DIESE DATEI UND PASSEN SIE SIE NACH BEDARF AN.") + except Exception as e: + logging.error(f"Fehler beim Speichern der YAML-Datei: {e}") + +if __name__ == "__main__": + main() \ No newline at end of file