""" CalorieCLIP API for FitGenie backend. POST /predict { "image": "" } -> { "calories": 342 } GET /health -> { "status": "ok" } """ from __future__ import annotations import os from contextlib import asynccontextmanager from fastapi import FastAPI, Header, HTTPException from pydantic import BaseModel, Field from model_core import decode_base64_image, load_models, predict_calories API_KEY = os.getenv("CALORIE_CLIP_API_KEY", "").strip() def _require_api_key(x_api_key: str | None) -> None: if not API_KEY: return if x_api_key != API_KEY: raise HTTPException(status_code=401, detail="Invalid API key") @asynccontextmanager async def lifespan(_: FastAPI): load_models() yield app = FastAPI(title="FitGenie CalorieCLIP", version="1.1.0", lifespan=lifespan) class PredictRequest(BaseModel): image: str = Field(..., description="Base64-encoded food photo") @app.get("/") def root() -> dict[str, str]: return {"service": "FitGenie CalorieCLIP", "endpoints": "/health, /predict"} @app.get("/health") def health() -> dict[str, str]: return {"status": "ok", "model": "CalorieCLIP"} @app.post("/predict") def predict( req: PredictRequest, x_api_key: str | None = Header(default=None, alias="X-API-Key"), ) -> dict[str, int]: _require_api_key(x_api_key) try: image = decode_base64_image(req.image) except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) from exc return {"calories": predict_calories(image)}