martinbrahm commited on
Commit
eb6f485
·
verified ·
1 Parent(s): bb1daa0

Upload main.py

Browse files
Files changed (1) hide show
  1. main.py +43 -28
main.py CHANGED
@@ -7,12 +7,15 @@ from datetime import datetime
7
 
8
  app = FastAPI()
9
 
10
- # --- SETUP ---
 
 
 
11
  COLLECTION_KNOWLEDGE = "knowledge_base"
12
  COLLECTION_RULES = "availability_rules"
13
  KNOWLEDGE_CACHE = []
14
 
15
- # --- DB VERBINDUNG ---
16
  db = None
17
  try:
18
  key = os.environ.get("FIREBASE_KEY")
@@ -42,7 +45,7 @@ def reload_knowledge():
42
  async def startup():
43
  reload_knowledge()
44
 
45
- # --- HELPER ---
46
  def get_stem(word):
47
  w = word.lower().strip()
48
  for end in ["ern", "en", "er", "es", "st", "te", "e", "s", "t"]:
@@ -50,7 +53,9 @@ def get_stem(word):
50
  return w
51
 
52
  # ==========================================
53
- # 1. START DES ANRUFS (Verfügbarkeit)
 
 
54
  # ==========================================
55
  @app.post("/vapi-incoming")
56
  async def vapi_incoming(request: Request):
@@ -59,42 +64,48 @@ async def vapi_incoming(request: Request):
59
  msg = data.get("message", {})
60
  msg_type = msg.get("type")
61
 
62
- # LOGGEN WAS PASSIERT
63
- print(f"⚡ INCOMING EVENT: {msg_type}")
64
 
65
- # Nur hier reagieren wir mit Regeln!
66
  if msg_type == "assistant-request":
67
- print("📞 ANRUF STARTET - Prüfe Regeln...")
 
68
  today = datetime.now().strftime("%Y-%m-%d")
69
- context = ""
70
 
 
71
  if db:
72
  rules = db.collection(COLLECTION_RULES).where("active", "==", True).stream()
73
  for r in rules:
74
  rd = r.to_dict()
75
- # Prüfen ob Datum passt
76
  if rd.get('start_date') <= today <= rd.get('end_date'):
77
- print(f"🛑 REGEL AKTIV: {rd.get('name')}")
78
- context = f"ACHTUNG - BESONDERE SITUATION: {rd.get('instruction_text')}"
79
  break
80
 
81
- if not context: print("✅ Keine Regeln für heute.")
 
82
 
 
83
  return {
84
- "assistant": {
 
85
  "variableValues": {
86
- "seasonal_context": context
87
  }
88
  }
89
  }
90
 
91
  except Exception as e:
92
- print(f"❌ ERROR START: {e}")
93
 
94
  return {"status": "ok"}
95
 
96
  # ==========================================
97
- # 2. WÄHREND DES ANRUFS (Suche)
 
 
98
  # ==========================================
99
  @app.post("/search")
100
  async def search(request: Request):
@@ -102,7 +113,7 @@ async def search(request: Request):
102
  data = await request.json()
103
  query = ""
104
 
105
- # Parsing
106
  if "search_query" in data: query = data["search_query"]
107
  elif "message" in data and "toolCalls" in data["message"]:
108
  args = data["message"]["toolCalls"][0]["function"]["arguments"]
@@ -112,17 +123,14 @@ async def search(request: Request):
112
  print(f"🔎 FRAGE: '{query}'")
113
  if not query: return {"result": "Akustik-Fehler."}
114
 
115
- # --- INTELLIGENTE FILTERUNG ---
116
- # Wörter, die wir IGNORIEREN, damit er nicht bei "Capaneo" jedes Dokument findet
117
  STOP_WORDS = ["capaneo", "udo", "schober", "firma", "gmbh", "hallo", "demo"]
118
 
119
  q_words = [get_stem(w) for w in query.lower().split() if len(w)>2]
120
  relevant_words = [w for w in q_words if w not in STOP_WORDS]
121
 
122
- print(f" ⚙️ Relevante Suchwörter: {relevant_words}")
123
-
124
  if not relevant_words:
125
- print("⚠️ Keine relevanten Keywords gefunden (nur Stopwörter).")
126
  return {"result": "Dazu habe ich keine spezifischen Informationen."}
127
 
128
  best_doc = None
@@ -133,12 +141,12 @@ async def search(request: Request):
133
  txt = (doc.get("question", "") + " " + doc.get("answer", "")).lower()
134
  kws = [k.lower() for k in doc.get("keywords", [])]
135
 
136
- # A) Keywords (Stark)
137
  for k in kws:
138
  k_stem = get_stem(k)
139
  if k_stem in relevant_words: score += 30
140
 
141
- # B) Text (Mittel)
142
  for w in relevant_words:
143
  if w in txt: score += 5
144
 
@@ -146,14 +154,21 @@ async def search(request: Request):
146
  best_score = score
147
  best_doc = doc
148
 
149
- # Schwelle auf 15 setzen
150
  if best_doc and best_score >= 15:
151
  print(f"🏆 TREFFER ({best_score}): {best_doc.get('question')}")
152
  return {"result": best_doc.get("answer")}
153
  else:
154
- print(f"⚠️ KEIN GUTER TREFFER (Max: {best_score})")
155
  return {"result": "Dazu habe ich leider keine Informationen."}
156
 
157
  except Exception as e:
158
  print(f"❌ SEARCH ERROR: {e}")
159
- return {"result": "Fehler."}
 
 
 
 
 
 
 
 
7
 
8
  app = FastAPI()
9
 
10
+ # --- KONFIGURATION ---
11
+ # Trage hier die ID von Alex aus deinem Vapi Dashboard ein!
12
+ ALEX_ID = "e3e86ece-e6d3-459c-87bc-e9fb9a0f0aa0"
13
+
14
  COLLECTION_KNOWLEDGE = "knowledge_base"
15
  COLLECTION_RULES = "availability_rules"
16
  KNOWLEDGE_CACHE = []
17
 
18
+ # --- FIREBASE VERBINDUNG ---
19
  db = None
20
  try:
21
  key = os.environ.get("FIREBASE_KEY")
 
45
  async def startup():
46
  reload_knowledge()
47
 
48
+ # --- HELPER: WORTSTÄMME ---
49
  def get_stem(word):
50
  w = word.lower().strip()
51
  for end in ["ern", "en", "er", "es", "st", "te", "e", "s", "t"]:
 
53
  return w
54
 
55
  # ==========================================
56
+ # 1. DER TÜRSTEHER (Phone Number URL)
57
+ # Endpunkt: /vapi-incoming
58
+ # Aufgabe: Prüft Regeln & weist den Agenten zu
59
  # ==========================================
60
  @app.post("/vapi-incoming")
61
  async def vapi_incoming(request: Request):
 
64
  msg = data.get("message", {})
65
  msg_type = msg.get("type")
66
 
67
+ # Loggen für Debugging
68
+ print(f"⚡ PHONE EVENT: {msg_type}")
69
 
 
70
  if msg_type == "assistant-request":
71
+ print("📞 ANRUF GEHT EIN! Entscheide Routing & Kontext...")
72
+
73
  today = datetime.now().strftime("%Y-%m-%d")
74
+ context_text = ""
75
 
76
+ # 1. Datenbank prüfen (Ist heute Schulung?)
77
  if db:
78
  rules = db.collection(COLLECTION_RULES).where("active", "==", True).stream()
79
  for r in rules:
80
  rd = r.to_dict()
81
+ # Datum Check
82
  if rd.get('start_date') <= today <= rd.get('end_date'):
83
+ print(f"🛑 SONDERREGEL AKTIV: {rd.get('name')}")
84
+ context_text = f"WICHTIGE VERFÜGBARKEITS-INFO: {rd.get('instruction_text')}"
85
  break
86
 
87
+ if not context_text:
88
+ print("✅ Keine Regeln (Normalbetrieb).")
89
 
90
+ # 2. Antwort an Vapi: "Nimm Alex + Hier ist der Kontext"
91
  return {
92
+ "assistantId": ALEX_ID,
93
+ "assistantOverrides": {
94
  "variableValues": {
95
+ "seasonal_context": context_text
96
  }
97
  }
98
  }
99
 
100
  except Exception as e:
101
+ print(f"❌ ERROR ROUTING: {e}")
102
 
103
  return {"status": "ok"}
104
 
105
  # ==========================================
106
+ # 2. DAS GEHIRN (Tool URL)
107
+ # Endpunkt: /search
108
+ # Aufgabe: Sucht Preise und Infos während des Gesprächs
109
  # ==========================================
110
  @app.post("/search")
111
  async def search(request: Request):
 
113
  data = await request.json()
114
  query = ""
115
 
116
+ # Robustes Parsing (egal wie Vapi die Frage verpackt)
117
  if "search_query" in data: query = data["search_query"]
118
  elif "message" in data and "toolCalls" in data["message"]:
119
  args = data["message"]["toolCalls"][0]["function"]["arguments"]
 
123
  print(f"🔎 FRAGE: '{query}'")
124
  if not query: return {"result": "Akustik-Fehler."}
125
 
126
+ # STOP-WÖRTER (Damit er nicht bei 'Udo' halluziniert)
 
127
  STOP_WORDS = ["capaneo", "udo", "schober", "firma", "gmbh", "hallo", "demo"]
128
 
129
  q_words = [get_stem(w) for w in query.lower().split() if len(w)>2]
130
  relevant_words = [w for w in q_words if w not in STOP_WORDS]
131
 
 
 
132
  if not relevant_words:
133
+ print("⚠️ Nur Stopwörter erkannt - Breche ab.")
134
  return {"result": "Dazu habe ich keine spezifischen Informationen."}
135
 
136
  best_doc = None
 
141
  txt = (doc.get("question", "") + " " + doc.get("answer", "")).lower()
142
  kws = [k.lower() for k in doc.get("keywords", [])]
143
 
144
+ # Hohe Punkte für Keywords (Preis, Kosten, Starter)
145
  for k in kws:
146
  k_stem = get_stem(k)
147
  if k_stem in relevant_words: score += 30
148
 
149
+ # Wenig Punkte für Fließtext
150
  for w in relevant_words:
151
  if w in txt: score += 5
152
 
 
154
  best_score = score
155
  best_doc = doc
156
 
157
+ # Schwelle: Mindestens 15 Punkte für einen Treffer
158
  if best_doc and best_score >= 15:
159
  print(f"🏆 TREFFER ({best_score}): {best_doc.get('question')}")
160
  return {"result": best_doc.get("answer")}
161
  else:
162
+ print(f"⚠️ KEIN TREFFER (Max: {best_score})")
163
  return {"result": "Dazu habe ich leider keine Informationen."}
164
 
165
  except Exception as e:
166
  print(f"❌ SEARCH ERROR: {e}")
167
+ return {"result": "Fehler."}
168
+
169
+ # ==========================================
170
+ # 3. KOSMETIK (Damit '404' im Log verschwindet)
171
+ # ==========================================
172
+ @app.get("/")
173
+ async def root():
174
+ return {"status": "Udo API Online", "endpoints": ["/vapi-incoming", "/search"]}