diff --git a/src/Components/API/app/routers/species_predictor.py b/src/Components/API/app/routers/species_predictor.py index 81e8373ce..ef305408c 100644 --- a/src/Components/API/app/routers/species_predictor.py +++ b/src/Components/API/app/routers/species_predictor.py @@ -2,18 +2,12 @@ from fastapi.responses import JSONResponse from typing import Optional from app.database import Predictions +from app.services.model_adapter import MultiModalPredictionError, predict_with_failure_detection import datetime import re router = APIRouter() -# Placeholder prediction -def predict_species(audio_file: UploadFile): - return { - "species": "Crimson Rosella", - "confidence": 0.92 - } - @router.post("/predict") async def predict( audio: UploadFile = File(...), @@ -31,7 +25,10 @@ async def predict( else: raise HTTPException(status_code=400, detail="Invalid upload_id format") - prediction = predict_species(audio) + try: + prediction = predict_with_failure_detection(audio) + except MultiModalPredictionError as e: + raise HTTPException(status_code=502, detail=str(e)) # Persist prediction result try: diff --git a/src/Components/API/app/services/model_adapter.py b/src/Components/API/app/services/model_adapter.py new file mode 100644 index 000000000..2473c7f61 --- /dev/null +++ b/src/Components/API/app/services/model_adapter.py @@ -0,0 +1,44 @@ +from numbers import Number +from typing import Any, Dict + + +class MultiModalPredictionError(Exception): + """Raised when the multi-modal prediction path fails or returns invalid data.""" + + +def predict_multimodal(audio_file: Any) -> Dict[str, Any]: + # Placeholder until the real multi-modal engine is wired into the adapter. + return { + "species": "Crimson Rosella", + "confidence": 0.92, + } + + +def validate_prediction_response(result: Any) -> Dict[str, Any]: + if not isinstance(result, dict): + raise MultiModalPredictionError("Multi-modal model returned an invalid response type") + + species = result.get("species") + confidence = result.get("confidence") + + if not isinstance(species, str) or not species.strip(): + raise MultiModalPredictionError("Multi-modal model response is missing a valid species") + + if not isinstance(confidence, Number): + raise MultiModalPredictionError("Multi-modal model response is missing a valid confidence") + + return { + "species": species, + "confidence": float(confidence), + } + + +def predict_with_failure_detection(audio_file: Any) -> Dict[str, Any]: + try: + result = predict_multimodal(audio_file) + except MultiModalPredictionError: + raise + except Exception as exc: + raise MultiModalPredictionError("Multi-modal prediction failed") from exc + + return validate_prediction_response(result)