diff --git a/generate_marketing_text.py b/generate_marketing_text.py new file mode 100644 index 00000000..99d09ea3 --- /dev/null +++ b/generate_marketing_text.py @@ -0,0 +1,152 @@ +# generate_marketing_text.py + +import os +import yaml +import logging +import time +import openai +import json +import pandas as pd +import argparse +from config import Config + +# --- Konfiguration --- +KNOWLEDGE_BASE_FILE = "marketing_wissen.yaml" +OUTPUT_FILE = "marketing_text_blocks.xlsx" # Excel ist besser für lange Texte +MODEL_TO_USE = "gpt-4o" + +# --- 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 und erwartet eine JSON-Antwort.""" + for attempt in range(max_retries): + try: + logging.info(f"Sende Prompt an OpenAI (Versuch {attempt + 1}/{max_retries})...") + response = openai.ChatCompletion.create( + model=MODEL_TO_USE, + response_format={"type": "json_object"}, # Fordert explizit JSON an + messages=[{"role": "user", "content": prompt}], + temperature=0.6, + max_tokens=1024 + ) + content = response.choices[0].message['content'].strip() + return json.loads(content) # Direkt als JSON-Objekt zurückgeben + except json.JSONDecodeError as e: + logging.error(f"Fehler beim Parsen der JSON-Antwort von OpenAI: {e}") + logging.debug(f"Rohe Antwort: {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 build_prompt(branch_name, branch_data, position_name, position_data): + """Baut den finalen Master-Prompt zusammen.""" + + branch_pain_points = "\n".join([f"- {p}" for p in branch_data.get('pain_points', [])]) + position_pain_points = "\n".join([f"- {p}" for p in position_data.get('pains_DE', [])]) + + return "\n".join([ + "Du bist ein kompetenter Lösungsberater auf Augenhöhe. Du verstehst die Herausforderungen einer Branche und einer spezifischen Management-Rolle und kannst elegant aufzeigen, wie Technologie diese lösen kann.", + "AUFGABE: Erstelle 2 Textblöcke (Subject, Introduction_Textonly) für eine E-Mail. Die Texte müssen so formuliert sein, dass sie nahtlos an einen vorausgehenden, unternehmensspezifischen Satz anknüpfen, der eine operative Service-Herausforderung beschreibt.", + "\n--- UNSERE LÖSUNG (ZUR ORIENTIERUNG FÜR DICH) ---", + "- Wir bieten eine Software zur intelligenten, automatischen Einsatzplanung (unsere Kernkompetenz).", + "- Wir bieten eine mobile App für die Techniker im Außendienst.", + "\n--- KONTEXT ---", + f"ZIELBRANCHE: {branch_name}", + f"BRANCHEN-HERAUSFORDERUNGEN (PAIN POINTS):\n{branch_pain_points}", + f"\nANSPRECHPARTNER: {position_name}", + f"PERSÖNLICHE HERAUSFORDERUNGEN DES ANSPRECHPARTNERS (PAIN POINTS):\n{position_pain_points}", + "\n--- DEINE AUFGABE ---", + "1. **Subject:** Formuliere eine kurze, prägnante Betreffzeile (max. 5 Wörter), die ein Kernthema aufgreift.", + "2. **Introduction_Textonly:** Formuliere einen Einleitungstext (2 Sätze) nach dem folgenden Muster:", + " - **Satz 1 (Die Brücke & Lösungs-Andeutung):** Knüpfe an die (uns unbekannte) Herausforderung an. Formuliere, dass die Lösung in einer **intelligenten Planung** oder der **digitalen Unterstützung der Techniker** liegt. Wähle den Aspekt (Planung vs. Mobile), der am besten zu den Branchen-Pain-Points passt.", + " - **Satz 2 (Die Relevanz für die Position):** Schaffe die Relevanz für die Zielperson, indem du das Thema mit einem ihrer persönlichen Pain Points verknüpfst.", + "\n--- BEISPIEL FÜR EINEN PERFEKTEN OUTPUT (Kombination Anlagenbau & IT) ---", + ''' +{ + "Subject": "Optimierung der Service-Einsatzplanung", + "Introduction_Textonly": "Konkret geht es darum, die Koordination Ihrer komplexen Service-Einsätze durch eine intelligente Software zur Einsatzplanung zu optimieren. Für Sie als IT-Leiter ist dabei sicher die nahtlose und sichere Integration in Ihre bestehende ERP-Landschaft von entscheidender Bedeutung." +} + ''', + "\nErstelle jetzt das JSON-Objekt für die oben genannte Kombination aus Branche und Ansprechpartner." + ]) + +def main(specific_branch=None): + """Hauptfunktion zur Generierung der Marketing-Texte.""" + logging.info("Starte die Generierung der Marketing-Textblöcke...") + + Config.load_api_keys() + openai.api_key = Config.API_KEYS.get('openai') + if not openai.api_key: + logging.critical("OpenAI API Key nicht gefunden. Skript wird beendet.") + return + + try: + with open(KNOWLEDGE_BASE_FILE, 'r', encoding='utf-8') as f: + knowledge_base = yaml.safe_load(f) + except FileNotFoundError: + logging.critical(f"FEHLER: Die Wissensbasis '{KNOWLEDGE_BASE_FILE}' wurde nicht gefunden.") + return + + results = [] + + target_branches = knowledge_base.get('Branchen', {}) + if specific_branch: + if specific_branch in target_branches: + logging.info(f"Fokus auf einzelne Branche: {specific_branch}") + target_branches = {specific_branch: target_branches[specific_branch]} + else: + logging.error(f"FEHLER: Die angegebene Branche '{specific_branch}' wurde in der Wissensbasis nicht gefunden.") + return + + positions = knowledge_base.get('Positionen', {}) + + for branch_name, branch_data in target_branches.items(): + for position_key, position_data in positions.items(): + logging.info(f"--- Generiere Texte für: Branche='{branch_name}', Position='{position_key}' ---") + + prompt = build_prompt(branch_name, branch_data, position_data.get('name_DE', position_key), position_data) + + # Hier könnten wir noch eine DE/EN Schleife einbauen, für den Moment nur DE + generated_json = call_openai_with_retry(prompt) + + if generated_json: + results.append({ + 'Branch Detail': branch_name, + 'Department': position_key, + 'Language': 'DE', + 'Subject': generated_json.get('Subject', 'FEHLER BEI GENERIERUNG'), + 'Introduction_Textonly': generated_json.get('Introduction_Textonly', 'FEHLER BEI GENERIERUNG'), + 'Industry References (Text only)': branch_data.get('references_DE', '') + }) + else: + results.append({ + 'Branch Detail': branch_name, + 'Department': position_key, + 'Language': 'DE', + 'Subject': 'FEHLER: KI-Antwort war ungültig', + 'Introduction_Textonly': 'FEHLER: KI-Antwort war ungültig', + 'Industry References (Text only)': branch_data.get('references_DE', '') + }) + time.sleep(2) # Pause zur Schonung der API + + # Ergebnisse in eine Excel-Datei schreiben + if results: + df = pd.DataFrame(results) + df.to_excel(OUTPUT_FILE, index=False) + logging.info(f"\nErfolgreich! {len(results)} Textvarianten wurden in '{OUTPUT_FILE}' gespeichert.") + else: + logging.info("Keine Textvarianten wurden generiert.") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Generiert Marketing-Textblöcke basierend auf der Wissensbasis.") + parser.add_argument("--branch", type=str, help="Generiert Texte nur für diese eine Branche.") + args = parser.parse_args() + + main(specific_branch=args.branch) \ No newline at end of file