Skip to content

Dashboard HTTP API

The desktop live dashboard is a FastAPI app served by python -m drowsyguard.cli live, on http://127.0.0.1:8000 by default.

Local tool, no authentication

There is no auth on any endpoint and /stream is your webcam. The default bind is 127.0.0.1; only pass --host 0.0.0.0 on a network you trust. FastAPI's own /docs and /redoc are disabled. See Security.

GET /

The dashboard page (src/drowsyguard/static/index.html).

Streams

All three are multipart/x-mixed-replace MJPEG with the boundary drowsyguardframe.

Endpoint Rate Shows
GET /stream 20 fps the annotated camera frame
GET /input-stream 10 fps the exact tensor the model receives
GET /eye-stream 10 fps the two eye crops

/input-stream is the one to open when results look wrong: it shows what the model actually sees, which is usually where the surprise is.

GET /snapshot.jpg

One JPEG of the current annotated frame. Returns 503 before the first frame has been captured.

GET /state

The engine snapshot, polled by the page.

Key Meaning
running the capture thread is alive
error fatal error, or null
warning non-fatal warnings joined into one string — tracker, eye model and capture warnings can all apply at once, and none silences the others
p_drowsy the current fused probability
state the RiskFilter state
streak, cooldown_left frames over the trigger, and frames still held off
config trigger, required, cooldown, zoom, PERCLOS window, eye threshold
history the rolling p(drowsy) trace behind the chart
alerts the last 10, newest first
behavior_events the last 12 cue events, newest first
alert_count, frames, fps, infer_ms counters
mode eye or face
eyes per-eye P(closed), PERCLOS, closure state
model kind, trained, source, normalizetrained: false is why the page says the probabilities are meaningless
image_size, crop preprocessing geometry
camera backend, index/source, capture timing
face, face_detect tracker state, and whether detection is on

POST /config

JSON body; every key optional. Applied live, which is what the sliders do.

curl -X POST http://127.0.0.1:8000/config \
     -H 'Content-Type: application/json' \
     -d '{"trigger": 0.6, "required": 8, "cooldown": 60}'
Key Effect
trigger risk level that starts a streak
required consecutive frames required to alert
cooldown frames held off after an alert
zoom centre-crop fraction (only when no face is detected)
face_detect enable/disable detection and tracking
perclos_window frames in the PERCLOS window
eye_closed_threshold P(closed) above which an eye counts as shut

Returns the resulting config. The page's Copy as C++ button turns trigger/required/cooldown into the RiskFilter constructor line for firmware/esp32s3/main/risk_filter.h.

POST /reset

Clears the filter state, the history and the counters. Returns {"ok": true}.

Compared with the device

The device API is a fixed-shape object built by one snprintf under a 6 kB stack; this one is whatever the engine snapshot holds. They are not interchangeable, and only the decision logic beneath them is shared.