from fastapi import FastAPI, File, UploadFile, HTTPException from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse, JSONResponse from fastapi.middleware.cors import CORSMiddleware import uvicorn from datetime import datetime from pathlib import Path from backend.detectors.image_detector import analyze_image_models from backend.detectors.metadata_detector import analyze_metadata from backend.detectors.scoring_engine import calculate_final_score from backend.detectors.style_detector import analyze_visual_style from PIL import Image import io app = FastAPI(title="ImgAuth AI API") app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]) BASE_DIR = Path(__file__).parent FRONTEND = BASE_DIR.parent / "frontend" PUBLIC = BASE_DIR.parent / "public" app.mount("/static", StaticFiles(directory=str(FRONTEND / "static")), name="static") app.mount("/public", StaticFiles(directory=str(PUBLIC)), name="public") @app.on_event("startup") async def startup(): print("ImgAuth AI started -> http://localhost:5000") try: print("[ImgAuth] Preloading models on startup...") from backend.detectors.image_detector import load_models load_models() print("[ImgAuth] Models preloaded successfully.") except Exception as e: print(f"[ImgAuth] Warning: failed to preload models: {e}") @app.get("/") async def root(): return FileResponse(str(FRONTEND / "index.html")) @app.post("/api/detect") async def detect(file: UploadFile = File(...)): if not file.content_type.startswith("image/"): raise HTTPException(400, "Only image files are accepted.") contents = await file.read() if len(contents) > 10 * 1024 * 1024: raise HTTPException(400, "File too large. Max 10 MB.") fn = {} md = analyze_metadata(contents) ml = analyze_image_models(contents) try: img_full = Image.open(io.BytesIO(contents)).convert("RGB") st = analyze_visual_style(img_full) except Exception as e: st = {"ai_points": 0, "real_points": 0, "signals": [f"[ERROR] Style loading: {str(e)[:50]}"]} ml["style"] = st if "signals" in ml and "signals" in st: ml["signals"].extend(st["signals"]) res = calculate_final_score(fn, md, ml) return JSONResponse({ "filename": file.filename, "verdict": res["verdict"], "ai_score": res["ai_score"], "real_score": res["real_score"], "confidence": res["confidence"], "color": res["color"], "layers": {"filename": fn, "metadata": md, "models": ml}, "breakdown": res["breakdown"], "summary": res["summary"], "timestamp": datetime.now().isoformat() })