martinbrahm commited on
Commit
db10d88
·
verified ·
1 Parent(s): 5f7913b

Upload main.py

Browse files
Files changed (1) hide show
  1. main.py +87 -60
main.py CHANGED
@@ -8,9 +8,11 @@ from datetime import datetime
8
  app = FastAPI()
9
 
10
  # --- EINSTELLUNGEN ---
11
- # Deine korrekten Sammlungs-Namen aus dem Screenshot
12
  COLLECTION_KNOWLEDGE = "knowledge_base"
13
- COLLECTION_INBOX = "inbox" # Kleingeschrieben, wie Standard
 
 
 
14
 
15
  # --- FIREBASE VERBINDUNG ---
16
  db = None
@@ -28,94 +30,119 @@ try:
28
  except Exception as e:
29
  print(f"❌ FEHLER beim Start: {e}")
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  @app.get("/")
32
  def home():
33
- return {"status": "Udo Agent API (Live) ist bereit."}
 
 
 
 
 
 
 
 
 
34
 
35
  @app.post("/search")
36
  async def search_knowledge(request: Request):
37
- # 1. DATEN EMPFANGEN
38
  try:
39
  data = await request.json()
40
  except:
41
  return {"result": "Fehler: Kein JSON."}
42
 
43
- # 2. FRAGE EXTRAHIEREN (Robust für Vapi)
44
  query_text = ""
45
- if "query" in data and isinstance(data["query"], str):
46
  query_text = data["query"]
47
  elif "message" in data and "toolCalls" in data["message"]:
48
  try:
49
  args = data["message"]["toolCalls"][0]["function"]["arguments"]
50
  query_text = json.loads(args).get("query", "") if isinstance(args, str) else args.get("query", "")
51
  except: pass
52
- elif "toolCall" in data:
53
- try:
54
- args = data["toolCall"]["function"]["arguments"]
55
- query_text = json.loads(args).get("query", "") if isinstance(args, str) else args.get("query", "")
56
- except: pass
57
 
58
- print(f"🔎 FRAGE: '{query_text}'")
59
 
60
  if not query_text:
61
  return {"result": "Ich habe die Frage akustisch nicht verstanden."}
62
- if not db:
63
- return {"result": "Server-Fehler: Datenbank nicht verbunden."}
64
 
65
- # 3. INTELLIGENTE SUCHE (Deine 752 Dokumente)
66
  antwort = "Dazu habe ich leider keine Informationen in meiner Datenbank. Ich habe die Frage für das Team notiert."
67
  treffer = False
68
 
69
- try:
70
- # Wir laden alle Dokumente (Caching wäre bei >2000 Docs nötig, für 750 geht es noch)
71
- docs = db.collection(COLLECTION_KNOWLEDGE).stream()
72
- query_lower = query_text.lower()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
- for doc in docs:
75
- d = doc.to_dict()
76
-
77
- # Felder sicher auslesen (auch wenn mal eins fehlt)
78
- t_answer = d.get("answer") or d.get("Antwort") or d.get("content")
79
- t_keywords = d.get("keywords") or d.get("Keywords") or []
80
- t_question = d.get("question") or d.get("Frage") or ""
81
-
82
- if not t_answer:
83
- continue
84
-
85
- # A) Keyword-Match (Sehr stark!)
86
- if isinstance(t_keywords, list):
87
- # Prüft, ob ein Keyword in der Frage vorkommt
88
- if any(k.lower() in query_lower for k in t_keywords):
89
- antwort = t_answer
90
- treffer = True
91
- print(f"✅ TREFFER (Keyword) in Doc {doc.id}")
92
- break
93
-
94
- # B) Frage-Match (Fuzzy)
95
- # Prüft, ob die User-Frage in der DB-Frage steckt (oder umgekehrt)
96
- if t_question and (t_question.lower() in query_lower or query_lower in t_question.lower()):
97
- antwort = t_answer
98
- treffer = True
99
- print(f"✅ TREFFER (Frage-Match) in Doc {doc.id}")
100
- break
101
-
102
- # 4. LERN-LOGIK (INBOX)
103
- if not treffer:
104
- print(f"⚠️ KEIN TREFFER. Speichere in '{COLLECTION_INBOX}'...")
105
- try:
106
  db.collection(COLLECTION_INBOX).add({
107
  "question": query_text,
108
  "status": "open",
109
  "timestamp": firestore.SERVER_TIMESTAMP,
110
- "source": "Vapi Call"
111
  })
112
- print("📩 Erfolgreich in Inbox gespeichert.")
113
- except Exception as e:
114
- print(f"❌ Fehler beim Speichern in Inbox: {e}")
115
-
116
- except Exception as e:
117
- print(f"❌ DATABASE ERROR: {e}")
118
- return {"result": "Es gab ein technisches Problem beim Zugriff auf das Wissen."}
119
 
120
- # Sauberes Ergebnis für Vapi
121
  return {"result": antwort}
 
8
  app = FastAPI()
9
 
10
  # --- EINSTELLUNGEN ---
 
11
  COLLECTION_KNOWLEDGE = "knowledge_base"
12
+ COLLECTION_INBOX = "inbox"
13
+
14
+ # --- GLOBALE VARIABLE (Der Turbo-Speicher) ---
15
+ KNOWLEDGE_CACHE = []
16
 
17
  # --- FIREBASE VERBINDUNG ---
18
  db = None
 
30
  except Exception as e:
31
  print(f"❌ FEHLER beim Start: {e}")
32
 
33
+ # --- HILFSFUNKTION: DATEN IN RAM LADEN ---
34
+ def reload_knowledge():
35
+ global KNOWLEDGE_CACHE
36
+ if not db:
37
+ return 0
38
+
39
+ print("🔄 Lade Wissensdatenbank in den Arbeitsspeicher...")
40
+ try:
41
+ docs = db.collection(COLLECTION_KNOWLEDGE).stream()
42
+ new_cache = []
43
+ for doc in docs:
44
+ d = doc.to_dict()
45
+ d["id"] = doc.id # ID speichern für Logs
46
+ new_cache.append(d)
47
+
48
+ KNOWLEDGE_CACHE = new_cache
49
+ print(f"🚀 TURBO-MODE: {len(KNOWLEDGE_CACHE)} Dokumente im RAM bereit!")
50
+ return len(KNOWLEDGE_CACHE)
51
+ except Exception as e:
52
+ print(f"❌ Fehler beim Laden des Caches: {e}")
53
+ return 0
54
+
55
+ # --- STARTUP EVENT (Lädt Daten sofort beim Start) ---
56
+ @app.on_event("startup")
57
+ async def startup_event():
58
+ reload_knowledge()
59
+
60
+ # --- ENDPUNKTE ---
61
+
62
  @app.get("/")
63
  def home():
64
+ return {
65
+ "status": "Turbo-Agent ist bereit.",
66
+ "cached_docs": len(KNOWLEDGE_CACHE),
67
+ "info": "Nutze /refresh_knowledge um neue Daten zu laden."
68
+ }
69
+
70
+ @app.get("/refresh_knowledge")
71
+ def refresh_endpoint():
72
+ count = reload_knowledge()
73
+ return {"status": "Cache aktualisiert", "docs_loaded": count}
74
 
75
  @app.post("/search")
76
  async def search_knowledge(request: Request):
77
+ # 1. FRAGE EMPFANGEN
78
  try:
79
  data = await request.json()
80
  except:
81
  return {"result": "Fehler: Kein JSON."}
82
 
83
+ # Frage extrahieren (Vapi/Retell kompatibel)
84
  query_text = ""
85
+ if "query" in data:
86
  query_text = data["query"]
87
  elif "message" in data and "toolCalls" in data["message"]:
88
  try:
89
  args = data["message"]["toolCalls"][0]["function"]["arguments"]
90
  query_text = json.loads(args).get("query", "") if isinstance(args, str) else args.get("query", "")
91
  except: pass
92
+
93
+ # Retell AI spezifisch (falls Retell die Frage anders schickt)
94
+ if not query_text and "args" in data:
95
+ query_text = data["args"].get("query", "")
 
96
 
97
+ print(f"🔎 TURBO-SEARCH: '{query_text}'")
98
 
99
  if not query_text:
100
  return {"result": "Ich habe die Frage akustisch nicht verstanden."}
 
 
101
 
102
+ # 2. SUCHEN IM RAM (Rasend schnell!)
103
  antwort = "Dazu habe ich leider keine Informationen in meiner Datenbank. Ich habe die Frage für das Team notiert."
104
  treffer = False
105
 
106
+ query_lower = query_text.lower()
107
+
108
+ # Wir iterieren durch die Liste im Speicher, nicht durch die Datenbank!
109
+ for entry in KNOWLEDGE_CACHE:
110
+ # Felder sicher auslesen
111
+ t_answer = entry.get("answer") or entry.get("Antwort") or entry.get("content")
112
+ t_keywords = entry.get("keywords") or entry.get("Keywords") or []
113
+ t_question = entry.get("question") or entry.get("Frage") or ""
114
+
115
+ if not t_answer:
116
+ continue
117
+
118
+ # A) Keyword-Match
119
+ if isinstance(t_keywords, list):
120
+ if any(k.lower() in query_lower for k in t_keywords):
121
+ antwort = t_answer
122
+ treffer = True
123
+ print(f"✅ TREFFER (Keyword) in Doc {entry.get('id')}")
124
+ break
125
 
126
+ # B) Frage-Match
127
+ if t_question and (t_question.lower() in query_lower or query_lower in t_question.lower()):
128
+ antwort = t_answer
129
+ treffer = True
130
+ print(f" TREFFER (Frage-Match) in Doc {entry.get('id')}")
131
+ break
132
+
133
+ # 3. LERN-LOGIK (Nur schreiben, wenn nichts gefunden)
134
+ if not treffer:
135
+ print(f"⚠️ KEIN TREFFER. Schreibe in '{COLLECTION_INBOX}' (DB Write)...")
136
+ # Das Schreiben passiert im Hintergrund, bremst die Antwort kaum
137
+ try:
138
+ if db:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  db.collection(COLLECTION_INBOX).add({
140
  "question": query_text,
141
  "status": "open",
142
  "timestamp": firestore.SERVER_TIMESTAMP,
143
+ "source": "AI Call"
144
  })
145
+ except Exception as e:
146
+ print(f"❌ Fehler Inbox: {e}")
 
 
 
 
 
147
 
 
148
  return {"result": antwort}