martinbrahm commited on
Commit
1b5d2ca
·
verified ·
1 Parent(s): 35ea9b7

Upload main.py

Browse files
Files changed (1) hide show
  1. main.py +55 -162
main.py CHANGED
@@ -1,168 +1,61 @@
1
- import uvicorn
2
  from fastapi import FastAPI, Request
3
- from sqlalchemy import create_engine, Column, Integer, String, DateTime, Text
4
- from sqlalchemy.orm import DeclarativeBase, sessionmaker
5
- from datetime import datetime
6
 
7
- # --- 1. DATENBANK SETUP ---
8
- DATABASE_URL = "sqlite:///./vapi_leads.db"
9
- engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
10
- SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
11
-
12
- class Base(DeclarativeBase):
13
- pass
14
-
15
- class CallLog(Base):
16
- __tablename__ = "vapi_anrufe"
17
- id = Column(Integer, primary_key=True, index=True)
18
- call_id = Column(String, unique=True)
19
- customer_number = Column(String)
20
- status = Column(String)
21
- transcript = Column(Text, nullable=True)
22
- timestamp = Column(DateTime, default=datetime.utcnow)
23
-
24
- Base.metadata.create_all(bind=engine)
25
-
26
- # --- 2. SERVER (Der entscheidende Teil) ---
27
  app = FastAPI()
28
 
29
- # WICHTIG: Hier definieren wir die Tür "/vapi", an die Vapi klopft!
30
- @app.post("/vapi")
31
- async def handle_vapi_event(request: Request):
 
 
 
 
 
 
32
  try:
33
  data = await request.json()
34
- message = data.get("message", {})
35
- msg_type = message.get("type")
36
-
37
- print(f"📩 Event empfangen: {msg_type}")
38
-
39
- db = SessionLocal()
40
-
41
- # Fall 1: Anruf startet (neuer Name: assistant.started)
42
- if msg_type == "assistant.started":
43
- call_details = message.get("call", {})
44
- customer_number = call_details.get("customer", {}).get("number", "Unbekannt")
45
- call_id = call_details.get("id")
46
-
47
- print(f"📞 Neuer Anruf erkannt! ID: {call_id}")
48
-
49
- # Prüfen ob Anruf schon da ist, sonst anlegen
50
- existing = db.query(CallLog).filter(CallLog.call_id == call_id).first()
51
- if not existing:
52
- new_call = CallLog(call_id=call_id, customer_number=customer_number, status="Live")
53
- db.add(new_call)
54
- db.commit()
55
-
56
- # Fall 2: Anruf zu Ende (Transkript speichern)
57
- elif msg_type == "end-of-call-report":
58
- call_id = message.get("call", {}).get("id")
59
- transcript = message.get("transcript", "")
60
- summary = message.get("summary", "Keine Zusammenfassung")
61
-
62
- print(f"✅ Anruf beendet. Transkript empfangen.")
63
-
64
- existing_call = db.query(CallLog).filter(CallLog.call_id == call_id).first()
65
- if existing_call:
66
- existing_call.status = "Beendet"
67
- existing_call.transcript = transcript
68
- db.commit()
69
-
70
- db.close()
71
- except Exception as e:
72
- print(f"⚠️ Fehler beim Verarbeiten: {e}")
73
-
74
- return {"status": "ok"}
75
- from fastapi.responses import HTMLResponse
76
-
77
- # --- WEBSEITE FÜR TESTER ---
78
- @app.get("/", response_class=HTMLResponse)
79
- async def get_web_interface():
80
- # HIER DEINE DATEN EINTRAGEN:
81
- VAPI_PUBLIC_KEY = "f4f1efff-091c-495f-acab-4669b1cc7cbe" # Beginnt nicht mit 'ey...', ist kürzer
82
- ASSISTANT_ID = "4008c58f-556c-44a3-b78d-2b920ea80c66"
83
-
84
- html_content = f"""
85
- <!DOCTYPE html>
86
- <html lang="de">
87
- <head>
88
- <meta charset="UTF-8">
89
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
90
- <title>Test: Alex Sales Bot</title>
91
- <script src="https://cdn.jsdelivr.net/gh/VapiAI/html-script-tag@latest/dist/assets/index.js"></script>
92
- <style>
93
- body {{
94
- font-family: 'Segoe UI', sans-serif;
95
- background-color: #f4f4f9;
96
- display: flex;
97
- flex-direction: column;
98
- align_items: center;
99
- justify-content: center;
100
- height: 100vh;
101
- margin: 0;
102
- color: #333;
103
- }}
104
- h1 {{ margin-bottom: 20px; }}
105
- p {{ color: #666; margin-bottom: 40px; }}
106
- .info {{
107
- background: white; padding: 20px; border-radius: 10px;
108
- box-shadow: 0 4px 6px rgba(0,0,0,0.1);
109
- text-align: center;
110
- }}
111
- </style>
112
- </head>
113
- <body>
114
- <div class="info">
115
- <h1>📞 Teste meinen Sales-Bot</h1>
116
- <p>Klicke unten rechts auf den Button, um das Gespräch zu starten.</p>
117
- <small>⚠️ Mein Laptop muss an sein, damit es funktioniert.</small>
118
- </div>
119
-
120
- <script>
121
- var vapiInstance = null;
122
- const assistant = "{ASSISTANT_ID}";
123
- const apiKey = "{VAPI_PUBLIC_KEY}";
124
-
125
- // Konfiguration des Buttons
126
- const buttonConfig = {{
127
- position: "bottom-right",
128
- offset: "40px",
129
- width: "50px",
130
- height: "50px",
131
- idle: {{
132
- color: "rgb(93, 254, 202)",
133
- type: "pill",
134
- title: "Hier klicken zum Sprechen",
135
- subtitle: "Kostenloser Testanruf",
136
- icon: "https://unpkg.com/lucide-static@0.321.0/icons/phone.svg",
137
- }},
138
- loading: {{
139
- color: "rgb(93, 124, 202)",
140
- type: "pill",
141
- title: "Verbinde...",
142
- subtitle: "Bitte warten",
143
- icon: "https://unpkg.com/lucide-static@0.321.0/icons/loader-2.svg",
144
- }},
145
- active: {{
146
- color: "rgb(255, 0, 0)",
147
- type: "pill",
148
- title: "Anruf läuft...",
149
- subtitle: "Klicken zum Auflegen",
150
- icon: "https://unpkg.com/lucide-static@0.321.0/icons/phone-off.svg",
151
- }}
152
- }};
153
-
154
- (function() {{
155
- vapiInstance = window.vapiSDK.run({{
156
- apiKey: apiKey,
157
- assistant: assistant,
158
- config: buttonConfig
159
- }});
160
- }})();
161
- </script>
162
- </body>
163
- </html>
164
- """
165
- return html_content
166
-
167
- if __name__ == "__main__":
168
- uvicorn.run(app, host="0.0.0.0", port=8000)
 
 
1
  from fastapi import FastAPI, Request
2
+ import json
 
 
3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  app = FastAPI()
5
 
6
+ # 1. Startseite (damit du im Browser siehst, dass es läuft)
7
+ @app.get("/")
8
+ def home():
9
+ return {"status": "Die API läuft und wartet auf Vapi!"}
10
+
11
+ # 2. Der Such-Endpunkt für Vapi
12
+ @app.post("/search")
13
+ async def search_knowledge(request: Request):
14
+ # Wir holen uns die Daten, egal wie Vapi sie verpackt
15
  try:
16
  data = await request.json()
17
+ print(f"📥 DEBUG: {json.dumps(data)}") # Zeigt dir im Log, was ankommt
18
+ except:
19
+ return {"result": "Fehler: Kein JSON empfangen."}
20
+
21
+ query_text = ""
22
+
23
+ # Vapi sendet Daten oft tief verschachtelt. Wir suchen die 'query' überall:
24
+
25
+ # Check 1: Einfaches Format (dein Curl Test)
26
+ if "query" in data and isinstance(data["query"], str):
27
+ query_text = data["query"]
28
+
29
+ # Check 2: Vapi Format A (message -> toolCalls)
30
+ elif "message" in data and "toolCalls" in data["message"]:
31
+ try:
32
+ args = data["message"]["toolCalls"][0]["function"]["arguments"]
33
+ # Manchmal ist args ein String, manchmal schon ein Objekt
34
+ if isinstance(args, str):
35
+ query_text = json.loads(args).get("query", "")
36
+ else:
37
+ query_text = args.get("query", "")
38
+ except:
39
+ pass
40
+
41
+ # Check 3: Vapi Format B (direkt toolCall)
42
+ elif "toolCall" in data:
43
+ try:
44
+ args = data["toolCall"]["function"]["arguments"]
45
+ if isinstance(args, str):
46
+ query_text = json.loads(args).get("query", "")
47
+ else:
48
+ query_text = args.get("query", "")
49
+ except:
50
+ pass
51
+
52
+ # --- ANTWORT ---
53
+ if not query_text:
54
+ # Fallback, falls wir nichts finden
55
+ return {"result": "Ich habe die Frage technisch nicht verstanden. Bitte prüfen Sie die Parameter."}
56
+
57
+ # Einfache Logik für den Test:
58
+ if "geo" in query_text.lower():
59
+ return {"result": "Geofencing ist eine virtuelle Begrenzung für ein echtes geografisches Gebiet."}
60
+
61
+ return {"result": f"Ich habe deine Frage '{query_text}' erhalten, habe aber keine Antwort in der Datenbank."}