Chain-of-Thought FSM Pitch Generation (Final)
- FEATURE: Der FSM-Pitch-Prompt wurde grundlegend überarbeitet und implementiert nun einen "Chain of Thought"-Ansatz für drastisch verbesserte Ergebnisse. - Die KI analysiert nun schrittweise das Geschäftsmodell und die Service-Art, bevor sie einen strategischen, positiv formulierten Pitch generiert. - Das Ergebnis ist nun eine Kombination aus interner Analyse und einem für die Marketing-Automation optimierten Ausgabesatz.
This commit is contained in:
89
helpers.py
89
helpers.py
@@ -1031,18 +1031,17 @@ def generate_fsm_pitch(
|
|||||||
techniker_bucket_ml,
|
techniker_bucket_ml,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Generiert einen maßgeschneiderten, strategischen Satz, der eine operative
|
Generiert einen FSM-Pitch mittels eines "Chain of Thought"-Ansatzes, um die Qualität
|
||||||
Herausforderung impliziert und für die E-Mail-Ansprache geeignet ist (v2.2.7).
|
und Relevanz der Ausgabe zu maximieren (v2.2.8).
|
||||||
"""
|
"""
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# 1. Daten-Check und Extraktion der reinen Zusammenfassung
|
# 1. Datenaufbereitung (bleibt gleich)
|
||||||
beschreibung_kombiniert = []
|
beschreibung_kombiniert = []
|
||||||
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: beschreibung_kombiniert.append(f"Website-Zusammenfassung: {summary_text}")
|
||||||
beschreibung_kombiniert.append(f"Website-Zusammenfassung: {summary_text}")
|
|
||||||
except IndexError: pass
|
except IndexError: pass
|
||||||
|
|
||||||
if wiki_absatz and 'k.a.' not in wiki_absatz.lower():
|
if wiki_absatz and 'k.a.' not in wiki_absatz.lower():
|
||||||
@@ -1051,65 +1050,57 @@ def generate_fsm_pitch(
|
|||||||
final_beschreibung = "\n".join(beschreibung_kombiniert)
|
final_beschreibung = "\n".join(beschreibung_kombiniert)
|
||||||
|
|
||||||
if not final_beschreibung:
|
if not final_beschreibung:
|
||||||
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 (bleibt unverändert)
|
|
||||||
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 = "" # Wir machen es optional
|
|
||||||
try:
|
try:
|
||||||
tech = int(anzahl_techniker or 0)
|
tech = int(anzahl_techniker or 0)
|
||||||
ma = int(anzahl_ma or 0)
|
ma = int(anzahl_ma or 0)
|
||||||
if tech > 0:
|
if tech > 0: personal_info = f"bei rund {int(round(tech, -1))} Servicetechnikern"
|
||||||
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"bei schätzungsweise {techniker_bucket_ml} Servicetechnikern"
|
||||||
elif techniker_bucket_ml and 'k.a.' not in techniker_bucket_ml.lower():
|
elif ma > 0: personal_info = f"bei über {int(round(ma, -2))} Mitarbeitern"
|
||||||
personal_info = f"bei schätzungsweise {techniker_bucket_ml} Servicetechnikern"
|
except (ValueError, TypeError): pass
|
||||||
elif ma > 0:
|
|
||||||
personal_info = f"bei über {round_number(ma)} Mitarbeitern"
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# 4. Der finale, strategische und positiv formulierte Prompt
|
# 2. Der neue "Chain of Thought"-Prompt
|
||||||
prompt_parts = [
|
prompt_parts = [
|
||||||
"Du bist ein B2B-Stratege, der die operativen Hebel eines Unternehmens im technischen Außendienst versteht.",
|
"Du bist ein B2B-Lösungsberater für Field Service Management. Deine Aufgabe ist es, aus Unternehmensdaten eine scharfsinnige Analyse abzuleiten und daraus einen perfekten, personalisierten Einleitungssatz für eine E-Mail zu formulieren.",
|
||||||
"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 der Lösung betont.",
|
|
||||||
"",
|
"\n--- Denkprozess (Chain of Thought) ---",
|
||||||
"--- Tonalität & Stil ---",
|
"Gehe die folgenden Schritte durch und gib deine Analyse für jeden Schritt aus:",
|
||||||
"- Formuliere als scharfsinnige Beobachtung, nicht als Problem ('Für ein Unternehmen wie X ist Y entscheidend, um Z zu erreichen').",
|
"1. **Geschäftsmodell-Analyse:** Analysiere die Beschreibung und identifiziere die primäre Tätigkeit. Ist es (A) Hersteller von physischen Produkten/Anlagen, (B) ein Installateur/Dienstleister, der bei Kunden vor Ort arbeitet, oder (C) ein reiner Reparaturservice?",
|
||||||
"- Der Satz muss direkt als erster Absatz in einer E-Mail an das Unternehmen funktionieren.",
|
"2. **Service-Relevanz:** Basierend auf Schritt 1, bewerte die Wahrscheinlichkeit eines signifikanten technischen Außendienstes (Hoch, Mittel, Niedrig, Keine).",
|
||||||
"- Beziehe die Personalinfo (falls vorhanden) elegant in den Satz ein.",
|
"3. **Hebel identifizieren:** Welcher operative Hebel ist für diese Art von Service am wichtigsten? (z.B. 'maximale Anlagenverfügbarkeit', 'gleichbleibend hohe Servicequalität', 'schnelle Reaktionszeiten').",
|
||||||
"",
|
"4. **Pitch-Formulierung:** Basierend auf deiner Analyse, formuliere einen einzigen, positiv-beobachtenden Satz (20-35 Wörter), der diesen Hebel adressiert und für die E-Mail-Ansprache geeignet ist. Der Satz soll die Wichtigkeit der Prozessoptimierung betonen, nicht ein Problem anklagen.",
|
||||||
"--- Inferenz-Regeln (um die Kernaussage zu finden) ---",
|
|
||||||
"1. **Hersteller von Anlagen/Maschinen:** Betone die Wichtigkeit der **'effizienten Inbetriebnahme'** oder der **'maximalen Anlagenverfügbarkeit (Uptime)'**.",
|
"\n--- Unternehmenskontext ---",
|
||||||
"2. **Installateur/Dienstleister (viele Standorte/Partner):** Betone die Wichtigkeit der **'gleichbleibend hohen Servicequalität'** über alle Standorte hinweg.",
|
f"Kurzname: {display_name}",
|
||||||
"3. **Reparaturservice:** Betone die Wichtigkeit der **'schnellen Reaktionszeiten'** und der **'Einhaltung von Service-Levels'**.",
|
f"KI-Branche: {ki_branche}",
|
||||||
"",
|
|
||||||
"--- Selbstkritik-Regel (WICHTIG) ---",
|
|
||||||
"Wenn die Beschreibung so allgemein ist, dass keine der Inferenz-Regeln spezifisch angewendet werden kann (z.B. reiner Handel, Online-Portal), antworte NUR mit dem Wort 'FEHLER_DATEN'.",
|
|
||||||
"",
|
|
||||||
"--- Unternehmenskontext ---",
|
|
||||||
f"Kurzname des Unternehmens: {display_name}",
|
|
||||||
f"KI-validierte Branche: {ki_branche}",
|
|
||||||
f"Beschreibung: {final_beschreibung}",
|
f"Beschreibung: {final_beschreibung}",
|
||||||
f"Personalinfo: {personal_info if personal_info else 'Keine Angabe'}",
|
f"Personalinfo: {personal_info if personal_info else 'Keine Angabe'}",
|
||||||
"",
|
|
||||||
"--- Deine Aufgabe ---",
|
"\n--- Deine Ausgabe (antworte AUSSCHLIESSLICH in diesem exakten Format) ---",
|
||||||
"Gib NUR den finalen, positiv formulierten Satz aus ODER das Wort 'FEHLER_DATEN'.",
|
"1. Geschäftsmodell-Analyse: <Deine Analyse zu A, B oder C>",
|
||||||
|
"2. Service-Relevanz: <Deine Bewertung>",
|
||||||
|
"3. Hebel: <Dein identifizierter Hebel>",
|
||||||
|
"4. FSM-Pitch: <Dein finaler, positiv formulierter Satz>",
|
||||||
]
|
]
|
||||||
prompt = "\n".join(prompt_parts)
|
prompt = "\n".join(prompt_parts)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fsm_pitch = call_openai_chat(prompt, temperature=0.6, model="gpt-4o")
|
response = call_openai_chat(prompt, temperature=0.5, model="gpt-4o")
|
||||||
if not fsm_pitch or "FEHLER_DATEN" in fsm_pitch:
|
if not response:
|
||||||
logger.warning(f"KI konnte keinen validen FSM-Pitch für {company_name} generieren (Grund: Mangelnde/unspezifische Daten).")
|
return "FEHLER (API-Antwort leer)"
|
||||||
return "FEHLER (Mangelnde Daten)"
|
|
||||||
return fsm_pitch.strip().replace('"', '')
|
# Wir geben die gesamte Chain-of-Thought-Analyse zurück.
|
||||||
|
# Die Formatierung für das Sheet machen wir hier.
|
||||||
|
formatted_response = response.replace("1. Geschäftsmodell-Analyse:", "**Analyse:**")
|
||||||
|
formatted_response = formatted_response.replace("2. Service-Relevanz:", "\n**Relevanz:**")
|
||||||
|
formatted_response = formatted_response.replace("3. Hebel:", "\n**Hebel:**")
|
||||||
|
formatted_response = formatted_response.replace("4. FSM-Pitch:", "\n\n**Pitch:**")
|
||||||
|
|
||||||
|
return formatted_response.strip()
|
||||||
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}")
|
||||||
return "FEHLER (API-Fehler)"
|
return "FEHLER (API-Fehler)"
|
||||||
|
|||||||
Reference in New Issue
Block a user