| | """ |
| | Marine species detection inference endpoints. |
| | """ |
| |
|
| | from fastapi import APIRouter, HTTPException, status, Depends |
| | from typing import List |
| |
|
| | from app.models.inference import ( |
| | InferenceRequest, |
| | InferenceResponse, |
| | SpeciesListResponse, |
| | SpeciesInfo, |
| | ErrorResponse |
| | ) |
| | from app.services.inference_service import inference_service |
| | from app.api.dependencies import validate_model_health |
| | from app.core.logging import get_logger |
| |
|
| | logger = get_logger(__name__) |
| |
|
| | router = APIRouter() |
| |
|
| |
|
| | @router.post( |
| | "/detect", |
| | response_model=InferenceResponse, |
| | responses={ |
| | 400: {"model": ErrorResponse, "description": "Bad Request"}, |
| | 503: {"model": ErrorResponse, "description": "Service Unavailable"}, |
| | }, |
| | summary="Detect Marine Species", |
| | description="Detect and identify marine species in an uploaded image using YOLOv5 model" |
| | ) |
| | async def detect_marine_species( |
| | request: InferenceRequest, |
| | _: bool = Depends(validate_model_health) |
| | ) -> InferenceResponse: |
| | """ |
| | Detect marine species in an image. |
| | |
| | - **image**: Base64 encoded image data |
| | - **confidence_threshold**: Minimum confidence for detections (0.0-1.0) |
| | - **iou_threshold**: IoU threshold for non-maximum suppression (0.0-1.0) |
| | - **image_size**: Input image size for inference (320-1280) |
| | - **return_annotated_image**: Whether to return annotated image with bounding boxes |
| | - **classes**: Optional list of class IDs to filter detections |
| | |
| | Returns detection results with bounding boxes, confidence scores, and species names. |
| | """ |
| | try: |
| | logger.info("Processing marine species detection request") |
| | |
| | result = await inference_service.detect_species( |
| | image_data=request.image, |
| | confidence_threshold=request.confidence_threshold, |
| | iou_threshold=request.iou_threshold, |
| | image_size=request.image_size, |
| | return_annotated_image=request.return_annotated_image, |
| | classes=request.classes |
| | ) |
| | |
| | logger.info(f"Detection completed: {len(result.detections)} species found") |
| | return result |
| | |
| | except ValueError as e: |
| | logger.error(f"Invalid input data: {str(e)}") |
| | raise HTTPException( |
| | status_code=status.HTTP_400_BAD_REQUEST, |
| | detail=f"Invalid input: {str(e)}" |
| | ) |
| | except Exception as e: |
| | logger.error(f"Detection failed: {str(e)}") |
| | raise HTTPException( |
| | status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
| | detail=f"Detection failed: {str(e)}" |
| | ) |
| |
|
| |
|
| | @router.get( |
| | "/species", |
| | response_model=SpeciesListResponse, |
| | summary="List Supported Species", |
| | description="Get a list of all marine species that can be detected by the model" |
| | ) |
| | async def list_supported_species( |
| | _: bool = Depends(validate_model_health) |
| | ) -> SpeciesListResponse: |
| | """ |
| | Get a list of all supported marine species. |
| | |
| | Returns a comprehensive list of all marine species that the model can detect, |
| | including their class IDs and scientific/common names. |
| | """ |
| | try: |
| | logger.info("Fetching supported species list") |
| | |
| | species_data = await inference_service.get_supported_species() |
| | |
| | species_list = [ |
| | SpeciesInfo(class_id=item["class_id"], class_name=item["class_name"]) |
| | for item in species_data |
| | ] |
| | |
| | return SpeciesListResponse( |
| | species=species_list, |
| | total_count=len(species_list) |
| | ) |
| | |
| | except Exception as e: |
| | logger.error(f"Failed to fetch species list: {str(e)}") |
| | raise HTTPException( |
| | status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
| | detail=f"Failed to fetch species list: {str(e)}" |
| | ) |
| |
|
| |
|
| | @router.get( |
| | "/species/{class_id}", |
| | response_model=SpeciesInfo, |
| | responses={ |
| | 404: {"model": ErrorResponse, "description": "Species Not Found"}, |
| | }, |
| | summary="Get Species Information", |
| | description="Get information about a specific marine species by class ID" |
| | ) |
| | async def get_species_info( |
| | class_id: int, |
| | _: bool = Depends(validate_model_health) |
| | ) -> SpeciesInfo: |
| | """ |
| | Get information about a specific marine species. |
| | |
| | - **class_id**: The class ID of the species to look up |
| | |
| | Returns detailed information about the specified marine species. |
| | """ |
| | try: |
| | logger.info(f"Fetching species info for class_id: {class_id}") |
| | |
| | species_data = await inference_service.get_supported_species() |
| | |
| | |
| | for species in species_data: |
| | if species["class_id"] == class_id: |
| | return SpeciesInfo( |
| | class_id=species["class_id"], |
| | class_name=species["class_name"] |
| | ) |
| | |
| | |
| | raise HTTPException( |
| | status_code=status.HTTP_404_NOT_FOUND, |
| | detail=f"Species with class_id {class_id} not found" |
| | ) |
| | |
| | except HTTPException: |
| | raise |
| | except Exception as e: |
| | logger.error(f"Failed to fetch species info: {str(e)}") |
| | raise HTTPException( |
| | status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
| | detail=f"Failed to fetch species info: {str(e)}" |
| | ) |
| |
|