Finalized FSM Pitch Generation
- REVERT: Zurück zur bewährten, ursprünglichen FSM-Pitch-Prompt-Logik, die die besten Ergebnisse in Tonalität und Spezifität geliefert hat. - FIX: Die Datenaufbereitung wurde an die neue, strukturierte Website-Zusammenfassung angepasst, um eine saubere Input-Qualität für die KI sicherzustellen. - Das FSM-Pitch-Modul ist nun finalisiert und liefert qualitativ hochwertige, für die Marketing-Automation geeignete Ergebnisse.
This commit is contained in:
92
helpers.py
92
helpers.py
@@ -1031,72 +1031,80 @@ def generate_fsm_pitch(
|
|||||||
techniker_bucket_ml,
|
techniker_bucket_ml,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Generiert einen FSM-Pitch mittels eines "Few-Shot"-Ansatzes, der auf exzellenten
|
Generiert einen maßgeschneiderten, nicht-werblichen Satz, der eine operative
|
||||||
Beispielen basiert, um eine aktive, pointierte Tonalität zu gewährleisten (v2.2.9).
|
Service-Herausforderung des Unternehmens beschreibt (v2.3.0, basierend auf der bewährten v2.1-Logik).
|
||||||
"""
|
"""
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# 1. Datenaufbereitung
|
# 1. VERBESSERTER Daten-Check (aus v2.2.x übernommen)
|
||||||
beschreibung_kombiniert = []
|
# Extrahiert intelligent die reine Zusammenfassung aus dem strukturierten Analyse-Text
|
||||||
|
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: beschreibung_kombiniert.append(f"Website-Zusammenfassung: {summary_text}")
|
if summary_text:
|
||||||
except IndexError: pass
|
parts.append(f"Website-Zusammenfassung: {summary_text}")
|
||||||
|
except IndexError:
|
||||||
|
# Fallback, falls das Format unerwartet ist, aber trotzdem verwenden
|
||||||
|
if 'k.a.' not in website_summary.lower():
|
||||||
|
parts.append(f"Website-Zusammenfassung: {website_summary}")
|
||||||
|
elif website_summary and 'k.a.' not in website_summary.lower():
|
||||||
|
parts.append(f"Website-Zusammenfassung: {website_summary}")
|
||||||
|
|
||||||
if wiki_absatz and 'k.a.' not in wiki_absatz.lower():
|
if wiki_absatz and 'k.a.' not in wiki_absatz.lower():
|
||||||
beschreibung_kombiniert.append(f"Wikipedia-Einleitung: {wiki_absatz}")
|
parts.append(f"Wikipedia-Einleitung: {wiki_absatz}")
|
||||||
|
|
||||||
final_beschreibung = "\n".join(beschreibung_kombiniert)
|
combined = "\n".join(parts)
|
||||||
|
|
||||||
if not final_beschreibung:
|
if len(combined.split()) < 10:
|
||||||
|
logger.warning(f"Zu wenige Informationen für FSM-Pitch bei {company_name}.")
|
||||||
return "FEHLER (Mangelnde Daten)"
|
return "FEHLER (Mangelnde Daten)"
|
||||||
|
|
||||||
# 2. Namenswahl und 3. Personalinfo
|
# 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
|
||||||
|
|
||||||
personal_info = ""
|
def round_number(n):
|
||||||
|
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"Ihre rund {int(round(tech, -1))} Servicetechniker"
|
personal_info = f"bei rund {round_number(tech)} Servicetechnikern"
|
||||||
elif techniker_bucket_ml and 'k.a.' not in techniker_bucket_ml.lower(): personal_info = f"Ihre schätzungsweise {techniker_bucket_ml} Servicetechniker"
|
elif techniker_bucket_ml and 'k.a.' not in techniker_bucket_ml.lower():
|
||||||
elif ma > 0: personal_info = f"Ihre über {int(round(ma, -2))} Mitarbeiter"
|
personal_info = f"bei schätzungsweise {techniker_bucket_ml} Servicetechnikern"
|
||||||
except (ValueError, TypeError): pass
|
elif int(anzahl_ma or 0) > 0:
|
||||||
|
personal_info = f"bei über {round_number(int(anzahl_ma))} Mitarbeitern"
|
||||||
|
except Exception:
|
||||||
|
logger.debug("Keine validen MA/Techniker-Zahlen für Pitch.")
|
||||||
|
|
||||||
# 4. Der finale "Few-Shot"-Prompt
|
# 4. Ihr bewährter Prompt
|
||||||
prompt_parts = [
|
prompt_parts = [
|
||||||
"Du bist ein exzellenter B2B-Stratege und Texter. Deine Aufgabe ist es, für ein Unternehmen einen hochpersonalisierten und scharfsinnigen Einleitungssatz für eine E-Mail zu formulieren, der deren zentrale operative Herausforderung im Außendienst adressiert.",
|
"Du bist ein B2B-Stratege und Texter, der operative Service-Herausforderungen punktgenau beschreibt.",
|
||||||
|
"Aufgabe: Formuliere EINEN flüssig lesbaren Satz (20–35 Wörter) zur **hochspezifischen** Service-Herausforderung.",
|
||||||
"",
|
"",
|
||||||
"--- Denkprozess ---",
|
"--- Stil-Regeln ---",
|
||||||
"1. **Identifiziere die Kern-Service-Tätigkeit:** Was tun die mobilen Teams des Unternehmens? (z.B. Installationen, Wartung, Reparatur).",
|
"- Nicht werblich.",
|
||||||
"2. **Quantifiziere die Herausforderung:** Verbinde die Tätigkeit mit der Unternehmensgröße oder der Anzahl der Anlagen/Kunden.",
|
"- Nutze den Kurznamen ohne Anführungszeichen.",
|
||||||
"3. **Formuliere den Satz:** Schreibe einen aktiven Satz, der mit 'UNTERNEHMENSNAME steht vor der Herausforderung...' beginnt. Der Satz muss die Tätigkeit, die Skalierung und das Geschäftsziel (z.B. Kundenzufriedenheit, Effizienz) verbinden.",
|
"- Vermeide allgemeine Phrasen wie 'Schlüssel zum Erfolg'.",
|
||||||
"4. **Nutze den Kurznamen:** Verwende IMMER den bereitgestellten 'Kurzname des Unternehmens', nicht die volle Firmierung.",
|
|
||||||
"",
|
"",
|
||||||
"--- Exzellente Beispiele für den Zielsatz ---",
|
"--- Kontext ---",
|
||||||
"Beispiel 1: 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: {display_name}",
|
||||||
"Beispiel 2: 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"Branche: {ki_branche}",
|
||||||
"Beispiel 3: 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.",
|
f"Beschreibung: {combined}",
|
||||||
|
f"Personalinfo: {personal_info}",
|
||||||
|
f"Gesamtmitarbeiterzahl: {anzahl_ma}",
|
||||||
"",
|
"",
|
||||||
"--- Selbstkritik ---",
|
"Bei zu allgemeiner Beschreibung → FEHLER_DATEN",
|
||||||
"Wenn die Beschreibung keine konkrete Service-Tätigkeit erkennen lässt (z.B. reiner Handel, Online-Portal), antworte NUR mit dem Wort 'FEHLER_DATEN'.",
|
|
||||||
"",
|
|
||||||
"--- Unternehmenskontext für deine Aufgabe ---",
|
|
||||||
f"Kurzname des Unternehmens: {display_name}",
|
|
||||||
f"KI-validierte Branche: {ki_branche}",
|
|
||||||
f"Beschreibung: {final_beschreibung}",
|
|
||||||
f"Personalinfo für den Satz: {personal_info if personal_info else 'Keine Angabe'}",
|
|
||||||
"",
|
|
||||||
"--- Deine Ausgabe ---",
|
|
||||||
"Gib NUR den finalen, perfekt formulierten Satz aus ODER das Wort 'FEHLER_DATEN'.",
|
|
||||||
]
|
]
|
||||||
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 "FEHLER_DATEN" in fsm_pitch:
|
||||||
logger.warning(f"KI konnte keinen validen FSM-Pitch für {company_name} generieren (Grund: Mangelnde/unspezifische Daten).")
|
logger.warning(f"KI konnte keinen validen FSM-Pitch für {company_name} generieren.")
|
||||||
return "FEHLER (Mangelnde Daten)"
|
return "FEHLER (Mangelnde Daten)"
|
||||||
return fsm_pitch.strip().replace('"', '')
|
return fsm_pitch.strip().replace('"', '')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user