Offload protocol

HTTP, served by westwind serve (default port 8765). JSON bodies.

GET /v1/health

{"ok": true, "version": "0.1.0"}

GET /v1/models

The models the server can run, with their placement.

POST /v1/infer

When the server has WESTWIND_SERVE_TOKEN set, the request needs Authorization: Bearer <token>; westwind serve --upstream sends WESTWIND_UPSTREAM_TOKEN. Request:

{
  "model": "mediapipe/face_detector/blaze_face_short_range",
  "image": { "format": "RGB565", "width": 96, "height": 96, "b64": "..." },
  "params": { "threshold": 0.5 }
}

image may be replaced by tensor: {"shape": [...], "dtype": "float32", "b64": "..."}, or by jpeg_b64. Response:

{ "ok": true, "task": "detection", "latency_ms": 41, "result": { "boxes": [] } }

Over UART or USB CDC the same request and response are carried as single lines prefixed with WW1 followed by a space and the JSON object, so they can share the console with log output. westwind serve --serial PORT reads requests from the device and writes the replies back on the same port.

Result objects, shared by the device JSON output, the offload server and the web application:

classification   {"labels": [{"label": "7", "index": 7, "score": 0.98}]}
detection        {"boxes": [{"x": 0.1, "y": 0.2, "w": 0.3, "h": 0.3, "score": 0.9, "label": "face"}]}
segmentation     {"mask": {"width": 64, "height": 64, "classes": ["background", "person"], "rle": [..]}}
pose             {"keypoints": [{"name": "nose", "x": 0.5, "y": 0.4, "score": 0.8}]}
anomaly          {"p_anomaly": 0.01, "anomaly": false}
keyword-spotting {"label": "hey_zephyr", "p": 0.96}

Coordinates are normalised to the input frame (0 to 1).