nilotpaldhar2004 commited on
Commit
4cdf8b2
·
unverified ·
1 Parent(s): e3ecb06

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +123 -2
app.py CHANGED
@@ -51,7 +51,6 @@ def _heuristic_sql(question: str, table: str, cols: list = None):
51
  if "count" in q or "how many" in q:
52
  return f'SELECT COUNT(*) AS total_rows FROM "{table}"'
53
 
54
- # Extract number from question if present, default to 10
55
  match = re.search(r'\b(\d+)\b', q)
56
  limit = match.group(1) if match else "10"
57
 
@@ -193,4 +192,126 @@ async def upload_csv(file: UploadFile = File(...)):
193
  if table_name and table_name[0].isdigit():
194
  table_name = "t_" + table_name
195
 
196
- table_n
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  if "count" in q or "how many" in q:
52
  return f'SELECT COUNT(*) AS total_rows FROM "{table}"'
53
 
 
54
  match = re.search(r'\b(\d+)\b', q)
55
  limit = match.group(1) if match else "10"
56
 
 
192
  if table_name and table_name[0].isdigit():
193
  table_name = "t_" + table_name
194
 
195
+ table_name = table_name[:40]
196
+
197
+ with tempfile.NamedTemporaryFile(delete=False) as tf:
198
+ conn = sqlite3.connect(tf.name)
199
+ df.to_sql(table_name, conn, index=False, if_exists="replace")
200
+
201
+ schema = conn.execute(
202
+ "SELECT sql FROM sqlite_master WHERE type='table'"
203
+ ).fetchone()[0]
204
+
205
+ conn.close()
206
+
207
+ db_bytes = open(tf.name, "rb").read()
208
+
209
+ os.remove(tf.name)
210
+
211
+ _db_store[session_id] = {
212
+ "bytes": db_bytes,
213
+ "table": table_name,
214
+ "cols": list(df.columns)
215
+ }
216
+
217
+ _schema_store[session_id] = schema
218
+
219
+ return {
220
+ "session_id": session_id,
221
+ "row_count": len(df),
222
+ "columns": list(df.columns),
223
+ "table_name": table_name
224
+ }
225
+
226
+ except Exception as e:
227
+ raise HTTPException(status_code=500, detail=str(e))
228
+
229
+
230
+ # ─────────────────────────────
231
+ # QUERY ENGINE
232
+ # ─────────────────────────────
233
+
234
+ @app.post("/query")
235
+ async def query(req: QueryRequest):
236
+
237
+ data = _db_store.get(req.session_id)
238
+
239
+ if not data and _db_store:
240
+ data = list(_db_store.values())[-1]
241
+
242
+ if not data:
243
+ raise HTTPException(status_code=404, detail="No dataset loaded")
244
+
245
+ table = data["table"]
246
+
247
+ sql = _heuristic_sql(req.question, table, data["cols"])
248
+
249
+ if not sql:
250
+ schema = (
251
+ _schema_store.get(req.session_id)
252
+ or list(_schema_store.values())[-1]
253
+ )
254
+ sql = _call_gemini(req.question, schema, data["cols"], table)
255
+
256
+ if not sql or "error" in sql.lower():
257
+ sql = f'SELECT * FROM "{table}" LIMIT 10'
258
+
259
+ results = execute_sql(sql, data["bytes"])
260
+
261
+ return {
262
+ "sql": sql,
263
+ "results": results
264
+ }
265
+
266
+
267
+ # ─────────────────────────────
268
+ # HEALTH
269
+ # ─────────────────────────────
270
+
271
+ @app.get("/health")
272
+ def health():
273
+ return {
274
+ "status": "ok",
275
+ "model": "gemini-2.5-flash",
276
+ "service": "AI Data Analyst"
277
+ }
278
+
279
+
280
+ # ─────────────────────────────
281
+ # TELEGRAM WEBHOOK
282
+ # ─────────────────────────────
283
+
284
+ @app.on_event("startup")
285
+ async def on_startup():
286
+ try:
287
+ from bot import setup_webhook
288
+ setup_webhook()
289
+ except Exception as e:
290
+ print(f"⚠️ Webhook setup skipped: {e}")
291
+
292
+
293
+ @app.post("/webhook/{token}")
294
+ async def telegram_webhook(token: str, request: Request):
295
+ expected = os.getenv("BOT_TOKEN", "")
296
+ if token != expected:
297
+ raise HTTPException(status_code=403, detail="Invalid token")
298
+ try:
299
+ import telebot
300
+ from bot import bot
301
+ json_data = await request.json()
302
+ update = telebot.types.Update.de_json(json_data)
303
+ bot.process_new_updates([update])
304
+ except Exception as e:
305
+ print(f"❌ Webhook error: {e}")
306
+ return {"ok": True}
307
+
308
+
309
+ # ─────────────────────────────
310
+ # FRONTEND
311
+ # ─────────────────────────────
312
+
313
+ app.mount("/static", StaticFiles(directory="static"), name="static")
314
+
315
+ @app.get("/")
316
+ def root():
317
+ return FileResponse("static/webapp.html")