The Definitive FSM Pitch (Master Prompt Implementation)

- REVERT & FINALIZE: Der FSM-Pitch-Prompt wurde auf die bewährte "Chain of Thought"-Version zurückgesetzt, die die qualitativ besten Ergebnisse liefert.
- FIX: Die Datenaufbereitung und die Anweisung zur Verwendung des Kurznamens wurden integriert, um die Zuverlässigkeit zu maximieren.
- Dies ist die finale, produktionsreife Version des FSM-Pitch-Moduls.
This commit is contained in:
2025-07-21 12:53:40 +00:00
parent 57afdb6bcd
commit ad4f4ec127

View File

@@ -1031,25 +1031,23 @@ def generate_fsm_pitch(
techniker_bucket_ml, techniker_bucket_ml,
): ):
""" """
Generiert einen maßgeschneiderten, nicht-werblichen Satz, der eine operative Generiert einen FSM-Pitch basierend auf dem bewährten "Chain of Thought"-Master-Prompt (v2.3.2).
Service-Herausforderung des Unternehmens beschreibt (v2.3.0, basierend auf der bewährten v2.1-Logik). Liefert den qualitativ hochwertigsten, für die E-Mail-Ansprache geeigneten Satz.
""" """
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# 1. VERBESSERTER Daten-Check (aus v2.2.x übernommen) # 1. Datenaufbereitung (Unsere technische Verbesserung)
# Extrahiert intelligent die reine Zusammenfassung aus dem strukturierten Analyse-Text
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"Website-Zusammenfassung: {summary_text}") parts.append(f"Zusammenfassung der Website: {summary_text}")
except IndexError: except IndexError:
# Fallback, falls das Format unerwartet ist, aber trotzdem verwenden
if 'k.a.' not in website_summary.lower(): if 'k.a.' not in website_summary.lower():
parts.append(f"Website-Zusammenfassung: {website_summary}") 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"Website-Zusammenfassung: {website_summary}") parts.append(f"Zusammenfassung der Website: {website_summary}")
if wiki_absatz and 'k.a.' not in wiki_absatz.lower(): if wiki_absatz and 'k.a.' not in wiki_absatz.lower():
parts.append(f"Wikipedia-Einleitung: {wiki_absatz}") parts.append(f"Wikipedia-Einleitung: {wiki_absatz}")
@@ -1063,49 +1061,57 @@ def generate_fsm_pitch(
# 2. Namenswahl & 3. Personalinfo (Ihre bewährte Logik) # 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
def round_number(n): personal_info = ""
if n < 100: return n
if n < 1000: return int(round(n / 50.0)) * 50
return int(round(n / 100.0)) * 100
personal_info = "in einem Unternehmen Ihrer Größe"
try: try:
tech = int(anzahl_techniker or 0) tech = int(anzahl_techniker or 0)
ma = int(anzahl_ma or 0)
if tech > 0: if tech > 0:
personal_info = f"bei rund {round_number(tech)} Servicetechnikern" personal_info = f"Ihre rund {int(round(tech, -1))} Servicetechniker"
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"bei schätzungsweise {techniker_bucket_ml} Servicetechnikern" personal_info = f"Ihre schätzungsweise {techniker_bucket_ml} Servicetechniker"
elif int(anzahl_ma or 0) > 0: elif ma > 0:
personal_info = f"bei über {round_number(int(anzahl_ma))} Mitarbeitern" personal_info = f"Ihre über {int(round(ma, -1))} Mitarbeiter"
except Exception: except (ValueError, TypeError):
logger.debug("Keine validen MA/Techniker-Zahlen für Pitch.") pass
# 4. Ihr bewährter Prompt # 4. IHR MASTER-PROMPT
prompt_parts = [ prompt_parts = [
"Du bist ein B2B-Stratege und Texter, der operative Service-Herausforderungen punktgenau beschreibt.", "Du bist ein B2B-Stratege, der die verborgenen operativen Herausforderungen eines Unternehmens erkennt und präzise auf den Punkt bringt.",
"Aufgabe: Formuliere EINEN flüssig lesbaren Satz (2035 Wörter) zur **hochspezifischen** Service-Herausforderung.", "Aufgabe:",
"", "Formuliere EINEN EINZIGEN, flüssig lesbaren Satz (ca. 2035 Wörter), der als hochpersonalisierter Einstieg in einer E-Mail dient.",
"--- Stil-Regeln ---", "Stil-Regeln:",
"- Nicht werblich.", "• Absolut NICHT werblich klingen. Keine Produktnamen, keine direkten Lösungsangebote.",
"- Nutze den Kurznamen ohne Anführungszeichen.", "• Formuliere es als eine scharfsinnige Beobachtung über die operative Tätigkeit des Unternehmens.",
"- Vermeide allgemeine Phrasen wie 'Schlüssel zum Erfolg'.", "• Der Satz muss spezifische Keywords aus der Unternehmensbeschreibung aufgreifen.",
"", "________________________________________",
"--- Kontext ---", "Denkprozess (Schritt für Schritt):",
f"Kurzname: {display_name}", "1. Analysiere die untenstehenden Unternehmensdaten.",
f"Branche: {ki_branche}", "2. Identifiziere die spezifischste genannte Dienstleistung oder das spezifischste Produkt (z. B. „Installation von Wärmepumpen“, „Wartung von Aufzügen“).",
f"Beschreibung: {combined}", "3. Leite daraus die konkrete operative Tätigkeit ab, die von mobilen Teams durchgeführt wird (z. B. „Installations-Termine“, „Störungsbehebungen“).",
f"Personalinfo: {personal_info}", "4. Formuliere den finalen Satz, der diese spezifische Tätigkeit und die Personalinfo elegant verbindet, idealerweise beginnend mit '[Unternehmensname] steht vor der Herausforderung...'.",
f"Gesamtmitarbeiterzahl: {anzahl_ma}", "________________________________________",
"", "Unternehmenskontext:",
"Bei zu allgemeiner Beschreibung → FEHLER_DATEN", f"• Unternehmen: {display_name}",
f"• Branche: {ki_branche}",
f"• Beschreibung:\n{combined}",
f"• Personalinfo für den Satz: {personal_info if personal_info else 'Keine Angabe'}",
"________________________________________",
"Beispiele für den gewünschten Output-Stil:",
"• Beispiel 1 (Branche „Energie“, Beschreibung „…baut Ladeinfrastruktur aus…“):",
"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.",
"• Beispiel 2 (Branche „Anlagenbau“, Beschreibung „…Service für Produktionsanlagen…“):",
"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.",
"________________________________________",
"Deine Aufgabe:",
"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 "FEHLER_DATEN" in fsm_pitch: if not fsm_pitch or len(fsm_pitch.split()) < 7: # Einfacher Check auf eine minimale Satzlänge
logger.warning(f"KI konnte keinen validen FSM-Pitch für {company_name} generieren.") logger.warning(f"KI konnte keinen validen FSM-Pitch für {company_name} generieren (Antwort zu kurz).")
return "FEHLER (Mangelnde Daten)" return "FEHLER (KI-Antwort unzureichend)"
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}")