martinbrahm commited on
Commit
bbd2971
·
verified ·
1 Parent(s): 93ddfa4

Upload main.py

Browse files
Files changed (1) hide show
  1. main.py +25 -45
main.py CHANGED
@@ -10,6 +10,7 @@ app = FastAPI()
10
  # --- SETUP ---
11
  COLLECTION_KNOWLEDGE = "knowledge_base"
12
  COLLECTION_RULES = "availability_rules"
 
13
  KNOWLEDGE_CACHE = []
14
 
15
  # --- FIREBASE VERBINDUNG ---
@@ -49,53 +50,39 @@ def get_stem(word):
49
  return w
50
 
51
  # --- HELPER: VAPI REQUEST PARSER ---
52
- # Holt sicher die ID und die Argumente aus dem Vapi-Salat
53
  def parse_vapi_request(data):
54
  tool_call_id = "unknown"
55
  args = {}
56
-
57
  try:
58
  msg = data.get("message", {})
59
-
60
- # Variante A: Dein Log-Format ("toolCallList")
61
  if "toolCallList" in msg:
62
  call = msg["toolCallList"][0]
63
  tool_call_id = call["id"]
64
  if "function" in call and "arguments" in call["function"]:
65
  args = call["function"]["arguments"]
66
-
67
- # Variante B: Standard Vapi ("toolCalls")
68
  elif "toolCalls" in msg:
69
  call = msg["toolCalls"][0]
70
  tool_call_id = call["id"]
71
  if "function" in call and "arguments" in call["function"]:
72
  args = call["function"]["arguments"]
73
-
74
- # Argumente sind oft ein String, müssen zu JSON werden
75
  if isinstance(args, str):
76
  args = json.loads(args)
77
-
78
  except Exception as e:
79
  print(f"⚠️ Parsing Info: {e}")
80
-
81
  return tool_call_id, args
82
 
83
  # ==========================================
84
- # TOOL 1: VERFÜGBARKEIT (Strict Vapi Format)
85
  # ==========================================
86
  @app.post("/check_availability")
87
  async def check_availability(request: Request):
88
  data = await request.json()
89
- print(f"🚦 TOOL REQUEST: {json.dumps(data)[:100]}...") # Debug Log
90
-
91
- # 1. ID extrahieren (WICHTIG!)
92
  tool_call_id, _ = parse_vapi_request(data)
93
 
94
  today = datetime.now().strftime("%Y-%m-%d")
95
  status = "available"
96
  instruction = "Normal arbeiten"
97
 
98
- # 2. Datenbank Check
99
  try:
100
  if db:
101
  rules = db.collection(COLLECTION_RULES).where("active", "==", True).stream()
@@ -103,48 +90,40 @@ async def check_availability(request: Request):
103
  rd = r.to_dict()
104
  if rd.get('start_date') <= today <= rd.get('end_date'):
105
  print(f"🛑 REGEL AKTIV: {rd.get('name')}")
106
- status = "unavailable"
 
 
 
 
107
  instruction = rd.get('instruction_text')
108
  break
109
  except Exception as e:
110
  print(f"❌ ERROR CHECK: {e}")
111
 
112
- print(f"👉 RESULTAT: {status} | {instruction}")
113
-
114
- # 3. Antwort im strikten Vapi-Format
115
  return {
116
- "results": [
117
- {
118
- "toolCallId": tool_call_id,
119
- "result": {
120
- "status": status,
121
- "instruction": instruction
122
- }
123
- }
124
- ]
125
  }
126
 
127
  # ==========================================
128
- # TOOL 2: SUCHE (Jetzt auch mit ID Rückgabe!)
129
  # ==========================================
130
  @app.post("/search")
131
  async def search(request: Request):
132
  data = await request.json()
133
-
134
- # 1. ID und Query extrahieren
135
  tool_call_id, args = parse_vapi_request(data)
136
  query = args.get("search_query") or args.get("query") or data.get("search_query")
137
 
138
  print(f"🔎 FRAGE (ID: {tool_call_id}): '{query}'")
139
 
140
- answer_text = "Dazu habe ich keine Informationen."
141
 
142
  if query:
143
- # --- SUCHE LOGIK (Mit Udo/Capaneo Boost) ---
144
  STOP_WORDS = ["hallo", "guten", "tag", "moin", "bitte", "danke", "frage"]
145
  q_words = [get_stem(w) for w in query.lower().split() if len(w)>2]
146
  relevant_words = [w for w in q_words if w not in STOP_WORDS]
147
 
 
 
148
  if relevant_words:
149
  best_doc = None
150
  best_score = 0
@@ -164,30 +143,31 @@ async def search(request: Request):
164
  best_score = score
165
  best_doc = doc
166
 
 
167
  if best_doc and best_score >= 20:
168
  print(f"🏆 TREFFER ({best_score}): {best_doc.get('question')}")
169
  answer_text = best_doc.get("answer")
 
170
  else:
171
  print(f"⚠️ Zu wenig Relevanz (Max: {best_score})")
 
 
 
 
 
 
 
 
 
172
 
173
- # 3. Antwort im strikten Vapi-Format
174
- # Bei 'search' erwartet das LLM meist einfach den Text im result
175
  return {
176
- "results": [
177
- {
178
- "toolCallId": tool_call_id,
179
- "result": answer_text
180
- }
181
- ]
182
  }
183
 
184
- # ==========================================
185
- # 3. MÜLLSCHLUCKER
186
- # ==========================================
187
  @app.post("/vapi-incoming")
188
  async def dummy_incoming(request: Request):
189
  return {"status": "ok"}
190
 
191
  @app.get("/")
192
  def home():
193
- return {"status": "Online", "docs_loaded": len(KNOWLEDGE_CACHE)}
 
10
  # --- SETUP ---
11
  COLLECTION_KNOWLEDGE = "knowledge_base"
12
  COLLECTION_RULES = "availability_rules"
13
+ COLLECTION_INBOX = "inbox" # NEU: Hier landen ungelöste Fragen
14
  KNOWLEDGE_CACHE = []
15
 
16
  # --- FIREBASE VERBINDUNG ---
 
50
  return w
51
 
52
  # --- HELPER: VAPI REQUEST PARSER ---
 
53
  def parse_vapi_request(data):
54
  tool_call_id = "unknown"
55
  args = {}
 
56
  try:
57
  msg = data.get("message", {})
 
 
58
  if "toolCallList" in msg:
59
  call = msg["toolCallList"][0]
60
  tool_call_id = call["id"]
61
  if "function" in call and "arguments" in call["function"]:
62
  args = call["function"]["arguments"]
 
 
63
  elif "toolCalls" in msg:
64
  call = msg["toolCalls"][0]
65
  tool_call_id = call["id"]
66
  if "function" in call and "arguments" in call["function"]:
67
  args = call["function"]["arguments"]
 
 
68
  if isinstance(args, str):
69
  args = json.loads(args)
 
70
  except Exception as e:
71
  print(f"⚠️ Parsing Info: {e}")
 
72
  return tool_call_id, args
73
 
74
  # ==========================================
75
+ # TOOL 1: VERFÜGBARKEIT
76
  # ==========================================
77
  @app.post("/check_availability")
78
  async def check_availability(request: Request):
79
  data = await request.json()
 
 
 
80
  tool_call_id, _ = parse_vapi_request(data)
81
 
82
  today = datetime.now().strftime("%Y-%m-%d")
83
  status = "available"
84
  instruction = "Normal arbeiten"
85
 
 
86
  try:
87
  if db:
88
  rules = db.collection(COLLECTION_RULES).where("active", "==", True).stream()
 
90
  rd = r.to_dict()
91
  if rd.get('start_date') <= today <= rd.get('end_date'):
92
  print(f"🛑 REGEL AKTIV: {rd.get('name')}")
93
+ # Einfache Logik: Wenn "Ferien" im Namen -> Limited, sonst Unavailable
94
+ if "ferien" in rd.get('name', '').lower():
95
+ status = "limited"
96
+ else:
97
+ status = "unavailable"
98
  instruction = rd.get('instruction_text')
99
  break
100
  except Exception as e:
101
  print(f"❌ ERROR CHECK: {e}")
102
 
 
 
 
103
  return {
104
+ "results": [{"toolCallId": tool_call_id, "result": {"status": status, "instruction": instruction}}]
 
 
 
 
 
 
 
 
105
  }
106
 
107
  # ==========================================
108
+ # TOOL 2: SUCHE (Mit Inbox-Speicherung!)
109
  # ==========================================
110
  @app.post("/search")
111
  async def search(request: Request):
112
  data = await request.json()
 
 
113
  tool_call_id, args = parse_vapi_request(data)
114
  query = args.get("search_query") or args.get("query") or data.get("search_query")
115
 
116
  print(f"🔎 FRAGE (ID: {tool_call_id}): '{query}'")
117
 
118
+ answer_text = "Dazu habe ich leider keine Informationen in meiner Datenbank."
119
 
120
  if query:
 
121
  STOP_WORDS = ["hallo", "guten", "tag", "moin", "bitte", "danke", "frage"]
122
  q_words = [get_stem(w) for w in query.lower().split() if len(w)>2]
123
  relevant_words = [w for w in q_words if w not in STOP_WORDS]
124
 
125
+ found = False
126
+
127
  if relevant_words:
128
  best_doc = None
129
  best_score = 0
 
143
  best_score = score
144
  best_doc = doc
145
 
146
+ # SCHWELLE: 20 PUNKTE
147
  if best_doc and best_score >= 20:
148
  print(f"🏆 TREFFER ({best_score}): {best_doc.get('question')}")
149
  answer_text = best_doc.get("answer")
150
+ found = True
151
  else:
152
  print(f"⚠️ Zu wenig Relevanz (Max: {best_score})")
153
+
154
+ # --- NEU: SPEICHERN WENN NICHT GEFUNDEN ---
155
+ if not found and db:
156
+ print("📥 Speichere in Inbox...")
157
+ db.collection(COLLECTION_INBOX).add({
158
+ "query": query,
159
+ "timestamp": datetime.now(),
160
+ "status": "open"
161
+ })
162
 
 
 
163
  return {
164
+ "results": [{"toolCallId": tool_call_id, "result": answer_text}]
 
 
 
 
 
165
  }
166
 
 
 
 
167
  @app.post("/vapi-incoming")
168
  async def dummy_incoming(request: Request):
169
  return {"status": "ok"}
170
 
171
  @app.get("/")
172
  def home():
173
+ return {"status": "Online", "docs": len(KNOWLEDGE_CACHE)}