This commit introduces the foundational elements for the new "Company Explorer" web application, marking a significant step away from the legacy Google Sheets / CLI system. Key changes include: - Project Structure: A new directory with separate (FastAPI) and (React/Vite) components. - Data Persistence: Migration from Google Sheets to a local SQLite database () using SQLAlchemy. - Core Utilities: Extraction and cleanup of essential helper functions (LLM wrappers, text utilities) into . - Backend Services: , , for AI-powered analysis, and logic. - Frontend UI: Basic React application with company table, import wizard, and dynamic inspector sidebar. - Docker Integration: Updated and for multi-stage builds and sideloading. - Deployment & Access: Integrated into central Nginx proxy and dashboard, accessible via . Lessons Learned & Fixed during development: - Frontend Asset Loading: Addressed issues with Vite's path and FastAPI's . - TypeScript Configuration: Added and . - Database Schema Evolution: Solved errors by forcing a new database file and correcting override. - Logging: Implemented robust file-based logging (). This new foundation provides a powerful and maintainable platform for future B2B robotics lead generation.
149 lines
7.6 KiB
Python
149 lines
7.6 KiB
Python
# generate_knowledge_base.py
|
|
|
|
import os
|
|
import yaml
|
|
import logging
|
|
import time
|
|
import openai
|
|
from config import Config # Wir nutzen die Config für den API-Schlüssel
|
|
|
|
# --- Konfiguration ---
|
|
# HIER BITTE IHRE FOKUSBRANCHEN EINTRAGEN
|
|
# Diese Namen sollten mit den Keys im BRANCH_GROUP_MAPPING aus config.py übereinstimmen.
|
|
FOKUS_BRANCHEN = [
|
|
"Medizintechnik",
|
|
"Anlagenbau",
|
|
"Facility Management",
|
|
"Maschinenbau",
|
|
"IT / Telekommunikation" # Beispiel, bitte anpassen
|
|
]
|
|
|
|
POSITIONEN = {
|
|
"IT": "IT-Leiter",
|
|
"Management / GF / C-Level": "Geschäftsführer / C-Level",
|
|
"Finanzen": "Finanzleiter / CFO",
|
|
"Procurement / Einkauf": "Einkaufsleiter",
|
|
"Field Service Management": "Leiter Kundenservice / Field Service"
|
|
}
|
|
|
|
OUTPUT_FILE = "marketing_wissen_entwurf.yaml"
|
|
|
|
# Logging einrichten
|
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
|
|
def call_openai_with_retry(prompt, max_retries=3, delay=5):
|
|
"""Ruft die OpenAI API mit Retry-Logik auf."""
|
|
for attempt in range(max_retries):
|
|
try:
|
|
logging.info(f"Sende Prompt an OpenAI (Versuch {attempt + 1}/{max_retries})...")
|
|
response = openai.ChatCompletion.create(
|
|
model="gpt-4-turbo", # Oder ein anderes Modell Ihrer Wahl
|
|
messages=[{"role": "user", "content": prompt}],
|
|
temperature=0.5,
|
|
max_tokens=500
|
|
)
|
|
content = response.choices[0].message['content'].strip()
|
|
return content
|
|
except Exception as e:
|
|
logging.error(f"Fehler bei OpenAI-API-Aufruf: {e}")
|
|
if attempt < max_retries - 1:
|
|
logging.info(f"Warte {delay} Sekunden vor dem nächsten Versuch...")
|
|
time.sleep(delay)
|
|
else:
|
|
logging.error("Maximale Anzahl an Wiederholungen erreicht. Breche ab.")
|
|
return None
|
|
|
|
def generate_pain_points_prompt(branch_name):
|
|
"""Erstellt den Prompt zur Generierung von Pain Points für eine Branche."""
|
|
return "\n".join([
|
|
"Du bist ein Top-Strategieberater mit Branchen-Expertise bei einer führenden Unternehmensberatung. Du analysierst die operativen Kernprozesse von Unternehmen und identifizierst die entscheidenden Hebel für Effizienzsteigerungen im Außendienst.",
|
|
f"Branche: {branch_name}",
|
|
"\n--- Denkprozess (Chain of Thought) ---",
|
|
"1. Versetze dich in ein typisches Unternehmen dieser Branche.",
|
|
"2. Was sind die häufigsten, sich wiederholenden Aufgaben, die mobile Techniker dort ausführen (z.B. Wartung, Reparatur, Installation, Inspektion)?",
|
|
"3. Welche spezifischen Probleme und Engpässe treten bei der Planung und Durchführung DIESER Aufgaben auf? Denke an Regularien, Kundenanforderungen, technische Komplexität und wirtschaftlichen Druck.",
|
|
"4. Formuliere aus diesen Problemen 5 prägnante, operative 'Pain Points', die sich auf den Service-Außendienst beziehen.",
|
|
"\n--- Aufgabe ---",
|
|
"Gib eine Liste von genau 5 Pain Points für die angegebene Branche aus. Formuliere sie als Herausforderungen aus Sicht des Unternehmens.",
|
|
"Gib das Ergebnis ausschließlich als saubere YAML-Liste unter dem Schlüssel 'pain_points:' aus. KEINE weiteren Einleitungen oder Kommentare.",
|
|
"\n--- Beispiel für den gewünschten Output-Stil (Branche: Aufzüge und Rolltreppen) ---",
|
|
"""
|
|
pain_points:
|
|
- "Sicherstellung der gesetzlich vorgeschriebenen, regelmäßigen Sicherheitsüberprüfungen und deren lückenlose Dokumentation."
|
|
- "Minimierung der Ausfallzeiten von Aufzügen in hochfrequentierten Gebäuden durch extrem schnelle Reaktionszeiten bei Störungen."
|
|
- "Effiziente Routenplanung, um die Vielzahl an dezentral verteilten Anlagen mit minimalem Fahrtaufwand abzudecken."
|
|
- "Bereitstellung von technischer Dokumentation und spezifischen Wartungsplänen für hunderte verschiedene Modelle direkt vor Ort."
|
|
- "Management von Ersatzteilen und deren Verfügbarkeit im Servicefahrzeug."
|
|
"""
|
|
])
|
|
|
|
def generate_position_focus_prompt(position_name):
|
|
"""Erstellt den Prompt zur Generierung des Fokus-Textes für eine Position."""
|
|
return "\n".join([
|
|
"Du bist ein erfahrener B2B-Vertriebs-Coach. Du formulierst Kernaussagen, die den spezifischen Blickwinkel unterschiedlicher Entscheidungsträger treffen.",
|
|
f"Position: {position_name}",
|
|
"\n--- Aufgabe ---",
|
|
"Formuliere EINEN EINZIGEN Satz, der den typischen Fokus oder das Hauptinteresse dieser Position in Bezug auf die Optimierung von Serviceprozessen beschreibt.",
|
|
"Dieser Satz wird später in einer E-Mail verwendet, beginnend mit 'Für Sie als...'. Formuliere den Satz so, dass er dort direkt passt.",
|
|
"Beispiel für 'Geschäftsführer': 'stehen vermutlich die Steigerung der Effizienz, die Kundenzufriedenheit und die Skalierbarkeit Ihrer Serviceprozesse im Vordergrund.'",
|
|
"Gib NUR den reinen Satz ohne Anführungszeichen oder einleitende Phrasen aus."
|
|
])
|
|
|
|
|
|
def main():
|
|
"""Hauptfunktion zur Generierung der Wissensbasis."""
|
|
logging.info("Starte die Generierung der Wissensbasis für Marketing-Texte...")
|
|
|
|
# API-Schlüssel laden
|
|
Config.load_api_keys()
|
|
openai.api_key = Config.API_KEYS.get('openai')
|
|
if not openai.api_key:
|
|
logging.critical("OpenAI API Key nicht in config.py gefunden. Skript wird beendet.")
|
|
return
|
|
|
|
knowledge_base = {'Branchen': {}, 'Positionen': {}}
|
|
|
|
# 1. Pain Points für jede Fokusbranche generieren
|
|
logging.info(f"Generiere Pain Points für {len(FOKUS_BRANCHEN)} Fokusbranchen...")
|
|
for branch in FOKUS_BRANCHEN:
|
|
logging.info(f"--- Verarbeite Branche: {branch} ---")
|
|
prompt = generate_pain_points_prompt(branch)
|
|
response_text = call_openai_with_retry(prompt)
|
|
if response_text:
|
|
try:
|
|
# Versuche, den YAML-Teil zu parsen
|
|
parsed_yaml = yaml.safe_load(response_text)
|
|
knowledge_base['Branchen'][branch] = {
|
|
'pain_points': parsed_yaml.get('pain_points', ['FEHLER: Konnte Pain Points nicht parsen.']),
|
|
'references_DE': '[HIER DEUTSCHE REFERENZKUNDEN EINTRAGEN]',
|
|
'references_GB': '[HIER ENGLISCHE REFERENZKUNDEN EINTRAGEN]'
|
|
}
|
|
except yaml.YAMLError as e:
|
|
logging.error(f"Fehler beim Parsen der YAML-Antwort für {branch}: {e}")
|
|
knowledge_base['Branchen'][branch] = {'pain_points': [f'PARSING-FEHLER: {response_text}']}
|
|
time.sleep(2) # Kurze Pause, um Rate-Limits zu vermeiden
|
|
|
|
# 2. Fokus für jede Position generieren
|
|
logging.info(f"\nGeneriere Fokus-Texte für {len(POSITIONEN)} Positionen...")
|
|
for key, name in POSITIONEN.items():
|
|
logging.info(f"--- Verarbeite Position: {name} ---")
|
|
prompt = generate_position_focus_prompt(name)
|
|
response_text = call_openai_with_retry(prompt)
|
|
if response_text:
|
|
knowledge_base['Positionen'][key] = {
|
|
'focus_DE': response_text,
|
|
'focus_GB': '[HIER ENGLISCHE ÜBERSETZUNG DES FOKUS-SATZES EINTRAGEN]'
|
|
}
|
|
time.sleep(2)
|
|
|
|
# 3. Ergebnis in YAML-Datei speichern
|
|
try:
|
|
with open(OUTPUT_FILE, 'w', encoding='utf-8') as f:
|
|
yaml.dump(knowledge_base, f, allow_unicode=True, sort_keys=False, width=120)
|
|
logging.info(f"\nErfolgreich! Die Wissensbasis wurde in '{OUTPUT_FILE}' gespeichert.")
|
|
logging.info("BITTE ÜBERPRÜFEN SIE DIESE DATEI UND PASSEN SIE SIE NACH BEDARF AN.")
|
|
except Exception as e:
|
|
logging.error(f"Fehler beim Speichern der YAML-Datei: {e}")
|
|
|
|
if __name__ == "__main__":
|
|
main() |