From 0007a3ff1d5dd67800abc8c5b7375cea6009d5c2 Mon Sep 17 00:00:00 2001 From: Floke Date: Tue, 22 Jul 2025 05:14:18 +0000 Subject: [PATCH] Umstellen Schreiben nach Google Sheets --- generate_marketing_text.py | 67 ++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/generate_marketing_text.py b/generate_marketing_text.py index 69248f26..9f1b9f92 100644 --- a/generate_marketing_text.py +++ b/generate_marketing_text.py @@ -9,29 +9,33 @@ import json import pandas as pd import argparse from config import Config +# NEU: Importiere unseren GoogleSheetHandler +from google_sheet_handler import GoogleSheetHandler # --- 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" # Das neueste und beste Modell für diese Aufgabe +# NEU: Definiere den Namen des Ziel-Tabellenblatts +OUTPUT_SHEET_NAME = "Texte_Automation" +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.""" + # ... (Diese Funktion bleibt unverändert) ... 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 + response_format={"type": "json_object"}, 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 + return json.loads(content) except json.JSONDecodeError as e: logging.error(f"Fehler beim Parsen der JSON-Antwort von OpenAI: {e}") logging.debug(f"Rohe Antwort: {content}") @@ -47,25 +51,22 @@ def call_openai_with_retry(prompt, max_retries=3, delay=5): def build_prompt(branch_name, branch_data, position_name, position_data): """Baut den finalen Master-Prompt (v4.1) zusammen.""" - + # ... (Diese Funktion bleibt unverändert) ... 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 und brillanter Texter. Du verstehst die Herausforderungen einer Branche und einer spezifischen Management-Rolle und formulierst elegante, unaufdringliche und hochrelevante E-Mail-Texte.", "AUFGABE: Erstelle 3 Textblöcke (Subject, Introduction_Textonly, Industry_References_Textonly) für eine E-Mail.", - "\n--- UNSERE LÖSUNG (ZUR ORIENTIERUNG FÜR DICH) ---", - "- Unsere Kernkompetenz ist eine Software zur **intelligenten, automatischen Einsatzplanung**.", - "- Wir bieten zudem eine **mobile App** für die Techniker im Außendienst.", - + "- Unsere Kernkompetenz ist eine Software zur intelligenten, automatischen Einsatzplanung.", + "- Wir bieten zudem 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}", f"\nREFERENZKUNDEN (Rohdaten):\n{branch_data.get('references_DE', 'Keine spezifischen Referenzen vorhanden.')}", - "\n--- DEINE AUFGABE ---", "1. **Subject:** Formuliere eine kurze Betreffzeile (max. 5 Wörter). Richte sie **direkt an einem der persönlichen Pain Points** des Ansprechpartners (z.B. 'Kostenkontrolle im Service', 'Nahtlose Systemintegration').", "2. **Introduction_Textonly:** Formuliere einen Einleitungstext (2 Sätze).", @@ -75,7 +76,6 @@ def build_prompt(branch_name, branch_data, position_name, position_data): " - **Satz 1 (Social Proof):** Nenne **alle bereitgestellten Referenzkunden** aus den Rohdaten. Wenn quantitative Erfolge (z.B. '% Einsparung', 'Anzahl Techniker') genannt sind, integriere diese elegant. Formuliere z.B. 'Zu unseren Kunden zählen namhafte Unternehmen wie...'.", " - **Satz 2 (Branchen-Expertise):** Betone unsere Erfahrung in der Branche. Formuliere z.B. 'Durch die langjährige Zusammenarbeit sind wir mit den spezifischen Anforderungen der [Branche] bestens vertraut.'", " - **Satz 3 (Rollen-Relevanz):** Schaffe den direkten Nutzen für die Zielperson. Formuliere z.B. 'Dieser Wissensvorsprung hilft uns, Ihre [persönlicher Pain Point der Rolle, z.B. 'Integrations-Herausforderungen'] besonders effizient zu lösen.'", - "\n--- BEISPIEL FÜR EINEN PERFEKTEN OUTPUT (Kombination Anlagenbau & IT) ---", ''' { @@ -87,26 +87,34 @@ def build_prompt(branch_name, branch_data, position_name, position_data): "\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 - + # --- NEU: Alle Initialisierungen in einen try-Block --- try: + Config.load_api_keys() + openai.api_key = Config.API_KEYS.get('openai') + if not openai.api_key: + raise ValueError("OpenAI API Key nicht gefunden.") + with open(KNOWLEDGE_BASE_FILE, 'r', encoding='utf-8') as f: knowledge_base = yaml.safe_load(f) + + # NEU: GoogleSheetHandler initialisieren + logging.info("Initialisiere GoogleSheetHandler...") + sheet_handler = GoogleSheetHandler() + except FileNotFoundError: logging.critical(f"FEHLER: Die Wissensbasis '{KNOWLEDGE_BASE_FILE}' wurde nicht gefunden.") return + except Exception as e: + logging.critical(f"FEHLER bei der Initialisierung: {e}") + return results = [] + # ... (Die Logik zur Auswahl der Branchen und Positionen bleibt unverändert) ... target_branches = knowledge_base.get('Branchen', {}) if specific_branch: if specific_branch in target_branches: @@ -116,15 +124,14 @@ def main(specific_branch=None): logging.error(f"FEHLER: Die angegebene Branche '{specific_branch}' wurde in der Wissensbasis nicht gefunden.") logging.info(f"Verfügbare Branchen sind: {list(knowledge_base.get('Branchen', {}).keys())}") return - positions = knowledge_base.get('Positionen', {}) - + + # --- NEU: Der Generierungs-Loop bleibt gleich, aber der Output ist anders --- 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) - generated_json = call_openai_with_retry(prompt) if generated_json: @@ -134,7 +141,7 @@ def main(specific_branch=None): 'Language': 'DE', 'Subject': generated_json.get('Subject', 'FEHLER BEI GENERIERUNG'), 'Introduction_Textonly': generated_json.get('Introduction_Textonly', 'FEHLER BEI GENERIERUNG'), - 'Industry References (Text only)': generated_json.get('Industry_References_Textonly', 'FEHLER BEI GENERIERUNG') # <<< DAS IST DIE ENTSCHEIDENDE KORREKTUR + 'Industry References (Text only)': generated_json.get('Industry_References_Textonly', 'FEHLER BEI GENERIERUNG') }) else: results.append({ @@ -143,14 +150,24 @@ def main(specific_branch=None): 'Language': 'DE', 'Subject': 'FEHLER: KI-Antwort war ungültig', 'Introduction_Textonly': 'FEHLER: KI-Antwort war ungültig', - 'Industry References (Text only)': 'FEHLER: KI-Antwort war ungültig' # Auch hier korrigiert + 'Industry References (Text only)': 'FEHLER: KI-Antwort war ungültig' }) time.sleep(2) + # --- NEU: Ergebnisse in Google Sheet schreiben statt in Excel --- if results: + # Konvertiere die Ergebnisse in das Format, das der Handler erwartet: Liste von Listen df = pd.DataFrame(results) - df.to_excel(OUTPUT_FILE, index=False) - logging.info(f"\nErfolgreich! {len(results)} Textvarianten wurden in '{OUTPUT_FILE}' gespeichert.") + header = df.columns.tolist() + values = df.values.tolist() + data_to_write = [header] + values + + # Rufe unsere neue Handler-Methode auf + success = sheet_handler.clear_and_write_data(OUTPUT_SHEET_NAME, data_to_write) + if success: + logging.info(f"\nErfolgreich! {len(results)} Textvarianten wurden in das Google Sheet '{OUTPUT_SHEET_NAME}' geschrieben.") + else: + logging.error("\nFehler! Die Textvarianten konnten nicht in das Google Sheet geschrieben werden.") else: logging.info("Keine Textvarianten wurden generiert.")