# Module: main ## Purpose FastAPI application entry point — exposes HTTP API for object detection on images and video media, health checks, and Server-Sent Events (SSE) streaming of detection results. ## Public Interface ### API Endpoints | Method | Path | Description | |--------|------|-------------| | GET | `/health` | Returns AI engine availability status | | POST | `/detect` | Single image detection (multipart file upload) | | POST | `/detect/{media_id}` | Start async detection on media from loader service | | GET | `/detect/stream` | SSE stream of detection events | ### DTOs (Pydantic Models) | Model | Fields | Description | |-------|--------|-------------| | `DetectionDto` | centerX, centerY, width, height, classNum, label, confidence | Single detection result | | `DetectionEvent` | annotations (list[DetectionDto]), mediaId, mediaStatus, mediaPercent | SSE event payload | | `HealthResponse` | status, aiAvailability, errorMessage | Health check response | | `AIConfigDto` | frame_period_recognition, frame_recognition_seconds, probability_threshold, tracking_*, model_batch_size, big_image_tile_overlap_percent, altitude, focal_length, sensor_width, paths | Configuration input for media detection | ### Class: TokenManager | Method | Signature | Description | |--------|-----------|-------------| | `__init__` | `(str access_token, str refresh_token)` | Stores tokens | | `get_valid_token` | `() -> str` | Returns access_token; auto-refreshes if expiring within 60s | ## Internal Logic ### `/health` Returns `HealthResponse` with `status="healthy"` always. `aiAvailability` reflects the engine's `AIAvailabilityStatus`. On exception, returns `aiAvailability="None"`. ### `/detect` (single image) 1. Reads uploaded file bytes 2. Parses optional JSON config 3. Runs `inference.detect_single_image` in ThreadPoolExecutor (max 2 workers) 4. Returns list of DetectionDto Error mapping: RuntimeError("not available") → 503, RuntimeError → 422, ValueError → 400. ### `/detect/{media_id}` (async media) 1. Checks for duplicate active detection (409 if already running) 2. Extracts auth tokens from Authorization header and x-refresh-token header 3. Creates `asyncio.Task` for background detection 4. Detection runs `inference.run_detect` in ThreadPoolExecutor 5. Callbacks push `DetectionEvent` to all SSE queues 6. If auth token present, also POSTs annotations to the Annotations service 7. Returns immediately: `{"status": "started", "mediaId": media_id}` ### `/detect/stream` (SSE) - Creates asyncio.Queue per client (maxsize=100) - Yields `data: {json}\n\n` SSE format - Cleans up queue on disconnect ### Token Management - Decodes JWT exp claim from base64 payload (no signature verification) - Auto-refreshes via POST to `{ANNOTATIONS_URL}/auth/refresh` when within 60s of expiry ### Annotations Service Integration - POST to `{ANNOTATIONS_URL}/annotations` with: - `mediaId`, `source: 0`, `videoTime` (formatted from ms), `detections` (list of dto dicts) - Optional base64-encoded `image` - Bearer token in Authorization header ## Dependencies - **External**: `asyncio`, `base64`, `json`, `os`, `time`, `concurrent.futures`, `typing`, `requests`, `fastapi`, `pydantic` - **Internal**: `inference` (lazy import), `constants_inf` (label lookup), `loader_http_client` (client instantiation) ## Consumers None (entry point). ## Data Models - `DetectionDto`, `DetectionEvent`, `HealthResponse`, `AIConfigDto` — Pydantic models for API - `TokenManager` — JWT token lifecycle ## Configuration | Env Var | Default | Description | |---------|---------|-------------| | `LOADER_URL` | `http://loader:8080` | Loader service base URL | | `ANNOTATIONS_URL` | `http://annotations:8080` | Annotations service base URL | ## External Integrations | Service | Protocol | Purpose | |---------|----------|---------| | Loader | HTTP (via LoaderHttpClient) | Model loading | | Annotations | HTTP POST | Auth refresh (`/auth/refresh`), annotation posting (`/annotations`) | ## Security - Bearer token from request headers, refreshed via Annotations service - JWT exp decoded (base64, no signature verification) — token validation is not performed locally - No CORS configuration - No rate limiting - No input validation on media_id path parameter beyond string type ## Tests None found.