Files
Brancheneinstufung2/lead-engine/README.md

203 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Lead Engine: Multi-Source Automation v2.2 [31988f42]
## 🚀 Übersicht
Die **Lead Engine** ist ein spezialisiertes Modul zur autonomen Verarbeitung von B2B-Anfragen. Sie fungiert als Brücke zwischen dem E-Mail-Postfach und dem **Company Explorer**, um innerhalb von Minuten hochgradig personalisierte Antwort-Entwürfe auf "Human Expert Level" zu generieren.
## 🛠 Hauptfunktionen
### 1. Intelligenter E-Mail Ingest
* **Multi-Source:** Überwacht das Postfach `info@robo-planet.de` via **Microsoft Graph API**.
* **Filter & Routing:** Unterscheidet Anfragen von **TradingTwins** und dem **Kontaktformular**.
* **Parsing:** Spezialisierte HTML-Parser extrahieren strukturierte Daten (Firma, Kontakt, Bedarf).
### 2. Contact Research (LinkedIn Lookup)
* **Automatisierung:** Sucht via **SerpAPI** und **Gemini 2.0 Flash** nach der beruflichen Position.
* **Ergebnis:** Identifiziert Rollen (z.B. "CFO"), um den Tonfall anzupassen.
### 3. Company Explorer Sync & Monitoring
* **Integration:** Legt Accounts und Kontakte automatisch im CE an.
* **Monitor:** Hintergrund-Prozess (`monitor.py`) überwacht den Analyse-Status.
* **Daten-Pull:** Übernimmt Branche und Dossier in die lokale Lead-Datenbank.
### 4. Expert Response Generator
* **KI-Engine:** Gemini 2.0 Flash erstellt E-Mail-Entwürfe.
* **Kontext:** Kombiniert Lead-Daten + CE-Daten + Matrix-Argumente (Pains/Gains).
### 5. Trading Twins Autopilot (PRODUKTIV v2.2)
Der vollautomatische "Zero Touch" Workflow für Trading Twins Anfragen.
* **Human-in-the-Loop:** Elizabeta Melcer erhält eine Teams-Nachricht ("Approve/Deny").
* **Feedback-Server:** Ein integrierter FastAPI-Server (Port 8004) verarbeitet Klicks.
* **Direct Calendar Booking (Micro-Service):**
* **Logik:** Prüft den Kalender von `e.melcer` auf **echte Verfügbarkeit**.
* **Raster:** Termine starten nur im **15-Minuten-Takt** (:00, :15, :30, :45).
* **Abstand:** Bietet zwei Termine an, mit ca. **3 Stunden Pause** dazwischen.
* **Buchung:** Klick auf Link -> Server erstellt Outlook-Termin von `info@` mit `e.melcer` als Teilnehmer.
### 6. Smartlead Webhook Integration (NEU)
* **Zweck:** Empfang von Echtzeit-Lead-Benachrichtigungen direkt aus der Smartlead-Plattform.
* **Event-basiert:** Das System empfängt nur Daten für *neue* Ereignisse (z.B. "Lead als heiß markiert"), keine historischen Daten.
#### Endpunkte
Die folgenden Endpunkte werden für Smartlead bereitgestellt. Die Basis-URL ist flexibel und kann bei einem Serverumzug einfach angepasst werden. Der Platzhalter `{IHRE_AKTUELLE_DOMAIN}` sollte durch die aktuell aktive URL (z.B. `floke-ai.duckdns.org` oder die zukünftige neue Domain) ersetzt werden.
* **Hot Leads:** `https://{IHRE_AKTUELLE_DOMAIN}/public/smartlead/hot-lead`
* **Follow-up Leads:** `https://{IHRE_AKTUELLE_DOMAIN}/public/smartlead/follow-up-lead`
#### Inbetriebnahme & Test-Prozess
Die Integration wird in einem kontrollierten Prozess ausgerollt, um die Datenstruktur sicher zu analysieren:
1. **URLs an Smartlead übergeben:** Die oben genannten URLs werden an den Smartlead-Support oder in deren Admin-Oberfläche eingetragen.
2. **Test-Auslösung anfordern:** Smartlead wird gebeten, für jeden der beiden Endpunkte einen einzelnen Test-Lead manuell auszulösen.
3. **Datenanalyse:** Alle eingehenden Anfragen werden ungefiltert in die Log-Datei `lead-engine/Log/smartlead_webhooks.log` geschrieben. Dies ermöglicht eine genaue Analyse der von Smartlead gesendeten JSON-Struktur.
4. **Implementierung der Logik:** Basierend auf den analysierten Test-Daten wird die eigentliche Geschäftslogik (z.B. Eintrag in die Datenbank, Teams-Benachrichtigung) implementiert.
Dieser Prozess stellt sicher, dass wir nicht "blind" entwickeln, sondern auf Basis der realen Datenstruktur von Smartlead aufbauen.
## 🏗 Architektur
```text
/app/lead-engine/
├── app.py # Streamlit Web-Interface
├── trading_twins_ingest.py # E-Mail Importer (Graph API)
├── monitor.py # Monitor + Trigger für Orchestrator
├── trading_twins/ # Autopilot Modul
│ ├── manager.py # Orchestrator, FastAPI, Graph API Logic
│ ├── test_calendar_logic.py # Interner Test für Kalender-Zugriff
│ └── signature.html # HTML-Signatur (mit Bildern im selben Ordner)
└── db.py # Lokale SQLite Lead-Datenbank
```
## 🚨 Lessons Learned & Critical Fixes
### 1. Microsoft Graph API: Kalender-Zugriff
* **Problem:** `debug_calendar.py` scheiterte oft mit `TimeZoneNotSupportedException`.
* **Ursache:** Der API-Aufruf zur Abfrage der Verfügbarkeit (`getSchedule`) hat keine explizite Zeitzoneninformation erhalten.
* **Lösung:** Die Zeitzone ("Europe/Berlin") wird nun explizit im `payload` des API-Aufrufs mitgegeben.
### 2. Exchange AppOnly AccessPolicy (Buchungs-Workaround)
* **Problem:** `Calendars.ReadWrite` erlaubt einer App oft nicht, Termine in *fremden* Kalendern (`e.melcer@`) zu erstellen (`403 Forbidden`).
* **Lösung:** Der Termin wird im **eigenen Kalender** des Service-Accounts (`info@`) erstellt. Der Mitarbeiter (`e.melcer@`) wird als **Teilnehmer** hinzugefügt. Das umgeht die Policy.
### 3. Dynamische HTML-Signatur mit Inline-Bildern
* **Problem:** Eine statische Signatur in der Konfiguration war unflexibel und konnte keine Bilder enthalten.
* **Lösung:** Ein Skript (`scripts/extract_signature_assets.py`) extrahiert die vollständige HTML-Signatur und alle eingebetteten Bilder aus einer `.eml`-Datei. Die `send_email`-Funktion wurde überarbeitet, um alle Bilder dynamisch als Inline-Anhänge zu versenden, was eine professionelle Darstellung sicherstellt.
### 4. Race-Condition-Schutz bei Überbuchung (Live-Check)
* **Problem:** Wenn mehrere Leads E-Mails mit denselben Terminvorschlägen erhalten, konnten Doppelbuchungen entstehen.
* **Lösung:** Implementierung eines "Live-Checks" im Feedback-Server. Bevor ein Termin gebucht wird, prüft das System in Echtzeit (`is_slot_free`), ob der Slot im Kalender von `e.melcer@` noch verfügbar ist. Ist er belegt, wird die Buchung abgebrochen und ein Fallback-Szenario aktiviert.
### 5. Seamless Website Integration (WordPress iFrame)
* **Problem:** Die API-Endpoints gaben nackten Text zurück, was für Kunden unprofessionell wirkte.
* **Lösung:** Der Server liefert nun saubere HTML-Snippets zurück. Durch Setzen der `WORDPRESS_BOOKING_URL` in der `.env` führen die Links in der Kunden-E-Mail direkt auf die Kunden-Website. Dort wird das HTML-Ergebnis (Erfolg inkl. Teams-Link ODER Fallback zum Microsoft Bookings Kalender bei Doppelbuchung) unsichtbar in einem iFrame geladen.
#### 5.1 Troubleshooting der iFrame-Integration
Um sicherzustellen, dass die Buchungs-Landingpage auf WordPress immer korrekt funktioniert sowohl mit spezifischen Terminvorschlägen als auch als Fallback zu einer allgemeinen Buchungsseite sind mehrere Konfigurationsschritte und Fehlerbehebungen notwendig:
**1. Robuster iFrame-Code für Ihre WordPress-Seite**
Der folgende JavaScript-Code sollte in Ihre WordPress-Seite integriert werden, die als Landingpage für Terminbuchungen dient (z.B. `robo-planet.de/terminbestaetigung`). Er prüft, ob spezifische Termindaten (Job-UUID und Timestamp) über die URL übergeben werden, und lädt entsprechend entweder den spezifischen Termin-Slot oder die allgemeine Microsoft Bookings URL als Fallback.
```html
<iframe id="booking-iframe" width="100%" height="800px" style="border:none;" scrolling="no"></iframe>
<script>
const urlParams = new URLSearchParams(window.location.search);
const jobUuid = urlParams.get('job_uuid');
const timestamp = urlParams.get('ts');
let iframeSrc = "";
if (jobUuid && timestamp) {
// Wenn beide Parameter vorhanden sind, den spezifischen Buchungslink verwenden
iframeSrc = "https://floke-ai.duckdns.org/feedback/book_slot/" + jobUuid + "/" + timestamp;
} else {
// Andernfalls auf die allgemeine MS Bookings URL verweisen
iframeSrc = "https://outlook.office.com/book/KennenlernenmitRoboplanet@wackler-group.de/?ismsaljsauthenabled";
}
document.getElementById('booking-iframe').src = iframeSrc;
</script>
```
**2. Nginx-Konfiguration für korrekte Pfad-Weiterleitung**
Das Laden der spezifischen `/feedback/book_slot/...`-URL im iFrame scheiterte initial, da der Nginx-Proxy die verschachtelten Pfade nicht korrekt an den `lead-engine`-Container weiterleitete. Dies führte zur "Synology-Fehlerseite".
* **Problem:** Die `location`-Regel in `nginx-proxy-clean.conf` für `/feedback/` war zu starr.
* **Lösung:** Die Konfiguration wurde mit einer `rewrite`-Regel angepasst, um sicherzustellen, dass der gesamte Pfad korrekt an den `lead-engine`-Dienst weitergegeben wird und die notwendigen Proxy-Header für moderne Webanwendungen gesetzt sind.
```nginx
location /feedback/ {
auth_basic off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
rewrite ^/feedback/(.*)$ /$1 break;
proxy_pass http://lead-engine:8004;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
```
* **Aktion nach Änderung:** Nach dem Anpassen von `nginx-proxy-clean.conf` muss der Nginx-Container neu gestartet werden:
`docker-compose restart nginx`
**3. Behebung des `lead-engine` Service-Absturzes (`SyntaxError`)**
Der `lead-engine`-Dienst selbst stürzte aufgrund eines Python `SyntaxError` ab, der durch einen ungültigen Import-Pfad verursacht wurde, der Bindestriche enthielt. Dies verhinderte, dass der Dienst überhaupt eine Antwort senden konnte, was ebenfalls zu einer leeren iFrame-Anzeige beitrug.
* **Problem:** Eine Zeile `from connector-superoffice.superoffice_client import SuperOfficeClient` in `manager.py` verursachte einen `SyntaxError`, da Bindestriche in Python-Modulnamen nicht erlaubt sind.
* **Lösung:** Die fehlerhafte `sys.path.append`-Anweisung und die ungültige `import`-Zeile wurden aus `lead-engine/trading_twins/manager.py` entfernt, da sie Teil eines verschobenen Tasks waren.
* **Aktion nach Änderung:** Nach der Korrektur in `manager.py` muss der `lead-engine`-Container neu gebaut und neu gestartet werden:
`docker-compose up -d --build --force-recreate lead-engine`
Durch diese Maßnahmen wird die iFrame-Integration nun robust funktionieren und immer eine sinnvolle Ansicht auf der WordPress-Landingpage bieten.
## 🚀 Inbetriebnahme & Test
### Inbetriebnahme
```bash
# Neustart des Dienstes
docker-compose up -d --build --force-recreate lead-engine
```
### Test & Debugging
* **Allgemeiner Test:** Die URL `https://floke-ai.duckdns.org/feedback/test_lead` löst einen generischen Test-Lead aus.
* **Spezifischer Test pro Lead:** Im Lead-Tool (`/lead/`) kann für jeden Lead mit einem generierten E-Mail-Entwurf der Button "🧪 Test-Versand (an floke.com@gmail.com)" geklickt werden. Dies startet den gesamten End-to-End-Prozess (Teams-Nachricht & E-Mail-Versand) für den ausgewählten Lead, sendet die E-Mail aber sicher an die Test-Adresse.
**Zugriff:** `https://floke-ai.duckdns.org/lead/` (Passwortgeschützt)
## 📝 Zukünftige Erweiterungen & Todos
### Task: Automatisches Nachfassen (Follow-up)
* **Problem:** Wenn ein Lead nicht auf die E-Mail antwortet und auch keinen Termin bucht, geht der Kontakt verloren.
* **Lösung:** Einbindung eines Follow-up-Mechanismus nach 5 Tagen. Dies könnte entweder durch ein Flag im CRM-System oder durch eine geplante E-Mail direkt über die Lead-Engine realisiert werden.
### Task: Erfolgsmessung & Tracking (Microsoft Bookings Auswertung)
* **Ziel:** Übersicht gewinnen, wie viele Meetings tatsächlich über diesen neuen Kanal (Trading Twins / E-Mail) final gebucht wurden.
* **Lösungsweg (Pragmatischer Ansatz):**
1. Die E-Mail-Adresse der geteilten Bookings-Seite (`KennenlernenmitRoboplanet@wackler-group.de`) muss von der IT zur bestehenden **Exchange ApplicationAccessPolicy** der `CAL_APPID` hinzugefügt werden.
2. Dadurch kann unsere bestehende "Lese-App" auch die Termine dieses zentralen Postfachs über die MS Graph API (`GET /users/{bookings-email}/calendar/events`) auslesen.
3. Ein geplanter Job (z.B. täglich oder wöchentlich) zählt die neu hinzugekommenen Termine und erstellt einen kurzen KPI-Report.
### Task: CRM-Synchronisierung der gebuchten Termine (SuperOffice)
* **Ziel:** Die über Bookings generierten Termine müssen für die Historie und Dokumentation im CRM-System (SuperOffice) landen.
* **Lösung:** Die im vorherigen Task ausgelesenen Termine werden über den `connector-superoffice` an das CRM übergeben und dort als "Termin" oder "Aktivität" direkt beim entsprechenden Kontakt (gematcht über die E-Mail-Adresse) abgelegt.
```env
# Info-Postfach (App 1 - Schreiben)
INFO_Application_ID=...
INFO_Tenant_ID=...
INFO_Secret=...
# E.Melcer Kalender (App 2 - Lesen)
CAL_APPID=...
CAL_TENNANT_ID=...
CAL_SECRET=...
# URLs
TEAMS_WEBHOOK_URL=...
FEEDBACK_SERVER_BASE_URL=https://floke-ai.duckdns.org/feedback
WORDPRESS_BOOKING_URL=https://www.robo-planet.de/terminbestaetigung
MS_BOOKINGS_URL=https://outlook.office365.com/book/KennenlernenmitRoboplanet@wackler-group.de/
```