Runtime Configuration#

Everything reconfigurable at runtime lives in the Settings modal, opened via the Settings button in the top action bar, next to Start/Stop.

First launch. The app opens with a one-time research-use disclaimer that must be acknowledged before the main UI is interactive. The ack is stored in localStorage under surgical_disclaimer_ack_v1 and does not survive a browser-profile wipe.

Input Source tab#

Pick where frames come from without editing config files or restarting compose. Three source kinds are supported; kinds with no detected devices are visible but disabled so it is clear what the app supports.

Kind

Argument

Populated by

Video file

basename under ./videos/

GET /api/videos — lists everything with .mp4 .mkv .avi .mov .ts

USB / v4l2 camera

/dev/videoN

GET /api/devices/cameras — reads /sys/class/video4linux

Basler camera

serial number

GET /api/devices/cameras — pypylon enumeration (ships in Slice E)

  • Upload a new video with the “Choose file…” button (max 500 MB, extension whitelist enforced server-side). New uploads land in the same ./videos/ volume and appear in the dropdown immediately.

  • Apply persists the selection client-side. It takes effect on the next Start — the pipeline rejects source changes mid-stream. If a pipeline is running, the modal shows a banner and blocks changes until you Stop.

  • Cameras are compose-time devices. Hot-plugging after make up requires make run (or the equivalent docker compose up -d) so the container can see the new node — the UI picker only surfaces what is already mounted.

Devices tab#

Single-row table (Workload · Model · Device) with a dropdown for the polyp-detection accelerator: CPU, GPU (Intel Arc iGPU — recommended), NPU (Intel AI Boost). Save applies the change on the next Start; Reset session clears the last inference session’s aggregates without stopping the backend process.

Backend contract (for scripting / smoke tests)#

The UI is a thin wrapper over these endpoints, so any of them can be driven from curl for automation.

Endpoint

Purpose

GET /api/videos

List {name, size_bytes, mtime} under VIDEOS_DIR (default /videos)

POST /api/videos

Multipart upload (file field). 415 for wrong ext, 409 for duplicate, 413 for oversize

GET /api/devices/cameras

{v4l2:[…], basler:[…], basler_note?}

GET /api/config

Reflects live source: {video_file, default_video, source:{kind,arg}, devices:{detect}}

POST /api/start

Optional body: {device?, source?:{kind,arg}} — persisted to ServerState for subsequent Starts

POST /api/stop · POST /api/reset

Lifecycle

POST /api/device

Set active accelerator for the polyp-detection workload

Pre-flight: make doctor#

Read-only diagnostic that checks the host before you run make up. Reports each item as [ OK ], [WARN], or [FAIL]; exits non-zero only on genuine fatals (missing Docker, no video assets, port collision with a foreign process). Own-stack aware — if surgical-ui is already running on UI_HOST_PORT, that is reported as OK, not as a conflict.

Sections: host prerequisites · accelerator visibility · cameras · assets · port availability · compose config. Sample output:

[doctor] --- accelerator visibility ---
  [ OK ] /dev/dri present (renderD* count: 1)
  [ OK ] /dev/accel/accel0 present (NPU visible)
[doctor] --- assets ---
  [ OK ] cached IR : models/yolo11n_polyp/best_openvino_model (5.4M)
  [ OK ] 2 demo video(s) under ./videos/
[doctor] --- port availability ---
  [ OK ] port 8080 free
[doctor] all critical checks passed — `make up` should succeed.