Restore Wiki-Verify Mode, Update FSM Pitch prompt
- FEATURE: Der `wiki_verify`-Modus wurde wiederhergestellt und ist nun über die CLI/das Menü aufrufbar. - FIX: `data_processor.py` enthält nun die `process_wiki_verify`-Methode, die gezielt Wikipedia-Artikel mittels ChatGPT verifiziert. - FIX: Dispatcher in `brancheneinstufung.py` erkennt und startet den `wiki_verify`-Modus korrekt.
This commit is contained in:
155
helpers.py
155
helpers.py
@@ -998,67 +998,152 @@ def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kateg
|
||||
logger.debug(f"Finale Branch-Evaluation: {result}")
|
||||
return result
|
||||
|
||||
|
||||
@retry_on_failure
|
||||
def verify_wiki_article_chatgpt(company_name, website, wiki_url):
|
||||
"""
|
||||
Überprüft mittels ChatGPT, ob ein gegebener Wikipedia-Artikel zum Unternehmen passt.
|
||||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.info(f"Starte ChatGPT-Verifizierung für '{company_name}' und URL '{wiki_url[:50]}...'")
|
||||
|
||||
prompt = f"""
|
||||
Aufgabe: Prüfe, ob der folgende Wikipedia-Artikel tatsächlich das angegebene Unternehmen beschreibt.
|
||||
|
||||
Unternehmen:
|
||||
- Name: {company_name}
|
||||
- Website: {website}
|
||||
|
||||
Vorgegebener Wikipedia-Artikel:
|
||||
- URL: {wiki_url}
|
||||
|
||||
Antworte ausschließlich im folgenden Format (keine Einleitung, kein Schlusssatz):
|
||||
Konsistenz: <OK oder X>
|
||||
Begründung: <Sehr kurze Begründung für deine Entscheidung. Gib an, welche Namen oder Fakten übereinstimmen oder abweichen.>
|
||||
Vorschlag URL: <Gib hier die korrekte URL an, falls der Artikel falsch ist und du eine bessere findest. Sonst leer lassen.>
|
||||
"""
|
||||
|
||||
try:
|
||||
chat_response = call_openai_chat(prompt, temperature=0.0)
|
||||
if not chat_response:
|
||||
raise APIError("Keine Antwort von OpenAI für Wiki-Verifizierung erhalten.")
|
||||
|
||||
# Parsing der Antwort
|
||||
result = {"consistency": "FEHLER", "justification": "", "suggested_url": ""}
|
||||
lines = chat_response.strip().split("\n")
|
||||
for line in lines:
|
||||
if ":" in line:
|
||||
key, value = line.split(":", 1)
|
||||
key = key.strip().lower()
|
||||
value = value.strip()
|
||||
if key == "konsistenz":
|
||||
result["consistency"] = value.upper()
|
||||
elif key == "begründung":
|
||||
result["justification"] = value
|
||||
elif key == "vorschlag url":
|
||||
result["suggested_url"] = value
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler bei der ChatGPT Wiki-Verifizierung: {e}")
|
||||
return {"consistency": "FEHLER API", "justification": str(e), "suggested_url": ""}
|
||||
|
||||
# ==============================================================================
|
||||
# Chat GPT FSM Pitch
|
||||
# ==============================================================================
|
||||
|
||||
|
||||
@retry_on_failure
|
||||
def generate_fsm_argument(company_name, crm_branche, website_summary, wiki_absatz, anzahl_ma, anzahl_techniker):
|
||||
def generate_fsm_pitch(company_name, company_short_name, ki_branche, website_summary, wiki_absatz, anzahl_ma, anzahl_techniker, techniker_bucket_ml):
|
||||
"""
|
||||
Generiert einen maßgeschneiderten, nicht-werblichen Satz, warum das Unternehmen FSM einsetzen sollte.
|
||||
Nutzt eine "Chain-of-Thought"-Anweisung für spezifischere Ergebnisse.
|
||||
Generiert einen maßgeschneiderten, nicht-werblichen Satz, der eine operative
|
||||
Service-Herausforderung des Unternehmens beschreibt (v2.1).
|
||||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
techniker_info = ""
|
||||
if anzahl_techniker and str(anzahl_techniker).strip().lower() not in ['0', 'k.a.', '']:
|
||||
techniker_info = f"bei rund {anzahl_techniker} Servicetechnikern im Außendienst"
|
||||
elif anzahl_ma and str(anzahl_ma).strip().lower() not in ['0', 'k.a.', '']:
|
||||
techniker_info = f"bei über {anzahl_ma} Mitarbeitern"
|
||||
else:
|
||||
techniker_info = "in einem Unternehmen Ihrer Größe"
|
||||
# 1. Daten-Check: Genug Futter für einen guten Satz?
|
||||
beschreibung_kombiniert = []
|
||||
if website_summary and 'k.a.' not in website_summary.lower():
|
||||
beschreibung_kombiniert.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}")
|
||||
|
||||
final_beschreibung = "\n".join(beschreibung_kombiniert)
|
||||
|
||||
if not final_beschreibung or len(final_beschreibung.split()) < 10:
|
||||
logger.warning(f"Zu wenige Informationen für FSM-Pitch für {company_name}. Breche ab.")
|
||||
return "FEHLER (Mangelnde Daten)"
|
||||
|
||||
# Nimm die bessere Beschreibung, wenn vorhanden
|
||||
beschreibung = website_summary if website_summary and website_summary.lower() != 'k.a.' else wiki_absatz
|
||||
# 2. Firmennamen priorisieren: Kurzform > Langform
|
||||
display_name = company_short_name if company_short_name and company_short_name.lower() != 'k.a.' else company_name
|
||||
|
||||
# 3. Mitarbeiter-/Techniker-Info aufbereiten und priorisieren
|
||||
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" # Default
|
||||
try:
|
||||
# Priorität 1: Explizite Technikerzahl
|
||||
if anzahl_techniker and int(anzahl_techniker) > 0:
|
||||
anzahl_techniker = round_number(int(anzahl_techniker))
|
||||
personal_info = f"bei rund {anzahl_techniker} Servicetechnikern"
|
||||
# Priorität 2: ML-Techniker-Bucket (wenn keine exakte Zahl vorhanden)
|
||||
elif techniker_bucket_ml and 'k.a.' not in techniker_bucket_ml.lower() and anzahl_techniker == 0:
|
||||
personal_info = f"bei schätzungsweise {techniker_bucket_ml} Servicetechnikern"
|
||||
# Priorität 3: Gesamtmitarbeiterzahl
|
||||
elif anzahl_ma and int(anzahl_ma) > 0:
|
||||
anzahl_ma = round_number(int(anzahl_ma))
|
||||
personal_info = f"bei über {anzahl_ma} Mitarbeitern"
|
||||
except (ValueError, TypeError):
|
||||
logger.debug("Keine validen MA/Techniker-Zahlen für Pitch.")
|
||||
|
||||
# 4. Der finale, verbesserte Prompt
|
||||
prompt_parts = [
|
||||
"Du bist ein B2B-Stratege, der die verborgenen operativen Herausforderungen eines Unternehmens erkennt und präzise auf den Punkt bringt.",
|
||||
"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.",
|
||||
"Du bist ein B2B-Stratege, der die operativen Herausforderungen eines Unternehmens im technischen Außendienst erkennt und präzise auf den Punkt bringt.",
|
||||
"Aufgabe: Formuliere EINEN EINZIGEN, flüssig lesbaren Satz (ca. 20-35 Wörter).",
|
||||
"Dieser Satz muss eine spezifische, operative Service-Herausforderung des Unternehmens beschreiben, basierend auf seinen Produkten oder Dienstleistungen.",
|
||||
|
||||
"\n--- 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', 'Verlegung von Glasfaser').",
|
||||
"3. Leite daraus die **konkrete operative Tätigkeit** ab, die von mobilen Teams durchgeführt wird (z.B. 'Installations-Termine', 'Störungsbehebungen', 'Wartungsarbeiten').",
|
||||
"4. Formuliere den finalen Satz, der diese spezifische Tätigkeit und die Personalinfo elegant verbindet.",
|
||||
"\n--- Stil-Regeln ---",
|
||||
"- Formuliere als scharfsinnige Beobachtung, nicht werblich.",
|
||||
"- Verwende den bereitgestellten 'Kurznamen des Unternehmens' natürlich im Satz.",
|
||||
"- Verwende KEINE Anführungszeichen um den Firmennamen im finalen Satz.",
|
||||
"- Vermeide generische Phrasen wie 'Schlüssel zum Erfolg'. Fokussiere auf operative Konsequenzen (z.B. 'entscheidend für die Servicequalität', 'unerlässlich für die Anlagenverfügbarkeit').",
|
||||
"- Wenn die Beschreibung keine klare Service-Tätigkeit enthält, antworte NUR mit dem Wort 'FEHLER_DATEN'.",
|
||||
|
||||
"\n--- Denkprozess (Schritt für Schritt) ---",
|
||||
"1. Analysiere die Unternehmensdaten. Leite aus der Beschreibung die konkrete Tätigkeit von mobilen Teams ab (Installation, Wartung, Reparatur, Logistik, Begutachtung).",
|
||||
"2. Formuliere einen Satz, der diese Tätigkeit mit der Personalinfo verbindet und als Herausforderung darstellt.",
|
||||
"3. Wenn keine klare Service-Tätigkeit erkennbar ist, antworte mit 'FEHLER_DATEN'.",
|
||||
|
||||
"\n--- Unternehmenskontext ---",
|
||||
f"Unternehmen: {company_name}",
|
||||
f"Branche: {crm_branche}",
|
||||
f"Beschreibung: {beschreibung}",
|
||||
f"Personalinfo für den Satz: {techniker_info}",
|
||||
f"Kurzname des Unternehmens: {display_name}",
|
||||
f"KI-validierte Branche: {ki_branche}",
|
||||
f"Beschreibung (aus Website & Wikipedia): {final_beschreibung}",
|
||||
f"Personalinfo für den Satz: {personal_info}",
|
||||
f"Gesamtmitarbeiterzahl (Kontext): {anzahl_ma}",
|
||||
|
||||
"\n--- Beispiele für den gewünschten Output-Stil ---",
|
||||
"Beispiel 1 (Kontext: Branche 'Energie', Beschreibung '...baut Ladeinfrastruktur aus...'): Angesichts des beschleunigten Ausbaus der Ladeinfrastruktur ist die reibungslose Koordination der Installationstermine Ihrer mobilen Teams entscheidend für den Projekterfolg.",
|
||||
"Beispiel 2 (Kontext: Branche 'Anlagenbau', Beschreibung '...Service für Produktionsanlagen...'): Bei der Wartung komplexer Produktionsanlagen hängt die Kundenzufriedenheit direkt von der pünktlichen und effizienten Durchführung der Serviceeinsätze ab.",
|
||||
"Beispiel 1: Angesichts des beschleunigten Ausbaus der Ladeinfrastruktur bei EnBW ist die reibungslose Koordination der Installationstermine Ihrer mobilen Teams entscheidend für den Projekterfolg.",
|
||||
"Beispiel 2: Bei der Wartung komplexer Produktionsanlagen für Siemens hängt die Kundenzufriedenheit direkt von der pünktlichen und effizienten Durchführung der Serviceeinsätze ab.",
|
||||
|
||||
"\n--- Deine Aufgabe ---",
|
||||
"Führe den Denkprozess durch und gib NUR den finalen, perfekten Satz für das oben genannte Unternehmen aus:",
|
||||
"Führe den Denkprozess durch und gib NUR den finalen Satz aus ODER das Wort 'FEHLER_DATEN'.",
|
||||
]
|
||||
|
||||
prompt = "\n".join(prompt_parts)
|
||||
|
||||
try:
|
||||
# Expliziter Aufruf eines fortschrittlicheren Modells für diese spezielle, kreative Aufgabe.
|
||||
# 'gpt-4-turbo-preview' oder 'gpt-4o' sind gute, kosteneffiziente Optionen.
|
||||
fsm_pitch = call_openai_chat(prompt, temperature=0.7, model="gpt-4-turbo-preview")
|
||||
return fsm_pitch.strip().replace('"', '') if fsm_pitch else "k.A. (Pitch-Generierung fehlgeschlagen)"
|
||||
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 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}")
|
||||
return "k.A. (Fehler bei Pitch-Generierung)"
|
||||
return "FEHLER (API-Fehler)"
|
||||
|
||||
|
||||
@retry_on_failure
|
||||
|
||||
Reference in New Issue
Block a user