diff --git a/helpers.py b/helpers.py index 7e32380d..e6dc69ca 100644 --- a/helpers.py +++ b/helpers.py @@ -1031,21 +1031,18 @@ def generate_fsm_pitch( techniker_bucket_ml, ): """ - Generiert einen FSM-Pitch basierend auf dem bewährten "Chain of Thought"-Master-Prompt (v2.3.2). - Liefert den qualitativ hochwertigsten, für die E-Mail-Ansprache geeigneten Satz. + Generiert einen FSM-Pitch basierend auf dem finalen Master-Prompt (v2.3.3). + Liefert einen strategischen, positiv formulierten Satz für die E-Mail-Ansprache. """ logger = logging.getLogger(__name__) - # 1. Datenaufbereitung (Unsere technische Verbesserung) + # 1. Datenaufbereitung parts = [] if website_summary and '**GESCHÄFTSMODELL**' in website_summary: try: summary_text = website_summary.split('Zusammenfassung:')[1].split('**FSM-POTENZIAL**')[0].strip() - if summary_text: - parts.append(f"Zusammenfassung der Website: {summary_text}") - except IndexError: - if 'k.a.' not in website_summary.lower(): - parts.append(f"Zusammenfassung der Website: {website_summary}") + if summary_text: parts.append(f"Zusammenfassung der Website: {summary_text}") + except IndexError: pass elif website_summary and 'k.a.' not in website_summary.lower(): parts.append(f"Zusammenfassung der Website: {website_summary}") @@ -1053,67 +1050,65 @@ def generate_fsm_pitch( parts.append(f"Wikipedia-Einleitung: {wiki_absatz}") combined = "\n".join(parts) + if not combined: return "FEHLER (Mangelnde Daten)" - if len(combined.split()) < 10: - 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) + # 2. Namenswahl 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 = "" try: - tech = int(anzahl_techniker or 0) - ma = int(anzahl_ma or 0) - if tech > 0: - personal_info = f"Ihre rund {int(round(tech, -1))} Servicetechniker" + tech_val = int(anzahl_techniker or 0) + ma_val = int(anzahl_ma or 0) + if tech_val > 0: + 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(): - personal_info = f"Ihre schätzungsweise {techniker_bucket_ml} Servicetechniker" - elif ma > 0: - personal_info = f"Ihre über {int(round(ma, -1))} Mitarbeiter" - except (ValueError, TypeError): - pass + if "Klein" in techniker_bucket_ml: personal_info = "Ihrem wachsenden Serviceteam" + elif "Mittel" in techniker_bucket_ml: personal_info = "Ihrer mittelgroßen Serviceorganisation" + elif "Gross" in techniker_bucket_ml: personal_info = "Ihrer großen Serviceorganisation mit über 250 Technikern" + elif ma_val > 0: + 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 = [ - "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:", - "Formuliere EINEN EINZIGEN, flüssig lesbaren Satz (ca. 20–35 Wörter), der als hochpersonalisierter Einstieg in einer E-Mail dient.", - "Stil-Regeln:", - "• Absolut NICHT werblich klingen. Keine Produktnamen, keine direkten Lösungsangebote.", - "• Formuliere es als eine scharfsinnige Beobachtung über die operative Tätigkeit des Unternehmens.", - "• Der Satz muss spezifische Keywords aus der Unternehmensbeschreibung aufgreifen.", - "________________________________________", - "Denkprozess (Schritt für Schritt):", - "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“).", - "3. Leite daraus die konkrete operative Tätigkeit ab, die von mobilen Teams durchgeführt wird (z. B. „Installations-Termine“, „Störungsbehebungen“).", - "4. Formuliere den finalen Satz, der diese spezifische Tätigkeit und die Personalinfo elegant verbindet, idealerweise beginnend mit '[Unternehmensname] steht vor der Herausforderung...'.", - "________________________________________", - "Unternehmenskontext:", - 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 (Installateur):", - "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 (Hersteller mit Service):", - "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.", - "• Beispiel 3 (Hersteller ohne direkten Service-Text):", - "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 Aufgabe:", - "Führe den Denkprozess durch und gib NUR den finalen, perfekten Satz für das oben genannte Unternehmen aus:", + "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.", + "", + "--- Tonalität & Stil (SEHR WICHTIG) ---", + "• Absolut NICHT werblich, sondern partnerschaftlich und beobachtend.", + "• 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').", + "• Verwende IMMER den bereitgestellten 'Kurznamen', niemals die volle Firmierung.", + "", + "--- Denkprozess (Schritt für Schritt) ---", + "1. Analysiere die Beschreibung, um die **spezifischste Service-Tätigkeit** zu finden (z.B. 'Installation von Glasfaseranschlüssen', 'Wartung von Produktionsanlagen').", + "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.", + "", + "--- Exzellente Beispiele für den Zielsatz ---", + "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.", + "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.", + "", + "--- Selbstkritik ---", + "Wenn die Beschreibung keine konkrete Service-Tätigkeit erkennen lässt (z.B. reiner Handel, Online-Portal), antworte NUR mit: FEHLER_DATEN", + "", + "--- Unternehmenskontext für deine Aufgabe ---", + f"Kurzname des Unternehmens: {display_name}", + f"Branche: {ki_branche}", + f"Beschreibung:\n{combined}", + 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) try: 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 - logger.warning(f"KI konnte keinen validen FSM-Pitch für {company_name} generieren (Antwort zu kurz).") - return "FEHLER (KI-Antwort unzureichend)" + 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).") + return "FEHLER (Mangelnde Daten)" return fsm_pitch.strip().replace('"', '') except Exception as e: logger.error(f"Fehler bei der Generierung des FSM-Pitches für {company_name}: {e}")