Docker-first FastAPI service for snake species detection using an Ultralytics YOLO12 .pt model on CPU. The container loads model weights from a mounted volume (default /models/best.pt), exposes /detect/* endpoints, and includes /health for liveness checks.
docker build -t snake-detect:latest .
docker run --rm -p 8000:8000 \
-e MODEL_PATH=/models/best.pt \
-e MODEL_VERSION=snake-yolo12-v1.0 \
-e MAX_UPLOAD_MB=10 \
-e MAX_SIDE=1920 \
-e MAX_CONCURRENCY=1 \
-e REQUEST_QUEUE_LIMIT=20 \
-e RATE_LIMIT_RPM=120 \
-e SAVE_DIR=/data/saved_images \
-e URL_FETCH_TIMEOUT_SECONDS=8 \
-e URL_MAX_DOWNLOAD_MB=10 \
-v $(pwd)/models:/models:ro \
-v $(pwd)/data/saved_images:/data/saved_images \
snake-detect:latestFor detailed API documentation, request/response schemas, and error codes, see FASTAPI_DOCS.md.
POST /detect/file- multipart form upload withimagefieldPOST /detect/base64- JSON body withimage_base64POST /detect/url- JSON body withimage_urlGET /health-{ status, model_loaded, model_version, uptime_s }
Available per-request parameters:
imgsz(int, default640)conf(float, default0.25)iou(float, default0.5)topk(int, default100)save_image(bool, defaultfalse)
Detections are sorted by confidence descending and capped by topk.
File upload:
curl -s -X POST "http://localhost:8000/detect/file?imgsz=640&conf=0.25&iou=0.5&topk=100&save_image=false" \
-F image=@/path/to/image.jpgBase64:
curl -s -X POST http://localhost:8000/detect/base64 \
-H "Content-Type: application/json" \
-d '{"image_base64":"<BASE64_DATA>","imgsz":640,"conf":0.25,"iou":0.5,"topk":100,"save_image":false}'URL:
curl -s -X POST http://localhost:8000/detect/url \
-H "Content-Type: application/json" \
-d '{"image_url":"https://example.com/image.jpg","imgsz":640,"conf":0.25,"iou":0.5,"topk":100,"save_image":false}'{
"model_version": "snake-yolo12-v1.0",
"image_width": 1280,
"image_height": 720,
"warnings": {"blur": 0.12, "brightness": 0.45, "too_small": 0.0},
"detections": [
{
"class_id": 3,
"class_name": "ho_mang_chua",
"confidence": 0.93,
"bbox": {"x1": 120, "y1": 60, "x2": 420, "y2": 360}
}
],
"saved_image_path": "/data/saved_images/abc123.jpg"
}Bounding boxes are pixel coordinates relative to the image that inference runs on (after EXIF autorotation and any downscale to MAX_SIDE).
- EXIF autorotation is applied on decode.
- If the longest side exceeds
MAX_SIDE, the image is downscaled proportionally. - Quality warnings are always returned (they never block inference):
blur(variance of Laplacian based)brightness(mean luminance)too_small(based on resolution threshold)
If save_image=true, the service saves the received image to SAVE_DIR (default /data/saved_images) and returns saved_image_path in the response. Mount SAVE_DIR as a volume if you want persisted outputs.
- Upload size limit:
MAX_UPLOAD_MBfor file/base64 requests. - URL download limit:
URL_MAX_DOWNLOAD_MB, withURL_FETCH_TIMEOUT_SECONDSandURL_MAX_REDIRECTS. - Concurrency control via
MAX_CONCURRENCYand optionalREQUEST_QUEUE_LIMIT. - Per-IP rate limiting via
RATE_LIMIT_RPM(0 disables).
MODEL_PATH(default:/models/best.pt)MODEL_VERSION(required)MAX_UPLOAD_MB(default:10)URL_MAX_DOWNLOAD_MB(default:10)URL_FETCH_TIMEOUT_SECONDS(default:8)URL_MAX_REDIRECTS(default:3)MAX_SIDE(default:1920)MAX_CONCURRENCY(default:1)REQUEST_QUEUE_LIMIT(default:0, disabled when0)RATE_LIMIT_RPM(default:0, disabled when0)SAVE_DIR(default:/data/saved_images)DEFAULT_IMGSZ(default:640)DEFAULT_CONF(default:0.25)DEFAULT_IOU(default:0.5)DEFAULT_TOPK(default:100)LOG_LEVEL(default:info)
Swagger UI is available at http://localhost:8000/swagger and the OpenAPI JSON at http://localhost:8000/openapi.json.

