Jonas c5fd4de09b Implement labeling frontend and the backend support it needs
Add a framework-free HTML/CSS/JS labeling UI: set/session/status
filters, a frame browser, drag-to-draw/move/resize bounding boxes with
a per-set class picker, per-frame status control, and Left/Right frame
navigation. No login - a locally cached username is sent for
attribution only, matching the backend's get-or-create user model.

Backend additions the frontend needed: serve frame images from a
configurable FRAMES_ROOT via a /images static mount, permissive CORS
(internal tool, not publicly exposed), and a GET /sets/{id}/frames
endpoint returning frames joined with their per-set label status
(defaulting missing rows to unlabeled) for the frame browser.

Verified the full call chain end-to-end against a running backend +
static frontend server (set/class creation, frame ingest, image
serving, label CRUD, status updates, CORS preflight) - every field
name the JS reads matches the API responses. 18/18 backend tests
pass. Not yet verified: actual interactive browser use (no browser
tooling available here) - try drag-to-draw/resize locally.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 11:34:26 +02:00

2.7 KiB

Labeling Tool — Frontend

UI for the bounding-box labeling tool: pick a label set, browse its frames, draw/ edit/delete boxes, assign classes, and mark per-frame status.

See CLAUDE.md §3.2 for full requirements.

Status: core labeling UI implemented — plain HTML/CSS/JS, no framework, no build step (matches "simple frontend — functionality over polish"). Not yet implemented: dataset-version browsing/promotion (backend doesn't have it yet either — see labeling/backend/README.md), multi-box copy/paste, and any kind of zoom/pan (assumes the fixed 1280x720 capture resolution fits on screen).

How it works

  • index.html / style.css — layout: top bar (set/session/status filters), a frame view with an absolutely-positioned box overlay, and a class-picker sidebar.
  • app.js — everything else: talks to the backend via fetch, renders boxes as DOM divs scaled to the displayed image size, and handles drawing (drag on empty space), moving (drag a box), resizing (drag its corner handle), selecting and deleting (click, then Delete/Backspace), and frame navigation (buttons or Left/Right arrow keys).
  • No login: a username is captured once via a prompt on first use, cached in localStorage, and sent as created_by/updated_by on writes purely for attribution (see the backend's multi-user notes).
  • Each sub-class gets a stable color derived from its id (colorForId in app.js), reused consistently across the class picker and the boxes.

Running it

This is static files — any static file server works, e.g. Python's stdlib one:

cd labeling/frontend
python3 -m http.server 5500

Then open http://127.0.0.1:5500. The backend must be running separately (see labeling/backend/README.md); the frontend defaults to http://127.0.0.1:8000 and the backend allows all CORS origins (it's an internal tool, not exposed publicly), so no extra configuration is needed for the default setup. To point at a different backend, set window.SPELUNKAI_API_BASE = "http://host:port" in a <script> tag before app.js loads in index.html.

You'll also need at least one label set with classes and some ingested frames to see anything — create those via the backend's API (/docs has interactive Swagger UI once it's running) until there's a bulk-ingest script.

Testing

No JS test framework/build step is set up (matches the "no build step" choice above). Verified so far: the full backend API contract this UI relies on is covered by the backend's pytest suite, and the static files + wiring (image serving, CORS, correct field names) were checked end-to-end via curl against a running backend. Not yet verified: actual interactive use in a browser (drag-to-draw, drag-to-resize) — try it locally and report anything that feels off.