Files
detections/_docs/02_document/modules/main.md
T
2026-03-23 14:07:54 +02:00

6.9 KiB
Raw Blame History

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

Detections posts results to the Annotations service (POST {ANNOTATIONS_URL}/annotations) server-to-server during async media detection (F3). This only happens when an auth token is present in the original request.

Endpoint: POST {ANNOTATIONS_URL}/annotations

Headers:

Header Value
Authorization Bearer {accessToken} (forwarded from the original client request)
Content-Type application/json

Request body — payload sent by Detections:

Field Type Description
mediaId string ID of the media being processed
source int 0 (AnnotationSource.AI)
videoTime string Video playback position formatted from ms as "HH:MM:SS" — mapped to Annotations.Time
detections list Detection results for this batch (see below)
image string (base64) Optional — base64-encoded frame image bytes

userId is not included in the payload. The Annotations service resolves the user identity from the Bearer JWT.

Detection object (as sent by Detections):

Field Type Description
centerX float X center, normalized 0.01.0
centerY float Y center, normalized 0.01.0
width float Width, normalized 0.01.0
height float Height, normalized 0.01.0
classNum int Detection class number
label string Human-readable class name
confidence float Model confidence 0.01.0

The Annotations API contract (CreateAnnotationRequest) also accepts description (string), affiliation (AffiliationEnum), and combatReadiness (CombatReadinessEnum) on each Detection, but the Detections service does not populate these — the Annotations service uses defaults.

Responses from Annotations service:

Status Condition
201 Annotation created
400 Neither image nor mediaId provided
404 MediaId not found in Annotations DB

Failure handling: POST failures are silently caught — detection processing continues regardless. Annotations that fail to post are not retried.

Downstream pipeline (Annotations service side):

  1. Saves annotation to local PostgreSQL (image → XxHash64 ID, label file in YOLO format)
  2. Publishes SSE event to UI via GET /annotations/events
  3. Enqueues annotation ID to annotations_queue_records buffer table (unless SilentDetection mode is enabled in system settings)
  4. FailsafeProducer (BackgroundService) drains the buffer to RabbitMQ Stream (azaion-annotations) using MessagePack + Gzip

Token refresh for long-running video:

For video detection that may outlast the JWT lifetime, the TokenManager auto-refreshes via POST {ANNOTATIONS_URL}/auth/refresh when the token is within 60s of expiry. The refresh token is provided by the client in the X-Refresh-Token request 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.