Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
57 lines
1.8 KiB
Python
57 lines
1.8 KiB
Python
from fastapi import FastAPI, File, HTTPException, UploadFile
|
|
|
|
from model import ImageDecodeError, LABELS, SERVICE_NAME, SERVICE_VERSION, model_service
|
|
from schemas import HealthResponse, MetadataResponse, PredictionResponse
|
|
|
|
|
|
app = FastAPI(title="ZeaVis ML Service", version=SERVICE_VERSION)
|
|
|
|
|
|
@app.on_event("startup")
|
|
def load_model() -> None:
|
|
model_service.load()
|
|
|
|
|
|
@app.get("/health", response_model=HealthResponse)
|
|
def health() -> HealthResponse:
|
|
return HealthResponse(status="ok", model_loaded=model_service.model_loaded)
|
|
|
|
|
|
@app.get("/metadata", response_model=MetadataResponse)
|
|
def metadata() -> MetadataResponse:
|
|
return MetadataResponse(
|
|
service_name=SERVICE_NAME,
|
|
service_version=SERVICE_VERSION,
|
|
model_path=str(model_service.model_path),
|
|
model_loaded=model_service.model_loaded,
|
|
input_size=model_service.input_size,
|
|
labels=LABELS,
|
|
)
|
|
|
|
|
|
@app.post("/predict", response_model=PredictionResponse)
|
|
async def predict(file: UploadFile = File(...)) -> PredictionResponse:
|
|
if file.content_type is None or not file.content_type.startswith("image/"):
|
|
raise HTTPException(status_code=400, detail="Uploaded file must be an image")
|
|
|
|
if not model_service.model_loaded:
|
|
raise HTTPException(status_code=503, detail="Model is not loaded")
|
|
|
|
image_bytes = await file.read()
|
|
|
|
try:
|
|
label, confidence, probabilities = model_service.predict(image_bytes)
|
|
except ImageDecodeError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
except Exception as exc:
|
|
import logging
|
|
|
|
logging.exception("Prediction failed")
|
|
raise HTTPException(status_code=500, detail="Prediction failed") from exc
|
|
|
|
return PredictionResponse(
|
|
label=label,
|
|
confidence=confidence,
|
|
probabilities=probabilities,
|
|
)
|