Spaces:
Running
Running
Download main.py from ItsXyron/hyperlookup-api: direct link, hf CLI and curl.
- Browser
- Download file 40.8 kB
-
https://huggingface.co/spaces/ItsXyron/hyperlookup-api/resolve/main/main.py
- Command line
-
hf download hf://spaces/ItsXyron/hyperlookup-api/main.py
-
curl -L -o main.py https://huggingface.co/spaces/ItsXyron/hyperlookup-api/resolve/main/main.py
40.8 kB
| import time | |
| import os | |
| import re | |
| import logging | |
| from contextlib import asynccontextmanager | |
| from typing import Optional, Dict, Any, List | |
| logger = logging.getLogger("LookupApp") | |
| from fastapi import FastAPI, Query, HTTPException, Request, Header, Depends | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.middleware.gzip import GZipMiddleware | |
| from fastapi.responses import HTMLResponse, FileResponse, JSONResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from pydantic import BaseModel, Field | |
| from engine import LookupEngine | |
| from external_services import ServiceGateway | |
| from auth import KeyManager, ADMIN_MASTER_KEY, INTERNAL_BOT_KEY | |
| start_time = time.time() | |
| _engine: Optional[LookupEngine] = None | |
| def get_engine() -> LookupEngine: | |
| global _engine | |
| if _engine is None: | |
| _engine = LookupEngine() | |
| _engine.warm_up() | |
| return _engine | |
| async def lifespan(app: FastAPI): | |
| get_engine() | |
| # Auto-launch Telegram Bot if TELEGRAM_BOT_TOKEN is provided in Space Secrets | |
| bot_token = os.environ.get("TELEGRAM_BOT_TOKEN", "").strip() | |
| if bot_token: | |
| import threading | |
| from bot import create_bot | |
| def _bot_worker(): | |
| try: | |
| b = create_bot(bot_token) | |
| b_info = b.get_me() | |
| print(f"[+] Telegram Bot Daemon online as @{b_info.username}", flush=True) | |
| b.infinity_polling(timeout=20, long_polling_timeout=15) | |
| except Exception as e: | |
| print(f"[!] Telegram Bot Daemon error: {e}", flush=True) | |
| t = threading.Thread(target=_bot_worker, daemon=True) | |
| t.start() | |
| print("[+] Background Telegram Bot thread dispatched.", flush=True) | |
| yield | |
| app = FastAPI( | |
| title="HyperLookup API & SaaS Engine", | |
| description="Enterprise-grade ultra-fast lookup API for 2.5B+ Indian Records (Phone & Aadhaar) and 65M+ Telegram Master Database with API Key Auth & Quota Controls.", | |
| version="2.2.0", | |
| lifespan=lifespan, | |
| docs_url="/docs", | |
| redoc_url="/redoc" | |
| ) | |
| # Enable GZip compression | |
| app.add_middleware(GZipMiddleware, minimum_size=1000) | |
| # Enable CORS for all frontends, bots, and external apps | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Mount static directory if exists | |
| static_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "static") | |
| if os.path.exists(static_dir): | |
| app.mount("/static", StaticFiles(directory=static_dir), name="static") | |
| # --------------------------------------------------------- | |
| # Request Models | |
| # --------------------------------------------------------- | |
| class CreateKeyRequest(BaseModel): | |
| name: str = Field(..., example="Client Alpha") | |
| days_valid: Optional[int] = Field(30, description="Validity period in days. Pass 0 or null for lifetime.") | |
| rate_limit_per_min: Optional[int] = Field(60, description="Max allowed requests per minute.") | |
| total_credits: Optional[int] = Field(1000, description="Total number of search queries allowed. Pass -1 for unlimited.") | |
| # --------------------------------------------------------- | |
| # Authentication Dependency | |
| # --------------------------------------------------------- | |
| def get_client_ip(request: Request) -> str: | |
| """Extracts client IP considering Cloudflare, proxies, and standard headers.""" | |
| cf_ip = request.headers.get("cf-connecting-ip") | |
| if cf_ip: | |
| return cf_ip.strip() | |
| forwarded = request.headers.get("x-forwarded-for") | |
| if forwarded: | |
| return forwarded.split(",")[0].strip() | |
| real_ip = request.headers.get("x-real-ip") | |
| if real_ip: | |
| return real_ip.strip() | |
| return request.client.host if request.client else "127.0.0.1" | |
| def verify_api_key( | |
| request: Request, | |
| api_key_query: Optional[str] = Query(None, alias="api_key"), | |
| key_query: Optional[str] = Query(None, alias="key"), | |
| x_api_key: Optional[str] = Header(None, alias="X-API-Key"), | |
| authorization: Optional[str] = Header(None) | |
| ) -> Dict[str, Any]: | |
| """Extracts and verifies API key or applies IP-based daily free search with anti-DDoS.""" | |
| token = None | |
| if x_api_key: | |
| token = x_api_key | |
| elif authorization and authorization.lower().startswith("bearer "): | |
| token = authorization.split(" ", 1)[1] | |
| elif api_key_query: | |
| token = api_key_query | |
| elif key_query: | |
| token = key_query | |
| client_ip = get_client_ip(request) | |
| is_valid, code, msg, meta = KeyManager.validate_request(token, client_ip) | |
| if not is_valid: | |
| raise HTTPException(status_code=code, detail=msg) | |
| return meta | |
| def verify_admin_key( | |
| x_admin_key: Optional[str] = Header(None, alias="X-Admin-Key"), | |
| admin_key_query: Optional[str] = Query(None, alias="admin_key") | |
| ): | |
| """Requires the master admin key to access administrative operations.""" | |
| key = x_admin_key or admin_key_query | |
| if key != ADMIN_MASTER_KEY: | |
| raise HTTPException(status_code=401, detail="Unauthorized. Master Admin Key required.") | |
| return key | |
| # --------------------------------------------------------- | |
| # Public Endpoints | |
| # --------------------------------------------------------- | |
| async def serve_home(): | |
| index_file = os.path.join(static_dir, "index.html") | |
| if os.path.exists(index_file): | |
| return FileResponse(index_file) | |
| return HTMLResponse("<h1>HyperLookup Engine API is Online</h1><p>API documentation available at <a href='/docs'>/docs</a>.</p>") | |
| async def health_check(): | |
| """Liveness probe for monitoring services.""" | |
| return {"status": "ok", "timestamp": time.time()} | |
| async def check_public_quota(request: Request): | |
| """Returns current daily free search quota for the caller IP.""" | |
| client_ip = get_client_ip(request) | |
| return KeyManager.get_public_quota(client_ip) | |
| async def get_system_stats(): | |
| """Returns engine health, cache status, and database metrics.""" | |
| eng = get_engine() | |
| uptime_sec = round(time.time() - start_time, 2) | |
| return { | |
| "status": "healthy", | |
| "uptime_seconds": uptime_sec, | |
| "engine_warmed": eng.is_warmed, | |
| "cache_entries": len(eng.cache), | |
| "database_info": { | |
| "total_records_indexed": "478,800,000+ Master DB Records", | |
| "active_services": 11, | |
| "engine": "DuckDB Vectorized Core", | |
| "cluster_state": "Operational" | |
| } | |
| } | |
| # --------------------------------------------------------- | |
| # Telegram Search Endpoints (Isolated & Ultra-Fast) | |
| # --------------------------------------------------------- | |
| async def search_telegram( | |
| user_id: Optional[str] = Query(None, description="Telegram User ID (e.g. 74252719)"), | |
| id: Optional[str] = Query(None, description="Alias for user_id"), | |
| q: Optional[str] = Query(None, description="Alias for user_id"), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| target = user_id or id or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required query parameter: 'user_id'") | |
| res = get_engine().query_by_telegram(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_telegram_path(user_id: str, auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| res = get_engine().query_by_telegram(user_id) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| # --------------------------------------------------------- | |
| # Individual Master Database Search Endpoints | |
| # --------------------------------------------------------- | |
| async def lookup_truecaller(phone_number: str, auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| """Search Truecaller 285M Master Database by 10-digit mobile.""" | |
| res = get_engine().query_truecaller(phone_number) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_airtel(phone_number: str, auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| """Search Airtel India 73M Master Database by 10-digit mobile.""" | |
| res = get_engine().query_airtel(phone_number) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_hdfc(phone_number: str, auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| """Search HDFC Bank Master Database (CIBIL, Highmark, Loans) by 10-digit mobile.""" | |
| res = get_engine().query_hdfc(phone_number) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_bsnl(phone_number: str, auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| """Search BSNL 19M Master Database by 10-digit mobile.""" | |
| res = get_engine().query_bsnl(phone_number) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_paytm(phone_number: str, auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| """Search Paytm India Master Database by 10-digit mobile.""" | |
| res = get_engine().query_paytm(phone_number) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_flipkart(phone_number: str, auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| """Search Flipkart India Master Database by 10-digit mobile.""" | |
| res = get_engine().query_flipkart(phone_number) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_instagram(query: str, auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| """Search Instagram 16.7M Master Database by Phone or Username.""" | |
| res = get_engine().query_instagram(query) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_twitter(query: str, auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| """Search Twitter / X 5.48M Master Database by User ID or Username.""" | |
| res = get_engine().query_twitter(query) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_sbi( | |
| query: Optional[str] = None, | |
| q: Optional[str] = Query(None, description="Search query (phone, aadhaar, pan, name, email)"), | |
| phone: Optional[str] = Query(None, description="10-digit mobile number"), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """Search SBI POSP & Indian Banking Master Database by Phone, Aadhaar, PAN, Name, or Email.""" | |
| target = query or q or phone | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide 'query', 'q', or 'phone'.") | |
| res = get_engine().query_sbi(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_ind( | |
| query: Optional[str] = None, | |
| q: Optional[str] = Query(None, description="Search query (phone, email, aadhaar, pan, name)"), | |
| phone: Optional[str] = Query(None, description="10-digit mobile number"), | |
| email: Optional[str] = Query(None, description="Email address"), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """Search IND Education, Admissions & KYC Master Database by Phone, Email, Aadhaar, PAN, or Name.""" | |
| target = query or q or phone or email | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide 'query', 'q', 'phone', or 'email'.") | |
| res = get_engine().query_ind(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_upi( | |
| query: Optional[str] = None, | |
| q: Optional[str] = Query(None, description="UPI ID / VPA (e.g. 9826287975@paytm) or 10-digit mobile number"), | |
| vpa: Optional[str] = Query(None, description="UPI VPA address"), | |
| phone: Optional[str] = Query(None, description="10-digit Indian Mobile"), | |
| mode: Optional[str] = Query("full", description="Lookup mode: 'full' (360° KYC Dossier), 'upi_to_num' (VPA to Phone), or 'num_to_upi' (Phone to active UPI IDs)"), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """ | |
| UPI & VPA 360° OSINT & KYC Resolver: | |
| - Mode 'full': Resolves UPI ID / Mobile to complete 360° cross-database KYC profile, | |
| active UPI handles, bank linkages, Aadhaar/PAN, and full address. | |
| - Mode 'upi_to_num': Extracts registered phone number, PSP application, acquiring bank & IFSC. | |
| - Mode 'num_to_upi': Generates and scores active UPI IDs across PhonePe, Google Pay, Paytm, BHIM, etc. | |
| """ | |
| target = query or q or vpa or phone | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide 'query', 'q', 'vpa', or 'phone'.") | |
| res = get_engine().query_upi(target, mode=mode) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| # --------------------------------------------------------- | |
| # Banking, Business, Vehicle & Network Intelligence APIs | |
| # --------------------------------------------------------- | |
| async def lookup_ifsc(code: Optional[str] = None, ifsc: Optional[str] = Query(None), q: Optional[str] = Query(None), auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| target = code or ifsc or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide 'code', 'ifsc', or 'q'.") | |
| res = ServiceGateway.get_ifsc(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_pincode(pin: Optional[str] = None, pincode: Optional[str] = Query(None), q: Optional[str] = Query(None), auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| target = pin or pincode or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide 'pin', 'pincode', or 'q'.") | |
| res = ServiceGateway.get_pincode(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_ip(ip_addr: Optional[str] = None, ip: Optional[str] = Query(None), q: Optional[str] = Query(None), auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| target = ip_addr or ip or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide 'ip_addr', 'ip', or 'q'.") | |
| res = ServiceGateway.get_ip(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_vehicle(vehicle_no: Optional[str] = None, vehicle: Optional[str] = Query(None), rc: Optional[str] = Query(None), owner: Optional[str] = Query(None), q: Optional[str] = Query(None), auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| target = vehicle_no or vehicle or rc or owner or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide vehicle registration number.") | |
| res = ServiceGateway.get_vehicle_rc(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_challan(vehicle_no: Optional[str] = None, vehicle: Optional[str] = Query(None), q: Optional[str] = Query(None), auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| target = vehicle_no or vehicle or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide vehicle registration number.") | |
| res = ServiceGateway.get_vehicle_challan(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_pan(pan_no: Optional[str] = None, pan: Optional[str] = Query(None), q: Optional[str] = Query(None), auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| target = pan_no or pan or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide 'pan_no', 'pan', or 'q'.") | |
| res = ServiceGateway.get_pan_details(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_gst(gstin: Optional[str] = None, gst: Optional[str] = Query(None), q: Optional[str] = Query(None), auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| target = gstin or gst or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide 'gstin', 'gst', or 'q'.") | |
| res = ServiceGateway.get_gst_details(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_pantogst(pan_no: Optional[str] = None, pan: Optional[str] = Query(None), q: Optional[str] = Query(None), auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| target = pan_no or pan or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide 'pan_no', 'pan', or 'q'.") | |
| res = ServiceGateway.get_pan_to_gst(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_veh_to_num(vehicle_no: Optional[str] = None, vehicle: Optional[str] = Query(None), q: Optional[str] = Query(None), auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| target = vehicle_no or vehicle or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide vehicle registration number.") | |
| res = ServiceGateway.get_veh_to_num(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_ration(query: Optional[str] = None, num: Optional[str] = Query(None), q: Optional[str] = Query(None), auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| target = query or num or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide 12-digit Aadhaar UID or Ration Card number.") | |
| res = ServiceGateway.get_ration(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_bgmi(uid: Optional[str] = None, q: Optional[str] = Query(None), auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| target = uid or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide BGMI numeric UID.") | |
| res = ServiceGateway.get_bgmi(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_github(query: Optional[str] = None, q: Optional[str] = Query(None), repo: Optional[str] = Query(None), auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| target = query or repo or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide GitHub username or repo.") | |
| res = ServiceGateway.get_github(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_youtube(query: Optional[str] = None, q: Optional[str] = Query(None), video: Optional[str] = Query(None), auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| target = query or video or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide YouTube URL or Video ID.") | |
| res = ServiceGateway.get_youtube_info(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_lpg_gas( | |
| request: Request, | |
| query: Optional[str] = None, | |
| num: Optional[str] = Query(None, description="10-digit mobile number or 17-digit LPG ID"), | |
| phone: Optional[str] = Query(None), | |
| lpg_id: Optional[str] = Query(None), | |
| consumer_no: Optional[str] = Query(None), | |
| provider: Optional[str] = Query(None, description="Gas provider: 'indane', 'bharat', or 'hp'"), | |
| q: Optional[str] = Query(None), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """ | |
| Direct LPG Gas Consumer Intelligence: | |
| Resolves 10-digit mobile number or 17-digit LPG ID across all 3 Indian OMCs: | |
| Indane Gas (IOCL), Bharat Gas (BPCL), and HP Gas (HPCL). | |
| """ | |
| target = query or num or phone or lpg_id or consumer_no or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide 10-digit mobile number or 17-digit LPG ID.") | |
| auto_prov = provider if (provider and isinstance(provider, str)) else None | |
| if not auto_prov: | |
| path_lower = request.url.path.lower() | |
| if "bharat" in path_lower: | |
| auto_prov = "bharat" | |
| elif "hp" in path_lower: | |
| auto_prov = "hp" | |
| elif "indane" in path_lower: | |
| auto_prov = "indane" | |
| clean_digits = re.sub(r'\D', '', str(target)).strip() | |
| user_kyc = None | |
| if len(clean_digits) == 10: | |
| try: | |
| eng = get_engine() | |
| phone_res = eng.query_by_phone(clean_digits) | |
| if isinstance(phone_res, dict): | |
| records = phone_res.get("records", []) | |
| if records and isinstance(records, list) and len(records) > 0: | |
| rec = records[0] | |
| user_kyc = { | |
| "name": rec.get("name") or rec.get("fullName"), | |
| "fathersName": rec.get("fathersName") or rec.get("father_name"), | |
| "phoneNumber": rec.get("phoneNumber") or clean_digits, | |
| "aadharNumber": rec.get("aadharNumber") or rec.get("aadhaar"), | |
| "address": rec.get("address"), | |
| "pincode": rec.get("pincode") or rec.get("pinCode"), | |
| "district": rec.get("district"), | |
| "state": rec.get("state") | |
| } | |
| if not user_kyc or not user_kyc.get("name"): | |
| comb_res = eng.query_combined(clean_digits) | |
| if isinstance(comb_res, dict): | |
| summary = comb_res.get("consolidated_summary", {}) | |
| p_name = summary.get("primary_name") | |
| if not p_name and summary.get("names_found"): | |
| p_name = summary["names_found"][0] | |
| locs = summary.get("locations_identified", []) | |
| loc = locs[0] if locs else "" | |
| if p_name: | |
| user_kyc = { | |
| "name": p_name, | |
| "fathersName": None, | |
| "phoneNumber": clean_digits, | |
| "aadharNumber": None, | |
| "address": loc, | |
| "pincode": None | |
| } | |
| except Exception as e: | |
| logger.error(f"Gas consumer KYC resolution: {e}") | |
| res = ServiceGateway.get_lpg(target, provider=auto_prov, user_kyc=user_kyc) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_by_phone(phone_number: str, auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| """Search Telecom 2.5B Database by phone number.""" | |
| res = get_engine().query_by_phone(phone_number) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_by_aadhar(aadhar_number: str, auth_meta: Dict[str, Any] = Depends(verify_api_key)): | |
| """Search Aadhaar Database by 12-digit number.""" | |
| res = get_engine().query_by_aadhar(aadhar_number) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_aadhar_family( | |
| query: Optional[str] = None, | |
| q: Optional[str] = Query(None, description="Aadhaar UID or Phone Number"), | |
| aadhar: Optional[str] = Query(None, description="12-digit Aadhaar UID"), | |
| phone: Optional[str] = Query(None, description="10-digit Phone Number"), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """ | |
| Search Aadhaar Family & Household Linkage Database by 12-digit Aadhaar UID or 10-digit Mobile. | |
| Returns structured family hierarchy, co-residents, and shared household connections. | |
| """ | |
| target = query or q or aadhar or phone | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing required parameter: provide 'query', 'q', 'aadhar', or 'phone'.") | |
| res = get_engine().query_by_aadhar_family(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| # --------------------------------------------------------- | |
| # Unified Combined Search Endpoints (All Databases in Parallel) | |
| # --------------------------------------------------------- | |
| async def combined_lookup( | |
| phone_number: Optional[str] = None, | |
| phone: Optional[str] = Query(None, description="10-digit Indian Mobile"), | |
| q: Optional[str] = Query(None, description="Search query"), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """ | |
| Unified Combined Search: Queries Truecaller, Airtel, HDFC, BSNL, | |
| Paytm, Flipkart, Instagram, and Telecom DB in parallel and returns | |
| both consolidated profile intelligence and individual database records. | |
| """ | |
| target = phone_number or phone or q | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing parameter: provide 'phone_number', 'phone', or 'q'.") | |
| res = get_engine().query_combined(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| # --------------------------------------------------------- | |
| # 🔥 360° Deep Intelligence Dossier Endpoints | |
| # --------------------------------------------------------- | |
| async def lookup_deep_dossier( | |
| query: Optional[str] = None, | |
| q: Optional[str] = Query(None, description="Any Indian identifier: Phone, Aadhaar, PAN, UPI, Vehicle, Telegram ID, Email, Name"), | |
| target_param: Optional[str] = Query(None, alias="target"), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """ | |
| 🔥 360° Deep Master Intelligence Dossier: | |
| Cross-queries all 16 Indian Master Databases in parallel and synthesizes | |
| a comprehensive, cross-correlated intelligence profile with KYC consensus score. | |
| """ | |
| target = query or q or target_param | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing parameter: provide 'query', 'q', or 'target'.") | |
| res = get_engine().query_deep_dossier(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_muthoot( | |
| query: Optional[str] = None, | |
| q: Optional[str] = Query(None), | |
| phone: Optional[str] = Query(None), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """Search Muthoot Finance Gold Loans & Banking KYC Master Database.""" | |
| target = query or q or phone | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing parameter: provide 'query', 'q', or 'phone'.") | |
| res = get_engine().query_muthoot(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_olx( | |
| query: Optional[str] = None, | |
| q: Optional[str] = Query(None), | |
| phone: Optional[str] = Query(None), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """Search OLX India Auto Dealers & Classifieds Merchants Master Database.""" | |
| target = query or q or phone | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing parameter: provide 'query', 'q', or 'phone'.") | |
| res = get_engine().query_olx(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_icici( | |
| query: Optional[str] = None, | |
| q: Optional[str] = Query(None), | |
| model: Optional[str] = Query(None), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """Search ICICI Lombard Private Car & Vehicle Insurance Master Database.""" | |
| target = query or q or model | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing parameter: provide 'query', 'q', or 'model'.") | |
| res = get_engine().query_icici(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_xyron_master( | |
| query: Optional[str] = None, | |
| q: Optional[str] = Query(None), | |
| phone: Optional[str] = Query(None), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """Search Unified Xyron Intel Master (Combined Banking, Insurance, Muthoot, OLX).""" | |
| target = query or q or phone | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing parameter: provide 'query', 'q', or 'phone'.") | |
| res = get_engine().query_xyron_master(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_sbi( | |
| query: Optional[str] = None, | |
| q: Optional[str] = Query(None), | |
| phone: Optional[str] = Query(None), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """Search SBI POSP & Indian Banking KYC Master Database.""" | |
| target = query or q or phone | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing parameter: provide 'query', 'q', or 'phone'.") | |
| res = get_engine().query_sbi(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def lookup_ind( | |
| query: Optional[str] = None, | |
| q: Optional[str] = Query(None), | |
| phone: Optional[str] = Query(None), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """Search IND Education Admissions & Student KYC Master Database.""" | |
| target = query or q or phone | |
| if not target: | |
| raise HTTPException(status_code=400, detail="Missing parameter: provide 'query', 'q', or 'phone'.") | |
| res = get_engine().query_ind(target) | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def unified_lookup( | |
| q: Optional[str] = Query(None, description="Search query (phone, aadhar, telegram user_id, username, deep)"), | |
| phone: Optional[str] = Query(None, description="Direct 10-digit phone number"), | |
| aadhar: Optional[str] = Query(None, description="Direct 12-digit aadhar number"), | |
| family: Optional[str] = Query(None, description="Direct Aadhaar family query"), | |
| user_id: Optional[str] = Query(None, description="Direct Telegram User ID"), | |
| sbi: Optional[str] = Query(None, description="Direct SBI POSP query"), | |
| ind: Optional[str] = Query(None, description="Direct IND Admissions & KYC query"), | |
| upi: Optional[str] = Query(None, description="Direct UPI ID or VPA query"), | |
| gas: Optional[str] = Query(None, description="Direct LPG Gas cylinder or consumer query"), | |
| deep: Optional[str] = Query(None, description="Direct 360° Deep Dossier query"), | |
| mode: Optional[str] = Query(None, description="Search mode: 'deep' or 'fast'"), | |
| auth_meta: Dict[str, Any] = Depends(verify_api_key) | |
| ): | |
| """ | |
| Smart Unified Lookup: Automatically detects input type. | |
| - Deep mode: Runs complete 360° Deep Intelligence Dossier across all 16 Master DBs. | |
| - 10-digit phone: Runs full parallel combined search across ALL databases. | |
| - 12-digit: Searches Aadhaar database. | |
| - 16/17/18-digit: Searches LPG Gas database. | |
| - Telegram ID: Searches Telegram 65M Master DB. | |
| - UPI ID / VPA: Resolves phone, PSP app, bank, and 360° KYC dossier. | |
| - Text/Username: Searches Instagram/Twitter. | |
| - Family: Discovers family linkages across Aadhaar & Telecom. | |
| - Gas: Resolves complete LPG cylinder details across Indane, Bharat Gas, HP Gas. | |
| - SBI: Searches SBI POSP & Indian Banking database. | |
| - IND: Searches IND Education, Admissions & KYC database. | |
| """ | |
| eng = get_engine() | |
| if deep or mode == "deep": | |
| target = deep or q or phone or aadhar or upi or user_id | |
| res = eng.query_deep_dossier(target) | |
| elif gas: | |
| res = ServiceGateway.get_lpg(gas) | |
| elif upi: | |
| res = eng.query_upi_full_info(upi) | |
| elif ind: | |
| res = eng.query_ind(ind) | |
| elif sbi: | |
| res = eng.query_sbi(sbi) | |
| elif family: | |
| res = eng.query_by_aadhar_family(family) | |
| elif user_id: | |
| res = eng.query_by_telegram(user_id) | |
| elif aadhar: | |
| res = eng.query_by_aadhar(aadhar) | |
| elif phone: | |
| res = eng.query_combined(phone) | |
| elif q: | |
| q_str = str(q).strip() | |
| if "@" in q_str: | |
| res = eng.query_upi_full_info(q_str) | |
| else: | |
| clean = "".join(c for c in q_str if c.isdigit()) | |
| if len(clean) in (16, 17, 18): | |
| res = ServiceGateway.get_lpg(clean) | |
| elif len(clean) == 12: | |
| res = eng.query_by_aadhar(clean) | |
| elif len(clean) == 10: | |
| res = eng.query_combined(clean) | |
| elif re.match(r"^[A-Za-z]{5}[0-9]{4}[A-Za-z]$", q_str): | |
| res = ServiceGateway.get_pan_details(q_str.upper()) | |
| elif 5 <= len(clean) <= 15: | |
| tg_res = eng.query_by_telegram(clean) | |
| if tg_res.get("status") == "success": | |
| res = tg_res | |
| else: | |
| res = eng.query_combined(clean) | |
| else: | |
| res = eng.query_instagram(q_str) | |
| else: | |
| raise HTTPException(status_code=400, detail="Missing parameter: provide 'q', 'phone', 'aadhar', 'upi', or 'user_id'.") | |
| if isinstance(res, dict): | |
| res["tier"] = auth_meta.get("tier", "free") | |
| res["remaining_credits"] = auth_meta.get("remaining", -1) | |
| return res | |
| async def check_key_status(api_key: str = Query(..., description="API Key to inspect")): | |
| status = KeyManager.get_key_status(api_key) | |
| if not status: | |
| raise HTTPException(status_code=404, detail="API Key not found.") | |
| return status | |
| # --------------------------------------------------------- | |
| # Admin Key Management Endpoints (Master Admin Only) | |
| # --------------------------------------------------------- | |
| async def create_api_key(req: CreateKeyRequest, _admin: str = Depends(verify_admin_key)): | |
| """Generate a new client API key with custom expiry, credits, and rate limit.""" | |
| new_key = KeyManager.create_key( | |
| name=req.name, | |
| days_valid=req.days_valid, | |
| rate_limit_per_min=req.rate_limit_per_min or 60, | |
| total_credits=req.total_credits if req.total_credits is not None else 1000 | |
| ) | |
| return { | |
| "success": True, | |
| "message": "API key generated successfully.", | |
| "key_data": new_key | |
| } | |
| async def list_all_keys(_admin: str = Depends(verify_admin_key)): | |
| """List all issued API keys with remaining credits and usage stats.""" | |
| return { | |
| "success": True, | |
| "keys": KeyManager.list_keys() | |
| } | |
| async def delete_api_key(target_key: str, _admin: str = Depends(verify_admin_key)): | |
| """Permanently delete or revoke an API key.""" | |
| deleted = KeyManager.delete_key(target_key) | |
| if not deleted: | |
| raise HTTPException(status_code=404, detail="Key not found.") | |
| return {"success": True, "message": "API key deleted successfully."} | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) | |