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

59 lines
2.7 KiB
Markdown

# 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 `div`s 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.