Final Pitch Polish & Data-to-Text Mapping

- FEATURE: Techniker-Buckets werden nun in `data_processor.py` in natürlichsprachliche Phrasen ("eine große Serviceorganisation") übersetzt, was die Prompt-Qualität verbessert.
- REFACTOR: Der FSM-Pitch-Prompt in `helpers.py` wurde final poliert, um eine positivere, partnerschaftlichere Tonalität zu fördern und die Eignung als "Door Opener" zu maximieren.
- Dies stellt den finalen Stand des FSM-Pitch-Moduls dar, optimiert für den Einsatz in der Marketing-Automation.
This commit is contained in:
2025-07-21 13:14:42 +00:00
parent 0726803839
commit aee0707285

View File

@@ -1031,21 +1031,18 @@ def generate_fsm_pitch(
techniker_bucket_ml, techniker_bucket_ml,
): ):
""" """
Generiert einen FSM-Pitch basierend auf dem bewährten "Chain of Thought"-Master-Prompt (v2.3.2). Generiert einen FSM-Pitch basierend auf dem finalen Master-Prompt (v2.3.3).
Liefert den qualitativ hochwertigsten, für die E-Mail-Ansprache geeigneten Satz. Liefert einen strategischen, positiv formulierten Satz für die E-Mail-Ansprache.
""" """
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# 1. Datenaufbereitung (Unsere technische Verbesserung) # 1. Datenaufbereitung
parts = [] parts = []
if website_summary and '**GESCHÄFTSMODELL**' in website_summary: if website_summary and '**GESCHÄFTSMODELL**' in website_summary:
try: try:
summary_text = website_summary.split('Zusammenfassung:')[1].split('**FSM-POTENZIAL**')[0].strip() summary_text = website_summary.split('Zusammenfassung:')[1].split('**FSM-POTENZIAL**')[0].strip()
if summary_text: if summary_text: parts.append(f"Zusammenfassung der Website: {summary_text}")
parts.append(f"Zusammenfassung der Website: {summary_text}") except IndexError: pass
except IndexError:
if 'k.a.' not in website_summary.lower():
parts.append(f"Zusammenfassung der Website: {website_summary}")
elif website_summary and 'k.a.' not in website_summary.lower(): elif website_summary and 'k.a.' not in website_summary.lower():
parts.append(f"Zusammenfassung der Website: {website_summary}") parts.append(f"Zusammenfassung der Website: {website_summary}")
@@ -1053,67 +1050,65 @@ def generate_fsm_pitch(
parts.append(f"Wikipedia-Einleitung: {wiki_absatz}") parts.append(f"Wikipedia-Einleitung: {wiki_absatz}")
combined = "\n".join(parts) combined = "\n".join(parts)
if not combined: return "FEHLER (Mangelnde Daten)"
if len(combined.split()) < 10: # 2. Namenswahl
logger.warning(f"Zu wenige Informationen für FSM-Pitch bei {company_name}.")
return "FEHLER (Mangelnde Daten)"
# 2. Namenswahl & 3. Personalinfo (Ihre bewährte Logik)
display_name = company_short_name if company_short_name and company_short_name.lower() != 'k.a.' else company_name display_name = company_short_name if company_short_name and company_short_name.lower() != 'k.a.' else company_name
# 3. VERBESSERTE Personalinfo-Generierung
personal_info = "" personal_info = ""
try: try:
tech = int(anzahl_techniker or 0) tech_val = int(anzahl_techniker or 0)
ma = int(anzahl_ma or 0) ma_val = int(anzahl_ma or 0)
if tech > 0: if tech_val > 0:
personal_info = f"Ihre rund {int(round(tech, -1))} Servicetechniker" personal_info = f"Ihrer Serviceorganisation mit rund {int(round(tech_val, -1))} Technikern"
elif techniker_bucket_ml and 'k.a.' not in techniker_bucket_ml.lower(): elif techniker_bucket_ml and 'k.a.' not in techniker_bucket_ml.lower():
personal_info = f"Ihre schätzungsweise {techniker_bucket_ml} Servicetechniker" if "Klein" in techniker_bucket_ml: personal_info = "Ihrem wachsenden Serviceteam"
elif ma > 0: elif "Mittel" in techniker_bucket_ml: personal_info = "Ihrer mittelgroßen Serviceorganisation"
personal_info = f"Ihre über {int(round(ma, -1))} Mitarbeiter" elif "Gross" in techniker_bucket_ml: personal_info = "Ihrer großen Serviceorganisation mit über 250 Technikern"
except (ValueError, TypeError): elif ma_val > 0:
pass personal_info = f"Ihrem Unternehmen mit über {int(round(ma_val, -2))} Mitarbeitern"
except (ValueError, TypeError): pass
# 4. IHR MASTER-PROMPT # 4. Der finale, polierte MASTER-PROMPT
prompt_parts = [ prompt_parts = [
"Du bist ein B2B-Stratege, der die verborgenen operativen Herausforderungen eines Unternehmens erkennt und präzise auf den Punkt bringt.", "Du bist ein exzellenter B2B-Stratege und Texter. Deine Aufgabe ist es, für ein Unternehmen einen hochpersonalisierten, scharfsinnigen und wertschätzenden Einleitungssatz für eine E-Mail zu formulieren.",
"Aufgabe:", "Aufgabe:",
"Formuliere EINEN EINZIGEN, flüssig lesbaren Satz (ca. 2035 Wörter), der als hochpersonalisierter Einstieg in einer E-Mail dient.", "Formuliere EINEN EINZIGEN, flüssig lesbaren Satz (ca. 2035 Wörter), der eine operative Kernkompetenz des Unternehmens beobachtet und deren Wichtigkeit für den Geschäftserfolg hervorhebt.",
"Stil-Regeln:", "",
"• Absolut NICHT werblich klingen. Keine Produktnamen, keine direkten Lösungsangebote.", "--- Tonalität & Stil (SEHR WICHTIG) ---",
"Formuliere es als eine scharfsinnige Beobachtung über die operative Tätigkeit des Unternehmens.", "Absolut NICHT werblich, sondern partnerschaftlich und beobachtend.",
"Der Satz muss spezifische Keywords aus der Unternehmensbeschreibung aufgreifen.", "Beginne den Satz entweder mit 'Angesichts Ihrer Spezialisierung auf...' oder 'Für ein Unternehmen wie [Kurzname], das...'.",
"________________________________________", "• Der Satz muss eine positive operative Herausforderung implizieren (z.B. 'ist die Effizienz entscheidend' statt 'ist Ineffizienz ein Problem').",
"Denkprozess (Schritt für Schritt):", "• Verwende IMMER den bereitgestellten 'Kurznamen', niemals die volle Firmierung.",
"1. Analysiere die untenstehenden Unternehmensdaten.", "",
"2. Identifiziere die spezifischste genannte Dienstleistung oder das spezifischste Produkt (z. B. „Installation von Wärmepumpen“, „Wartung von Aufzügen“).", "--- Denkprozess (Schritt für Schritt) ---",
"3. Leite daraus die konkrete operative Tätigkeit ab, die von mobilen Teams durchgeführt wird (z. B. Installations-Termine“, „Störungsbehebungen“).", "1. Analysiere die Beschreibung, um die **spezifischste Service-Tätigkeit** zu finden (z.B. 'Installation von Glasfaseranschlüssen', 'Wartung von Produktionsanlagen').",
"4. Formuliere den finalen Satz, der diese spezifische Tätigkeit und die Personalinfo elegant verbindet, idealerweise beginnend mit '[Unternehmensname] steht vor der Herausforderung...'.", "2. Formuliere den Satz, der diese Tätigkeit mit der Personalinfo und einer positiven geschäftlichen Konsequenz (z.B. 'entscheidend für die Kundenzufriedenheit', 'der Schlüssel zum Projekterfolg') verbindet.",
"________________________________________", "",
"Unternehmenskontext:", "--- Exzellente Beispiele für den Zielsatz ---",
f"• Unternehmen: {display_name}", "Beispiel 1: Für ein Unternehmen wie 2G Energy, das bei über 8.500 installierten Modulen weltweit den Service sicherstellt, ist die effiziente Koordination Ihrer 200 Servicetechniker entscheidend für die maximale Anlagenverfügbarkeit.",
f"• Branche: {ki_branche}", "Beispiel 2: Angesichts der Spezialisierung von 1KOMMA5° auf die schnelle und effiziente Installation von integrierten Energielösungen ist die reibungslose Planung Ihres wachsenden Serviceteams der Schlüssel zur Sicherstellung der Kundenzufriedenheit.",
f"• Beschreibung:\n{combined}", "",
f"• Personalinfo für den Satz: {personal_info if personal_info else 'Keine Angabe'}", "--- Selbstkritik ---",
"________________________________________", "Wenn die Beschreibung keine konkrete Service-Tätigkeit erkennen lässt (z.B. reiner Handel, Online-Portal), antworte NUR mit: FEHLER_DATEN",
"Beispiele für den gewünschten Output-Stil:", "",
"• Beispiel 1 (Installateur):", "--- Unternehmenskontext für deine Aufgabe ---",
"1KOMMA5° steht vor der Herausforderung, mit einer begrenzten Anzahl von Servicetechnikern die steigende Nachfrage nach schnellen und effizienten Installationen von integrierten Energielösungen zu bewältigen, um Kundenzufriedenheit sicherzustellen.", f"Kurzname des Unternehmens: {display_name}",
"• Beispiel 2 (Hersteller mit Service):", f"Branche: {ki_branche}",
"2G Energy steht vor der Herausforderung, ihre 200 Servicetechniker effizient zu koordinieren, um die zunehmende Nachfrage nach Vor-Ort-Service und digitaler Wartung bei über 8.500 installierten Modulen weltweit zeitnah zu erfüllen.", f"Beschreibung:\n{combined}",
"• Beispiel 3 (Hersteller ohne direkten Service-Text):", f"Personalinfo für den Satz: {personal_info if personal_info else 'Keine Angabe'}",
"Angesichts Ihrer Spezialisierung auf die Entwicklung und Herstellung von Highend-Produktionsanlagen für kritische Industrien, ist die präzise Projektplanung und -umsetzung durch Ihre über 450 Mitarbeiter der Schlüssel zum Erfolg.", "",
"________________________________________", "--- Deine Ausgabe ---",
"Deine Aufgabe:", "Gib NUR den finalen, perfekt formulierten Satz aus ODER das Wort 'FEHLER_DATEN'.",
"Führe den Denkprozess durch und gib NUR den finalen, perfekten Satz für das oben genannte Unternehmen aus:",
] ]
prompt = "\n".join(prompt_parts) prompt = "\n".join(prompt_parts)
try: try:
fsm_pitch = call_openai_chat(prompt, temperature=0.6, model="gpt-4o") fsm_pitch = call_openai_chat(prompt, temperature=0.6, model="gpt-4o")
if not fsm_pitch or len(fsm_pitch.split()) < 7: # Einfacher Check auf eine minimale Satzlänge if not fsm_pitch or "FEHLER_DATEN" in fsm_pitch:
logger.warning(f"KI konnte keinen validen FSM-Pitch für {company_name} generieren (Antwort zu kurz).") logger.warning(f"KI konnte keinen validen FSM-Pitch für {company_name} generieren (Grund: Mangelnde/unspezifische Daten).")
return "FEHLER (KI-Antwort unzureichend)" return "FEHLER (Mangelnde Daten)"
return fsm_pitch.strip().replace('"', '') return fsm_pitch.strip().replace('"', '')
except Exception as e: except Exception as e:
logger.error(f"Fehler bei der Generierung des FSM-Pitches für {company_name}: {e}") logger.error(f"Fehler bei der Generierung des FSM-Pitches für {company_name}: {e}")