diff --git a/helpers.py b/helpers.py index d9b75465..9fd8544f 100644 --- a/helpers.py +++ b/helpers.py @@ -1031,72 +1031,80 @@ def generate_fsm_pitch( techniker_bucket_ml, ): """ - Generiert einen FSM-Pitch mittels eines "Few-Shot"-Ansatzes, der auf exzellenten - Beispielen basiert, um eine aktive, pointierte Tonalität zu gewährleisten (v2.2.9). + Generiert einen maßgeschneiderten, nicht-werblichen Satz, der eine operative + Service-Herausforderung des Unternehmens beschreibt (v2.3.0, basierend auf der bewährten v2.1-Logik). """ logger = logging.getLogger(__name__) - # 1. Datenaufbereitung - beschreibung_kombiniert = [] + # 1. VERBESSERTER Daten-Check (aus v2.2.x übernommen) + # Extrahiert intelligent die reine Zusammenfassung aus dem strukturierten Analyse-Text + 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: beschreibung_kombiniert.append(f"Website-Zusammenfassung: {summary_text}") - except IndexError: pass - + if summary_text: + 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(): - beschreibung_kombiniert.append(f"Wikipedia-Einleitung: {wiki_absatz}") + parts.append(f"Wikipedia-Einleitung: {wiki_absatz}") - final_beschreibung = "\n".join(beschreibung_kombiniert) - - if not final_beschreibung: + combined = "\n".join(parts) + + if len(combined.split()) < 10: + logger.warning(f"Zu wenige Informationen für FSM-Pitch bei {company_name}.") 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 - - 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: 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" - 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, -2))} Mitarbeiter" - except (ValueError, TypeError): pass + if tech > 0: + 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 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 = [ - "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 ---", - "1. **Identifiziere die Kern-Service-Tätigkeit:** Was tun die mobilen Teams des Unternehmens? (z.B. Installationen, Wartung, Reparatur).", - "2. **Quantifiziere die Herausforderung:** Verbinde die Tätigkeit mit der Unternehmensgröße oder der Anzahl der Anlagen/Kunden.", - "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.", - "4. **Nutze den Kurznamen:** Verwende IMMER den bereitgestellten 'Kurzname des Unternehmens', nicht die volle Firmierung.", + "--- Stil-Regeln ---", + "- Nicht werblich.", + "- Nutze den Kurznamen ohne Anführungszeichen.", + "- Vermeide allgemeine Phrasen wie 'Schlüssel zum Erfolg'.", "", - "--- Exzellente Beispiele für den Zielsatz ---", - "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.", - "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.", - "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.", + "--- Kontext ---", + f"Kurzname: {display_name}", + f"Branche: {ki_branche}", + f"Beschreibung: {combined}", + f"Personalinfo: {personal_info}", + f"Gesamtmitarbeiterzahl: {anzahl_ma}", "", - "--- Selbstkritik ---", - "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'.", + "Bei zu allgemeiner Beschreibung → 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 "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 fsm_pitch.strip().replace('"', '') except Exception as e: