from fastapi import FastAPI, HTTPException from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from pydantic import BaseModel import json import time from pathlib import Path from engine import BrowserFrameAnalyzer app = FastAPI() BASE_DIR = Path(__file__).resolve().parent app.mount("/static", StaticFiles(directory=str(BASE_DIR)), name="static") browser_analyzers: dict = {} SESSION_TTL_SECONDS = 30 * 60 class BrowserFrameInput(BaseModel): session_id: str image: str label: str = "Browser Camera" @app.get("/") def home(): return FileResponse(BASE_DIR / "templates" / "browser_camera.html") @app.get("/browser-camera") def browser_camera_page(): return FileResponse(BASE_DIR / "templates" / "browser_camera.html") @app.get("/alerts") def alerts(): data = [] try: with open("alerts.jsonl") as f: for line in f: data.append(json.loads(line)) except Exception: pass return data @app.post("/predict-frame") def predict_frame(payload: BrowserFrameInput): session_id = payload.session_id.strip() if not session_id: raise HTTPException(status_code=400, detail="session_id is required") now = time.time() expired = [ key for key, item in browser_analyzers.items() if now - item["last_seen"] > SESSION_TTL_SECONDS ] for key in expired: browser_analyzers.pop(key, None) item = browser_analyzers.get(session_id) if item is None: item = { "analyzer": BrowserFrameAnalyzer(payload.label.strip() or "Browser Camera"), "last_seen": now, } browser_analyzers[session_id] = item item["last_seen"] = now try: result = item["analyzer"].analyze_data_url(payload.image) except Exception as exc: raise HTTPException(status_code=400, detail=str(exc)) from exc return result