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

Upload main.py

Browse files
Files changed (1) hide show
  1. main.py +38 -63
main.py CHANGED
@@ -8,11 +8,9 @@ from datetime import datetime
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 ---
@@ -45,7 +43,6 @@ def reload_knowledge():
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,59 +50,46 @@ def get_stem(word):
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):
 
 
 
 
 
 
62
  try:
63
- data = await request.json()
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,7 +97,7 @@ 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,14 +107,12 @@ async def search(request: Request):
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,12 +123,9 @@ async def search(request: Request):
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,7 +133,6 @@ async def search(request: Request):
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")}
@@ -166,9 +144,6 @@ async def search(request: Request):
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"]}
 
8
  app = FastAPI()
9
 
10
  # --- KONFIGURATION ---
 
 
 
11
  COLLECTION_KNOWLEDGE = "knowledge_base"
12
  COLLECTION_RULES = "availability_rules"
13
+ COLLECTION_INBOX = "inbox"
14
  KNOWLEDGE_CACHE = []
15
 
16
  # --- FIREBASE VERBINDUNG ---
 
43
  async def startup():
44
  reload_knowledge()
45
 
 
46
  def get_stem(word):
47
  w = word.lower().strip()
48
  for end in ["ern", "en", "er", "es", "st", "te", "e", "s", "t"]:
 
50
  return w
51
 
52
  # ==========================================
53
+ # NEU: TOOL FÜR VERFÜGBARKEIT
54
+ # Endpunkt: /check_availability
 
55
  # ==========================================
56
+ @app.post("/check_availability")
57
+ async def check_availability(request: Request):
58
+ print("🚦 TOOL CALL: checkAvailability")
59
+
60
+ today = datetime.now().strftime("%Y-%m-%d")
61
+ status = "available"
62
+ message = "Normaler Betrieb. Nimm Anrufe entgegen und vereinbare Termine."
63
+
64
  try:
65
+ if db:
66
+ rules = db.collection(COLLECTION_RULES).where("active", "==", True).stream()
67
+ for r in rules:
68
+ rd = r.to_dict()
69
+ # Datum Check
70
+ if rd.get('start_date') <= today <= rd.get('end_date'):
71
+ print(f"🛑 REGEL GEFUNDEN: {rd.get('name')}")
72
+ status = "unavailable"
73
+ # Wir bauen die Instruktion direkt in die Message
74
+ message = f"ACHTUNG SONDERREGEL: {rd.get('instruction_text')}"
75
+ break
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  except Exception as e:
77
+ print(f"❌ ERROR CHECK: {e}")
78
+ return {"status": "error", "message": "Fehler beim Datenbank-Check. Gehe von Normalbetrieb aus."}
79
+
80
+ print(f"👉 RESULTAT: {status} | {message}")
81
 
82
+ # Rückgabe genau wie vom LLM benötigt
83
+ return {
84
+ "result": json.dumps({
85
+ "status": status,
86
+ "instruction": message
87
+ })
88
+ }
89
 
90
  # ==========================================
91
+ # TOOL: SUCHE / WISSEN
92
  # Endpunkt: /search
 
93
  # ==========================================
94
  @app.post("/search")
95
  async def search(request: Request):
 
97
  data = await request.json()
98
  query = ""
99
 
100
+ # Parsing Logic
101
  if "search_query" in data: query = data["search_query"]
102
  elif "message" in data and "toolCalls" in data["message"]:
103
  args = data["message"]["toolCalls"][0]["function"]["arguments"]
 
107
  print(f"🔎 FRAGE: '{query}'")
108
  if not query: return {"result": "Akustik-Fehler."}
109
 
110
+ # Stop-Wörter
111
  STOP_WORDS = ["capaneo", "udo", "schober", "firma", "gmbh", "hallo", "demo"]
 
112
  q_words = [get_stem(w) for w in query.lower().split() if len(w)>2]
113
  relevant_words = [w for w in q_words if w not in STOP_WORDS]
114
 
115
  if not relevant_words:
 
116
  return {"result": "Dazu habe ich keine spezifischen Informationen."}
117
 
118
  best_doc = None
 
123
  txt = (doc.get("question", "") + " " + doc.get("answer", "")).lower()
124
  kws = [k.lower() for k in doc.get("keywords", [])]
125
 
 
126
  for k in kws:
127
  k_stem = get_stem(k)
128
  if k_stem in relevant_words: score += 30
 
 
129
  for w in relevant_words:
130
  if w in txt: score += 5
131
 
 
133
  best_score = score
134
  best_doc = doc
135
 
 
136
  if best_doc and best_score >= 15:
137
  print(f"🏆 TREFFER ({best_score}): {best_doc.get('question')}")
138
  return {"result": best_doc.get("answer")}
 
144
  print(f"❌ SEARCH ERROR: {e}")
145
  return {"result": "Fehler."}
146
 
 
 
 
147
  @app.get("/")
148
+ def home():
149
+ return {"status": "Online", "endpoints": ["/check_availability", "/search"]}