# 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 from helpers import create_log_filename # NEU: Logging-Funktion importieren from google_sheet_handler import GoogleSheetHandler # --- Konfiguration --- KNOWLEDGE_BASE_FILE = "marketing_wissen_final.yaml" OUTPUT_SHEET_NAME = "Texte_Automation" MODEL_TO_USE = "gpt-4o" # --- Logging einrichten --- # Wird jetzt in main() initialisiert, um einen Dateinamen zu haben def call_openai_with_retry(prompt, max_retries=3, delay=5): # ... (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"}, messages=[{"role": "user", "content": prompt}], temperature=0.6, max_tokens=1024 ) content = response.choices[0].message['content'].strip() return json.loads(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 build_prompt(branch_name, branch_data, position_name, position_data): # ... (Diese Funktion bleibt unverändert, v4.2 ist die korrekte) ... 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...", "AUFGABE: Erstelle 3 Textblöcke (Subject, Introduction_Textonly, Industry_References_Textonly)...", # ... (der Rest des Prompts v4.2) "\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:** ...", "2. **Introduction_Textonly:** ...", "3. **Industry_References_Textonly:** ...", "\n--- BEISPIEL FÜR EINEN PERFEKTEN OUTPUT (Kombination Anlagenbau & IT) ---", ''' { "Subject": "Nahtlose Systemintegration", "Introduction_Textonly": "Genau hier setzt die digitale Unterstützung Ihrer Techniker an, um Serviceberichte direkt vor Ort zu erfassen und die Projektabrechnung zu beschleunigen. Für Sie als IT-Leiter ist dabei die nahtlose und sichere Integration in Ihre bestehende ERP-Landschaft von entscheidender Bedeutung.", "Industry_References_Textonly": "Ihre Marktbegleiter wie Jungheinrich mit weltweit über 4.000 Technikern und Christ Wash Systems, wo 10 % Fahrtzeit eingespart wurde, profitieren bereits von unseren Lösungen. Durch die langjährige Zusammenarbeit sind wir mit den spezifischen Anforderungen von Anlagenbau-Unternehmen, wie der Anbindung an komplexe ERP-Systeme, bestens vertraut. Dieser Wissensvorsprung hilft uns, Ihre Integrations-Herausforderungen besonders effizient und sicher zu lösen." } ''', "\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.""" # --- NEUES, ROBUSTES LOGGING SETUP --- log_file_path = create_log_filename("generate_texts") log_level = logging.INFO log_format = '%(asctime)s - %(levelname)-8s - %(name)-25s - %(message)s' # Root-Logger konfigurieren root_logger = logging.getLogger() root_logger.setLevel(log_level) # Bestehende Handler entfernen, um Dopplung zu vermeiden for handler in root_logger.handlers[:]: root_logger.removeHandler(handler) # Neue Handler hinzufügen root_logger.addHandler(logging.StreamHandler()) # Immer auf der Konsole loggen if log_file_path: file_handler = logging.FileHandler(log_file_path, mode='a', encoding='utf-8') file_handler.setFormatter(logging.Formatter(log_format)) root_logger.addHandler(file_handler) logging.info(f"===== Skript gestartet: Modus 'generate_texts' =====") logging.info(f"Logdatei: {log_file_path}") # --- Initialisierung --- 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) sheet_handler = GoogleSheetHandler() except Exception as e: logging.critical(f"FEHLER bei der Initialisierung: {e}") return # --- NEU: Bestehende Texte aus dem Sheet laden --- try: logging.info(f"Lese bestehende Texte aus dem Tabellenblatt '{OUTPUT_SHEET_NAME}'...") existing_texts_df = sheet_handler.get_sheet_as_dataframe(OUTPUT_SHEET_NAME) if existing_texts_df is not None and not existing_texts_df.empty: existing_combinations = set(zip(existing_texts_df['Branch Detail'], existing_texts_df['Department'])) logging.info(f"{len(existing_combinations)} bereits existierende Kombinationen gefunden.") else: existing_combinations = set() logging.info("Keine bestehenden Texte gefunden. Alle Kombinationen werden neu erstellt.") except Exception as e: logging.error(f"Fehler beim Lesen des '{OUTPUT_SHEET_NAME}'-Sheets. Nehme an, es ist leer. Fehler: {e}") existing_combinations = set() # --- Generierungs-Loop --- newly_generated_results = [] target_branches = knowledge_base.get('Branchen', {}) if specific_branch: # ... (Logik für specific_branch bleibt gleich) ... if specific_branch in target_branches: target_branches = {specific_branch: target_branches[specific_branch]} else: logging.error(f"FEHLER: Die angegebene Branche '{specific_branch}' wurde nicht gefunden.") return positions = knowledge_base.get('Positionen', {}) total_combinations = len(target_branches) * len(positions) logging.info(f"Prüfe {total_combinations} mögliche Kombinationen...") for branch_name, branch_data in target_branches.items(): for position_key, position_data in positions.items(): # NEU: Überspringe, wenn die Kombination bereits existiert if (branch_name, position_key) in existing_combinations: logging.debug(f"Überspringe bereits existierende Kombination: Branche='{branch_name}', Position='{position_key}'") continue logging.info(f"--- Generiere Texte für NEUE Kombination: 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: newly_generated_results.append({ 'Branch Detail': branch_name, 'Department': position_key, 'Language': 'DE', 'Subject': generated_json.get('Subject', 'FEHLER'), 'Introduction_Textonly': generated_json.get('Introduction_Textonly', 'FEHLER'), 'Industry References (Text only)': generated_json.get('Industry_References_Textonly', 'FEHLER') }) else: # Füge einen Fehler-Eintrag hinzu, um zu sehen, was fehlgeschlagen ist newly_generated_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)': 'FEHLER: KI-Antwort war ungültig' }) time.sleep(2) # --- NEU: Hänge neue Ergebnisse an das Sheet an --- if newly_generated_results: logging.info(f"{len(newly_generated_results)} neue Textvarianten wurden generiert.") df_new = pd.DataFrame(newly_generated_results) # Konvertiere in die Liste-von-Listen-Struktur values_to_append = df_new.values.tolist() success = sheet_handler.append_rows(OUTPUT_SHEET_NAME, values_to_append) if success: logging.info(f"Erfolgreich! {len(values_to_append)} neue Textvarianten wurden an das Google Sheet '{OUTPUT_SHEET_NAME}' angehängt.") else: logging.error("Fehler! Die neuen Textvarianten konnten nicht an das Google Sheet angehängt werden.") else: logging.info("Keine neuen Textvarianten zu generieren. Das Sheet ist auf dem neuesten Stand.") 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)