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:
105
helpers.py
105
helpers.py
@@ -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. 20–35 Wörter), der als hochpersonalisierter Einstieg in einer E-Mail dient.",
|
"Formuliere EINEN EINZIGEN, flüssig lesbaren Satz (ca. 20–35 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}")
|
||||||
|
|||||||
Reference in New Issue
Block a user