File size: 3,211 Bytes
6cc8ae1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
"""
Prediction endpoints.
POST /predict/file  - Upload image file
POST /predict/url   - Predict from image URL
POST /predict/base64 - Predict from base64 image
"""

from fastapi import APIRouter, UploadFile, File, HTTPException, Query

from backend.app.schemas.predict import (
    PredictResponse,
    PredictURLRequest,
    PredictBase64Request,
    PredictionItem,
    BreedInfo,
)
from backend.app.services.inference import inference_service
from backend.app.services.image_loader import (
    load_image_from_upload,
    load_image_from_url,
    load_image_from_base64,
)
from backend.app.services.breed_info import breed_info_service
from backend.app.core.logging import logger

router = APIRouter(prefix="/predict", tags=["Prediction"])


def _build_response(result: dict) -> PredictResponse:
    """Build a PredictResponse from inference result dict."""
    # Get breed info
    breed_info = None
    breed_summary = breed_info_service.get_breed_summary(result['predicted_breed'])
    if breed_summary:
        breed_info = BreedInfo(**breed_summary)

    return PredictResponse(
        predicted_breed=result['predicted_breed'],
        confidence=result['confidence'],
        top_k=[PredictionItem(**item) for item in result['top_k']],
        breed_info=breed_info,
        model_version=result.get('model_version', 'v1.0'),
        inference_time_ms=result['inference_time_ms'],
        warning=result.get('warning'),
    )


@router.post("/file", response_model=PredictResponse)
async def predict_file(
    file: UploadFile = File(...),
    top_k: int = Query(default=3, ge=1, le=10),
):
    """Predict breed from uploaded image file."""

    try:
        contents = await file.read()
        image = load_image_from_upload(contents)
        result = inference_service.predict(image, top_k=top_k)
        return _build_response(result)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"Prediction error: {e}")
        raise HTTPException(status_code=500, detail="Prediction failed")


@router.post("/url", response_model=PredictResponse)
async def predict_url(request: PredictURLRequest):
    """Predict breed from image URL."""

    try:
        image = load_image_from_url(request.url)
        result = inference_service.predict(image, top_k=request.top_k)
        return _build_response(result)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"Prediction error: {e}")
        raise HTTPException(status_code=500, detail="Prediction failed")


@router.post("/base64", response_model=PredictResponse)
async def predict_base64(request: PredictBase64Request):
    """Predict breed from base64-encoded image."""

    try:
        image = load_image_from_base64(request.image)
        result = inference_service.predict(image, top_k=request.top_k)
        return _build_response(result)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"Prediction error: {e}")
        raise HTTPException(status_code=500, detail="Prediction failed")