Spaces:
Running
Running
Real Google Auth Upgrade: Integrated Google Identity Services (GIS). Button now triggers real Google Popup if GOOGLE_CLIENT_ID is set in secrets.
69171a1 | import io | |
| from fastapi import FastAPI, File, UploadFile, Form, Request | |
| from fastapi.responses import JSONResponse | |
| from fastapi.templating import Jinja2Templates | |
| from fastapi.staticfiles import StaticFiles | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from PIL import Image | |
| from ai_router import route_model | |
| from utils.security import check_rate_limit, validate_image_size | |
| from config import DEVICE, ENABLE_EXTERNAL_AI | |
| from database import init_db, login_user, signup_user, log_request_db, check_gemini_limit, increment_gemini_limit, get_user_logs | |
| from fastapi import HTTPException | |
| # ================= CREATE APP FIRST ================= | |
| app = FastAPI(title="GenAI VQA System") | |
| async def startup_event(): | |
| init_db() | |
| # ================= CORS ================= | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # ================= STATIC + TEMPLATE ================= | |
| app.mount("/static", StaticFiles(directory="static"), name="static") | |
| templates = Jinja2Templates(directory="templates") | |
| # ================= HOME ================= | |
| async def home(request: Request): | |
| import os | |
| cid = os.getenv("GOOGLE_CLIENT_ID", "") | |
| return templates.TemplateResponse("index.html", { | |
| "request": request, | |
| "google_client_id": cid | |
| }) | |
| # ================= API ================= | |
| async def handle_login(request: Request): | |
| data = await request.json() | |
| username = data.get("username") | |
| password = data.get("password") | |
| if login_user(username, password): | |
| return {"status": "success", "user": username} | |
| return JSONResponse(status_code=401, content={"status": "error", "message": "Invalid password or user does not exist."}) | |
| async def handle_signup(request: Request): | |
| data = await request.json() | |
| username = data.get("username") | |
| password = data.get("password") | |
| if not username or not password: | |
| return JSONResponse(status_code=400, content={"status": "error", "message": "Username and password required."}) | |
| if signup_user(username, password): | |
| return {"status": "success", "user": username} | |
| return JSONResponse(status_code=400, content={"status": "error", "message": "Username already taken."}) | |
| async def handle_google_login(request: Request): | |
| data = await request.json() | |
| email = data.get("email") | |
| if not email or "@" not in email: | |
| return JSONResponse(status_code=400, content={"status": "error", "message": "Invalid Google Email."}) | |
| username = email.split("@")[0].lower() | |
| from database import login_or_create_google_user | |
| login_or_create_google_user(username) | |
| return {"status": "success", "user": username} | |
| async def get_logs_endpoint(user: str): | |
| logs = get_user_logs(user) | |
| return {"logs": logs} | |
| async def ask_question( | |
| file: UploadFile = File(...), | |
| question: str = Form(...), | |
| model_choice: str = Form("reasoning"), | |
| user: str = Form("guest"), | |
| lang: str = Form("en") | |
| ): | |
| check_rate_limit(user) | |
| if model_choice == "gemini": | |
| if not check_gemini_limit(user): | |
| return JSONResponse({ | |
| "device": "Error", | |
| "model_used": "gemini", | |
| "caption": "Quota Exceeded", | |
| "answer": "You have reached your limit of 10 Gemini requests per day.", | |
| "explanation": "To prevent abusive cost spikes, users are limited to 10 Gemini requests per day. The Admin has unlimited access.", | |
| "external_enabled": True | |
| }) | |
| image_bytes = await file.read() | |
| validate_image_size(len(image_bytes)) | |
| try: | |
| image = Image.open(io.BytesIO(image_bytes)).convert("RGB") | |
| except Exception as e: | |
| return JSONResponse({ | |
| "device": "Error", | |
| "model_used": model_choice, | |
| "caption": "Image Load Error", | |
| "answer": f"The supplied image was empty or an invalid format. Size received: {len(image_bytes)} bytes.", | |
| "explanation": str(e), | |
| "external_enabled": False | |
| }) | |
| caption, answer, explanation = route_model( | |
| model_choice, | |
| image, | |
| question, | |
| lang | |
| ) | |
| log_request_db(user, model_choice, question) | |
| if model_choice == "gemini": | |
| increment_gemini_limit(user) | |
| return JSONResponse({ | |
| "device": DEVICE, | |
| "model_used": model_choice, | |
| "caption": caption, | |
| "answer": answer, | |
| "explanation": explanation, | |
| "external_enabled": ENABLE_EXTERNAL_AI | |
| }) |