Base URL: http://localhost:8080
Interactive docs: http://localhost:8080/docs (Swagger) · http://localhost:8080/redoc
All endpoints (except /api/v1/health and /api/v1/auth/login) require a Bearer token:
Authorization: Bearer <access_token>
// Request
{ "username": "admin", "password": "admin" }
// Response 200
{
"access_token": "eyJ...",
"refresh_token": "eyJ...",
"token_type": "bearer",
"user": { "id": "...", "username": "admin", "roles": ["admin"] }
}// Request
{ "refresh_token": "eyJ..." }
// Response 200 — new access_tokenInvalidates the refresh token.
Returns the current user profile.
Upload an image for inspection.
Content-Type: multipart/form-data
Fields:
file image/jpeg|png|bmp|tiff|webp (max 20 MB)
station_id string (default: "default")
part_id string (optional)
Response:
{
"id": "uuid",
"decision": "pass|fail|uncertain",
"confidence": 0.94,
"objects_found": 2,
"total_time_ms": 340,
"detections": [
{
"class_name": "scratch",
"confidence": 0.94,
"bbox": [120, 80, 240, 160],
"area_mm2": 12.4
}
],
"image_url": "/static/images/..."
}Capture from the configured camera and inspect. Same response shape.
Query params: station_id, part_id
Returns a stored inspection record by ID.
List inspections with filtering and pagination.
Query params:
| Param | Type | Default | Description |
|---|---|---|---|
| station_id | string | — | Filter by station |
| decision | string | — | pass / fail / uncertain |
| limit | int | 50 | Max results (≤ 500) |
| offset | int | 0 | Pagination offset |
Delete an inspection record (admin/engineer only).
Returns aggregated stats for the last N hours. Cached 30 s.
Query: hours (1–168, default 24), station_id
{
"total_inspections": 1420,
"passed": 1380,
"failed": 32,
"uncertain": 8,
"pass_rate": 0.972,
"avg_inspection_time_ms": 312,
"defect_breakdown": { "scratch": 18, "dent": 14 }
}Time-series data for charting. Cached 60 s.
Query: hours, interval (hour|day), station_id
{
"labels": ["2024-01-15 08:00:00", "..."],
"total": [45, 52, 38],
"passed": [44, 50, 38],
"failed": [1, 2, 0]
}Download all inspection history as CSV.
List all batch jobs.
Create a new batch job.
{ "name": "Shift A", "input_dir": "/data/shift_a", "file_pattern": "*.jpg" }Start a pending job.
Cancel a running job.
Get job status and progress.
Returns queue counts: pending / labeled / trained.
Returns the next N images requiring annotation.
Submit annotations for a queued image.
{
"annotations": [
{ "class_name": "scratch", "bbox": [10, 20, 100, 80] }
],
"reviewed_by": "operator1"
}Start a fine-tuning job using labeled images.
{
"epochs": 20,
"batch_size": 8,
"learning_rate": 0.001,
"model_name": "v1.1-scratch"
}Returns current training job status and metrics.
Abort the running training job.
List all available model versions.
Hot-swap the active model (zero downtime).
Revert to a previous model version.
Query params: severity (info|warning|error|critical), acknowledged (bool)
{
"alerts": [
{
"id": "uuid",
"severity": "warning",
"title": "Pass rate below threshold",
"message": "Pass rate 87% is below the 90% target",
"timestamp": "2024-01-15T09:32:00",
"acknowledged": false
}
]
}Mark an alert as acknowledged.
No auth required.
{ "status": "healthy", "version": "1.0.0" }Returns current application configuration.
Update configuration (admin/engineer only).
Returns disk usage breakdown.
Delete images older than retention policy.
Prometheus metrics endpoint.
Requires VLM_ENABLED=true in settings.
// Request
{ "question": "How many scratches were found at Station 3 this week?" }
// Response
{
"question": "How many scratches...",
"answer": "17 scratches were detected at Station 3 over the last 7 days...",
"backend": "anthropic"
}Returns the current state of the OPC-UA server.
Response
{
"enabled": true,
"running": true,
"endpoint": "opc.tcp://0.0.0.0:4840/ussop",
"station_count": 3,
"nodes": ["station/line-1", "station/line-2", "station/line-3", "SystemStatus"]
}The OPC-UA server exposes the following nodes per station:
| Node | Type | Description |
|---|---|---|
LastDecision |
String | "pass" / "fail" / "uncertain" |
LastConfidence |
Float | Confidence score 0–1 |
ObjectsFound |
Int | Number of detections in last inspection |
CycleTimeMs |
Float | Inference time in milliseconds |
PassCount |
Int | Cumulative pass count |
FailCount |
Int | Cumulative fail count |
UncertainCount |
Int | Cumulative uncertain count |
PassRate1h |
Float | Pass rate over last hour (0–100) |
LastInspectionTime |
DateTime | UTC timestamp of last inspection |
Enable the server by setting OPCUA_ENABLED=true and OPCUA_PORT=4840 in .env.
Returns whether the OpenVINO optimizer is available and which device is configured.
Response
{
"available": true,
"enabled": true,
"device": "AUTO",
"loaded_models": ["encoder", "decoder"],
"ort_fallback": false
}Load an ONNX model into the OpenVINO runtime.
Request body
{
"model_key": "encoder",
"model_path": "/app/models/resnet18_image_encoder.onnx",
"device": "CPU"
}Response — 200 OK
{ "status": "loaded", "model_key": "encoder", "device": "CPU" }Run a side-by-side latency comparison between ONNX Runtime and OpenVINO.
Request body
{
"model_key": "encoder",
"iterations": 50
}Response
{
"model_key": "encoder",
"ort_mean_ms": 42.1,
"ov_mean_ms": 18.7,
"speedup": 2.25
}Real-time push updates for the dashboard. Messages:
// Heartbeat (every 5 s)
{ "type": "ping", "data": { ... current stats ... } }
// New inspection completed
{ "type": "inspection", "data": { ... inspection record ... } }
// Stats refresh
{ "type": "stats", "data": { ... statistics ... } }Falls back to polling if WebSocket is unavailable.
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/users | List all users |
| POST | /api/v1/users | Create user |
| PUT | /api/v1/users/{id} | Update user |
| DELETE | /api/v1/users/{id} | Delete user |
| PUT | /api/v1/users/me | Update own email |
| PUT | /api/v1/users/me/password | Change own password |
| Endpoint | Limit |
|---|---|
| POST /auth/login | 10 / minute |
| All others | 200 / minute |
Exceeding limits returns 429 Too Many Requests.
All errors follow:
{ "detail": "Human-readable error message" }| Code | Meaning |
|---|---|
| 400 | Bad request / validation error |
| 401 | Missing or invalid token |
| 403 | Insufficient permissions |
| 404 | Resource not found |
| 413 | File too large (> 20 MB) |
| 415 | Unsupported media type |
| 422 | Unprocessable entity |
| 429 | Rate limit exceeded |
| 503 | Service unavailable (VLM disabled, etc.) |