Spaces:
Runtime error
Runtime error
| import duckdb | |
| from fastapi import FastAPI, Query | |
| import os | |
| from contextlib import asynccontextmanager | |
| MOUNT_PATH = "/data" | |
| FILES = { | |
| "p2": "TGDATA BY DEADLOX P2.parquet", | |
| "p4": "TGDATA BY DEADLOX P4.parquet" | |
| } | |
| AVAILABLE = {} | |
| async def lifespan(app: FastAPI): | |
| global AVAILABLE | |
| for key, fname in FILES.items(): | |
| path = os.path.join(MOUNT_PATH, fname) | |
| if os.path.exists(path): | |
| AVAILABLE[key] = path | |
| print(f"✅ {key}: {fname}") | |
| yield | |
| app = FastAPI(lifespan=lifespan) | |
| con = duckdb.connect() | |
| # Preload column names for each file (to avoid reading file every time) | |
| COLUMNS = {} | |
| def get_columns(db: str): | |
| if db not in COLUMNS: | |
| path = AVAILABLE[db] | |
| df = con.execute(f"SELECT * FROM '{path}' LIMIT 0").fetchdf() | |
| COLUMNS[db] = list(df.columns) | |
| return COLUMNS[db] | |
| async def search_fast( | |
| q: str = Query(..., min_length=1), | |
| db: str = Query("p4") | |
| ): | |
| if db not in AVAILABLE: | |
| return {"error": f"Database {db} not available", "developer": "Gopal Parmar"} | |
| path = AVAILABLE[db] | |
| keyword = q.strip() | |
| # Determine if keyword looks like a phone number (digits only, length 10-15) | |
| is_numeric = keyword.replace('+', '').isdigit() and len(keyword) >= 5 | |
| try: | |
| if is_numeric: | |
| # Exact match on phone or user_id columns (fast) | |
| query = f""" | |
| SELECT * FROM '{path}' | |
| WHERE phone = '{keyword}' | |
| OR user_id = '{keyword}' | |
| OR username = '{keyword}' | |
| LIMIT 50 | |
| """ | |
| else: | |
| # Text search only on relevant columns (username, first_name, last_name) | |
| query = f""" | |
| SELECT * FROM '{path}' | |
| WHERE username ILIKE '%{keyword}%' | |
| OR first_name ILIKE '%{keyword}%' | |
| OR last_name ILIKE '%{keyword}%' | |
| OR phone ILIKE '%{keyword}%' | |
| LIMIT 50 | |
| """ | |
| results_df = con.execute(query).fetchdf() | |
| records = results_df.to_dict(orient='records') | |
| return { | |
| "developer": "Gopal Parmar", | |
| "query": keyword, | |
| "database": db, | |
| "count": len(records), | |
| "columns": get_columns(db), | |
| "results": records | |
| } | |
| except Exception as e: | |
| return {"error": str(e), "developer": "Gopal Parmar"} | |
| async def search_all_fast(q: str = Query(...)): | |
| """Search both databases in parallel (using asyncio)""" | |
| import asyncio | |
| async def search_one(db): | |
| return await search_fast(q, db) | |
| results = await asyncio.gather(search_one("p2"), search_one("p4")) | |
| return { | |
| "developer": "Gopal Parmar", | |
| "query": q, | |
| "p2": results[0], | |
| "p4": results[1] | |
| } | |
| async def root(): | |
| return { | |
| "message": "Fast Search API", | |
| "developer": "Gopal Parmar", | |
| "available": list(AVAILABLE.keys()), | |
| "note": "Exact match on numbers, limited to 50 results" | |
| } |