Umstellen Schreiben nach Google Sheets
This commit is contained in:
@@ -9,29 +9,33 @@ import json
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
import argparse
|
import argparse
|
||||||
from config import Config
|
from config import Config
|
||||||
|
# NEU: Importiere unseren GoogleSheetHandler
|
||||||
|
from google_sheet_handler import GoogleSheetHandler
|
||||||
|
|
||||||
# --- Konfiguration ---
|
# --- Konfiguration ---
|
||||||
KNOWLEDGE_BASE_FILE = "marketing_wissen.yaml"
|
KNOWLEDGE_BASE_FILE = "marketing_wissen.yaml"
|
||||||
OUTPUT_FILE = "marketing_text_blocks.xlsx" # Excel ist besser für lange Texte
|
# NEU: Definiere den Namen des Ziel-Tabellenblatts
|
||||||
MODEL_TO_USE = "gpt-4o" # Das neueste und beste Modell für diese Aufgabe
|
OUTPUT_SHEET_NAME = "Texte_Automation"
|
||||||
|
MODEL_TO_USE = "gpt-4o"
|
||||||
|
|
||||||
# --- Logging einrichten ---
|
# --- Logging einrichten ---
|
||||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
def call_openai_with_retry(prompt, max_retries=3, delay=5):
|
def call_openai_with_retry(prompt, max_retries=3, delay=5):
|
||||||
"""Ruft die OpenAI API mit Retry-Logik auf und erwartet eine JSON-Antwort."""
|
"""Ruft die OpenAI API mit Retry-Logik auf und erwartet eine JSON-Antwort."""
|
||||||
|
# ... (Diese Funktion bleibt unverändert) ...
|
||||||
for attempt in range(max_retries):
|
for attempt in range(max_retries):
|
||||||
try:
|
try:
|
||||||
logging.info(f"Sende Prompt an OpenAI (Versuch {attempt + 1}/{max_retries})...")
|
logging.info(f"Sende Prompt an OpenAI (Versuch {attempt + 1}/{max_retries})...")
|
||||||
response = openai.ChatCompletion.create(
|
response = openai.ChatCompletion.create(
|
||||||
model=MODEL_TO_USE,
|
model=MODEL_TO_USE,
|
||||||
response_format={"type": "json_object"}, # Fordert explizit JSON an
|
response_format={"type": "json_object"},
|
||||||
messages=[{"role": "user", "content": prompt}],
|
messages=[{"role": "user", "content": prompt}],
|
||||||
temperature=0.6,
|
temperature=0.6,
|
||||||
max_tokens=1024
|
max_tokens=1024
|
||||||
)
|
)
|
||||||
content = response.choices[0].message['content'].strip()
|
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:
|
except json.JSONDecodeError as e:
|
||||||
logging.error(f"Fehler beim Parsen der JSON-Antwort von OpenAI: {e}")
|
logging.error(f"Fehler beim Parsen der JSON-Antwort von OpenAI: {e}")
|
||||||
logging.debug(f"Rohe Antwort: {content}")
|
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):
|
def build_prompt(branch_name, branch_data, position_name, position_data):
|
||||||
"""Baut den finalen Master-Prompt (v4.1) zusammen."""
|
"""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', [])])
|
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', [])])
|
position_pain_points = "\n".join([f"- {p}" for p in position_data.get('pains_DE', [])])
|
||||||
|
|
||||||
return "\n".join([
|
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.",
|
"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.",
|
"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) ---",
|
"\n--- UNSERE LÖSUNG (ZUR ORIENTIERUNG FÜR DICH) ---",
|
||||||
"- Unsere Kernkompetenz ist eine Software zur **intelligenten, automatischen Einsatzplanung**.",
|
"- Unsere Kernkompetenz ist eine Software zur intelligenten, automatischen Einsatzplanung.",
|
||||||
"- Wir bieten zudem eine **mobile App** für die Techniker im Außendienst.",
|
"- Wir bieten zudem eine mobile App für die Techniker im Außendienst.",
|
||||||
|
|
||||||
"\n--- KONTEXT ---",
|
"\n--- KONTEXT ---",
|
||||||
f"ZIELBRANCHE: {branch_name}",
|
f"ZIELBRANCHE: {branch_name}",
|
||||||
f"BRANCHEN-HERAUSFORDERUNGEN (PAIN POINTS):\n{branch_pain_points}",
|
f"BRANCHEN-HERAUSFORDERUNGEN (PAIN POINTS):\n{branch_pain_points}",
|
||||||
f"\nANSPRECHPARTNER: {position_name}",
|
f"\nANSPRECHPARTNER: {position_name}",
|
||||||
f"PERSÖNLICHE HERAUSFORDERUNGEN DES ANSPRECHPARTNERS (PAIN POINTS):\n{position_pain_points}",
|
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.')}",
|
f"\nREFERENZKUNDEN (Rohdaten):\n{branch_data.get('references_DE', 'Keine spezifischen Referenzen vorhanden.')}",
|
||||||
|
|
||||||
"\n--- DEINE AUFGABE ---",
|
"\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').",
|
"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).",
|
"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 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 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.'",
|
" - **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) ---",
|
"\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."
|
"\nErstelle jetzt das JSON-Objekt für die oben genannte Kombination aus Branche und Ansprechpartner."
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
def main(specific_branch=None):
|
def main(specific_branch=None):
|
||||||
"""Hauptfunktion zur Generierung der Marketing-Texte."""
|
"""Hauptfunktion zur Generierung der Marketing-Texte."""
|
||||||
logging.info("Starte die Generierung der Marketing-Textblöcke...")
|
logging.info("Starte die Generierung der Marketing-Textblöcke...")
|
||||||
|
|
||||||
Config.load_api_keys()
|
# --- NEU: Alle Initialisierungen in einen try-Block ---
|
||||||
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:
|
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:
|
with open(KNOWLEDGE_BASE_FILE, 'r', encoding='utf-8') as f:
|
||||||
knowledge_base = yaml.safe_load(f)
|
knowledge_base = yaml.safe_load(f)
|
||||||
|
|
||||||
|
# NEU: GoogleSheetHandler initialisieren
|
||||||
|
logging.info("Initialisiere GoogleSheetHandler...")
|
||||||
|
sheet_handler = GoogleSheetHandler()
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logging.critical(f"FEHLER: Die Wissensbasis '{KNOWLEDGE_BASE_FILE}' wurde nicht gefunden.")
|
logging.critical(f"FEHLER: Die Wissensbasis '{KNOWLEDGE_BASE_FILE}' wurde nicht gefunden.")
|
||||||
return
|
return
|
||||||
|
except Exception as e:
|
||||||
|
logging.critical(f"FEHLER bei der Initialisierung: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
|
# ... (Die Logik zur Auswahl der Branchen und Positionen bleibt unverändert) ...
|
||||||
target_branches = knowledge_base.get('Branchen', {})
|
target_branches = knowledge_base.get('Branchen', {})
|
||||||
if specific_branch:
|
if specific_branch:
|
||||||
if specific_branch in target_branches:
|
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.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())}")
|
logging.info(f"Verfügbare Branchen sind: {list(knowledge_base.get('Branchen', {}).keys())}")
|
||||||
return
|
return
|
||||||
|
|
||||||
positions = knowledge_base.get('Positionen', {})
|
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 branch_name, branch_data in target_branches.items():
|
||||||
for position_key, position_data in positions.items():
|
for position_key, position_data in positions.items():
|
||||||
logging.info(f"--- Generiere Texte für: Branche='{branch_name}', Position='{position_key}' ---")
|
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)
|
prompt = build_prompt(branch_name, branch_data, position_data.get('name_DE', position_key), position_data)
|
||||||
|
|
||||||
generated_json = call_openai_with_retry(prompt)
|
generated_json = call_openai_with_retry(prompt)
|
||||||
|
|
||||||
if generated_json:
|
if generated_json:
|
||||||
@@ -134,7 +141,7 @@ def main(specific_branch=None):
|
|||||||
'Language': 'DE',
|
'Language': 'DE',
|
||||||
'Subject': generated_json.get('Subject', 'FEHLER BEI GENERIERUNG'),
|
'Subject': generated_json.get('Subject', 'FEHLER BEI GENERIERUNG'),
|
||||||
'Introduction_Textonly': generated_json.get('Introduction_Textonly', '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:
|
else:
|
||||||
results.append({
|
results.append({
|
||||||
@@ -143,14 +150,24 @@ def main(specific_branch=None):
|
|||||||
'Language': 'DE',
|
'Language': 'DE',
|
||||||
'Subject': 'FEHLER: KI-Antwort war ungültig',
|
'Subject': 'FEHLER: KI-Antwort war ungültig',
|
||||||
'Introduction_Textonly': '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)
|
time.sleep(2)
|
||||||
|
|
||||||
|
# --- NEU: Ergebnisse in Google Sheet schreiben statt in Excel ---
|
||||||
if results:
|
if results:
|
||||||
|
# Konvertiere die Ergebnisse in das Format, das der Handler erwartet: Liste von Listen
|
||||||
df = pd.DataFrame(results)
|
df = pd.DataFrame(results)
|
||||||
df.to_excel(OUTPUT_FILE, index=False)
|
header = df.columns.tolist()
|
||||||
logging.info(f"\nErfolgreich! {len(results)} Textvarianten wurden in '{OUTPUT_FILE}' gespeichert.")
|
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:
|
else:
|
||||||
logging.info("Keine Textvarianten wurden generiert.")
|
logging.info("Keine Textvarianten wurden generiert.")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user