Final Refined & Positive-Toned FSM Pitch
- REFACTOR: Der FSM-Pitch-Prompt wurde final überarbeitet, um eine positive, lösungsorientierte Tonalität für die direkte Kundenansprache zu gewährleisten. - FIX: Die "FEHLER_DATEN"-Regel wurde gelockert, um die Erfolgsquote bei der Pitch-Generierung auch bei dünnerer Datenlage zu erhöhen. - Die generierten Pitches sind nun strategisch fundiert UND für die Marketing-Automation geeignet.
This commit is contained in:
59
helpers.py
59
helpers.py
@@ -1031,32 +1031,27 @@ def generate_fsm_pitch(
|
|||||||
techniker_bucket_ml,
|
techniker_bucket_ml,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Generiert einen maßgeschneiderten, nicht-werblichen Satz, der eine operative
|
Generiert einen maßgeschneiderten, positiv formulierten Satz, der eine operative
|
||||||
Service-Herausforderung des Unternehmens beschreibt (v2.1).
|
Service-Herausforderung impliziert und für die Kundenansprache geeignet ist (v2.2.6).
|
||||||
"""
|
"""
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# 1. Daten-Check und Extraktion
|
# 1. Daten-Check und Extraktion der reinen Zusammenfassung
|
||||||
beschreibung_kombiniert = []
|
beschreibung_kombiniert = []
|
||||||
# Extrahiere NUR den reinen Zusammenfassungstext, falls unsere strukturierte Analyse vorliegt
|
|
||||||
if website_summary and '**GESCHÄFTSMODELL**' in website_summary:
|
if website_summary and '**GESCHÄFTSMODELL**' in website_summary:
|
||||||
try:
|
try:
|
||||||
# Extrahiert den Text nach "Zusammenfassung:" und vor dem nächsten Abschnitt
|
|
||||||
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:
|
||||||
beschreibung_kombiniert.append(f"Website-Zusammenfassung: {summary_text}")
|
beschreibung_kombiniert.append(f"Website-Zusammenfassung: {summary_text}")
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# Fallback, falls das Format unerwartet ist
|
pass # Ignoriere Formatierungsfehler, fahre mit anderen Daten fort
|
||||||
beschreibung_kombiniert.append(f"Website-Zusammenfassung: {website_summary}")
|
|
||||||
elif website_summary and 'k.a.' not in website_summary.lower():
|
|
||||||
beschreibung_kombiniert.append(f"Website-Zusammenfassung: {website_summary}") # Für alte, unstrukturierte Zusammenfassungen
|
|
||||||
|
|
||||||
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}")
|
beschreibung_kombiniert.append(f"Wikipedia-Einleitung: {wiki_absatz}")
|
||||||
|
|
||||||
combined = "\n".join(beschreibung_kombiniert)
|
final_beschreibung = "\n".join(beschreibung_kombiniert)
|
||||||
|
|
||||||
if len(combined.split()) < 10:
|
if not final_beschreibung:
|
||||||
logger.warning(f"Zu wenige Informationen für FSM-Pitch bei {company_name}.")
|
logger.warning(f"Zu wenige Informationen für FSM-Pitch bei {company_name}.")
|
||||||
return "FEHLER (Mangelnde Daten)"
|
return "FEHLER (Mangelnde Daten)"
|
||||||
|
|
||||||
@@ -1072,45 +1067,49 @@ def generate_fsm_pitch(
|
|||||||
personal_info = "in einem Unternehmen Ihrer Größe"
|
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"bei rund {round_number(tech)} Servicetechnikern"
|
||||||
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"bei schätzungsweise {techniker_bucket_ml} Servicetechnikern"
|
||||||
elif int(anzahl_ma or 0) > 0:
|
elif ma > 0:
|
||||||
personal_info = f"bei über {round_number(int(anzahl_ma))} Mitarbeitern"
|
personal_info = f"bei über {round_number(ma)} Mitarbeitern"
|
||||||
except Exception:
|
except (ValueError, TypeError):
|
||||||
logger.debug("Keine validen MA/Techniker-Zahlen für Pitch.")
|
logger.debug("Keine validen MA/Techniker-Zahlen für Pitch.")
|
||||||
|
|
||||||
# 4. Prompt bauen
|
# 4. Der finale, positiv formulierte Prompt
|
||||||
prompt_parts = [
|
prompt_parts = [
|
||||||
"Du bist ein B2B-Lösungsberater, spezialisiert auf die Optimierung von Außendienstprozessen. Deine Stärke ist es, aus Unternehmensbeschreibungen den kritischsten operativen Schmerzpunkt (Pain Point) im Service abzuleiten.",
|
"Du bist ein B2B-Stratege, der die operativen Hebel eines Unternehmens im technischen Außendienst versteht.",
|
||||||
"Aufgabe: Formuliere EINEN EINZIGEN, prägnanten Satz (ca. 20-35 Wörter), der den wahrscheinlichsten **operativen Schmerzpunkt** des Unternehmens im technischen Außendienst adressiert.",
|
"Aufgabe: Formuliere EINEN EINZIGEN, positiv-beobachtenden Satz (ca. 20-35 Wörter), der die zentrale operative Herausforderung im Service subtil andeutet, indem er die Wichtigkeit ihrer Lösung betont.",
|
||||||
"",
|
"",
|
||||||
"--- Denkprozess & Inferenz-Regeln ---",
|
"--- Tonalität & Stil ---",
|
||||||
"1. **Analysiere das Kerngeschäft:** Ist es die Herstellung komplexer Anlagen, die Installation von Systemen bei Kunden oder ein Reparaturservice?",
|
"- Formuliere als scharfsinnige Beobachtung, nicht als Problem.",
|
||||||
"2. **Leite den Schmerzpunkt ab:** Was ist die größte operative Hürde bei dieser Tätigkeit in dieser Größenordnung?",
|
"- Der Satz muss direkt als erster Absatz in einer E-Mail an das Unternehmen funktionieren.",
|
||||||
" - **Regel A (Hersteller):** Bei Anlagenherstellern ist der Schmerzpunkt die **Effizienz bei der Inbetriebnahme** oder die **garantierte Anlagenverfügbarkeit (Uptime)** durch Wartung.",
|
"- Fokus auf die geschäftlichen Konsequenzen (z.B. 'entscheidend für den Projekterfolg', 'unerlässlich für die Kundenzufriedenheit').",
|
||||||
" - **Regel B (Dezentraler Installateur):** Bei vielen Standorten/Partnern ist der Schmerzpunkt die **Standardisierung der Servicequalität** und die **Routenoptimierung**.",
|
"",
|
||||||
" - **Regel C (Reparaturservice):** Bei Reparaturdiensten ist der Schmerzpunkt die **Einhaltung von SLAs** und die **First-Time Fix Rate**.",
|
"--- Inferenz-Regeln (um die Kernaussage zu finden) ---",
|
||||||
"3. **Formuliere den Satz:** Verbinde das Unternehmen und seine Personalinfo mit dem identifizierten Schmerzpunkt und den geschäftlichen Konsequenzen (z.B. 'entscheidend für die Kundentreue', 'unerlässlich für die Einhaltung von SLAs').",
|
"1. **Hersteller von Anlagen/Maschinen:** Betone die Wichtigkeit der **'effizienten Inbetriebnahme'** oder der **'maximalen Anlagenverfügbarkeit (Uptime)'**.",
|
||||||
"4. **Selbstkritik:** Wenn die Beschreibung zu allgemein ist, um einen spezifischen Schmerzpunkt abzuleiten, antworte NUR mit 'FEHLER_DATEN'.",
|
"2. **Installateur/Dienstleister mit vielen Standorten/Partnern:** Betone die Wichtigkeit der **'Standardisierung der Servicequalität'** über alle Standorte hinweg.",
|
||||||
|
"3. **Reiner Reparaturservice:** Betone die Wichtigkeit der **'schnellen Reaktionszeiten'** und der **'Einhaltung von Service-Levels'**.",
|
||||||
|
"4. **Wenn unspezifisch:** Formuliere einen etwas allgemeineren, aber immer noch relevanten Satz über die 'Effizienz des Service-Teams'.",
|
||||||
"",
|
"",
|
||||||
"--- Unternehmenskontext ---",
|
"--- Unternehmenskontext ---",
|
||||||
f"Kurzname des Unternehmens: {display_name}",
|
f"Kurzname des Unternehmens: {display_name}",
|
||||||
f"KI-validierte Branche: {ki_branche}",
|
f"KI-validierte Branche: {ki_branche}",
|
||||||
f"Beschreibung: {combined}",
|
f"Beschreibung: {final_beschreibung}",
|
||||||
f"Personalinfo für den Satz: {personal_info}",
|
f"Personalinfo für den Satz: {personal_info}",
|
||||||
"",
|
"",
|
||||||
"--- Deine Aufgabe ---",
|
"--- Deine Aufgabe ---",
|
||||||
"Führe den Denkprozess durch und gib NUR den finalen Satz aus ODER das Wort 'FEHLER_DATEN'.",
|
"Gib NUR den finalen, positiv formulierten Satz 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:
|
# Wir entfernen die "FEHLER_DATEN"-Prüfung, um die Trefferquote zu erhöhen
|
||||||
logger.warning(f"KI konnte keinen validen FSM-Pitch für {company_name} generieren.")
|
if not fsm_pitch:
|
||||||
return "FEHLER (Mangelnde Daten)"
|
logger.warning(f"KI konnte keinen FSM-Pitch für {company_name} generieren (leere Antwort).")
|
||||||
|
return "FEHLER (API-Antwort leer)"
|
||||||
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}")
|
||||||
|
|||||||
Reference in New Issue
Block a user