3 Commits

Author SHA1 Message Date
4e993ccf52 Add dataset version promotion (enemy-v1, enemy-v2, ...)
Add DatasetVersion/DatasetVersionFrame/DatasetVersionLabel and a
promote endpoint (POST /sets/{id}/dataset-versions) that freezes a
set's currently-reviewed frames (or an explicit frame_ids selection)
into a named, immutable snapshot: it copies each label's data at
promotion time rather than referencing the live rows, so later edits
or deletes to those labels can't retroactively change an already
-promoted version. GET /dataset-versions/{id} returns the frozen
frames+labels - this is what the training pipeline will eventually
pull from.

This was the labeling backend's last deliberately-deferred piece from
the original data model (needed its own design pass for snapshot
semantics). 31/31 backend tests pass, including one that promotes a
version, edits and deletes the live label afterward, and asserts the
snapshot is untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 13:08:17 +02:00
96b7d42c34 Add bulk frame ingest for recording sessions
Registering thousands of extracted frames one-by-one via POST /frames
doesn't scale, so add `spelunkai-labeling-backend ingest-session`: it
writes Frame rows directly against the database (no server needs to
be running) for all frame_*.png files under a directory already
placed under FRAMES_ROOT. Idempotent per (session_name, frame_index),
so re-running after copying more frames only inserts the new ones.

Restructured the CLI into subcommands (serve / ingest-session) while
keeping `spelunkai-labeling-backend` with no arguments working exactly
as before (defaults to serve), verified against a live run. 22/22
backend tests pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 13:04:09 +02:00
4c9deda66a Implement labeling backend: FastAPI + SQLAlchemy data model and CRUD API
Add the core labeling data model (label sets, ad-hoc Main->Sub class
hierarchy, frames, bounding-box labels, per-frame/per-set label
status) behind a FastAPI app, with SQLite as the default swappable
DATABASE_URL. Multi-user support is attribution-only for now
(get-or-create by username, no login flow yet). Dataset
versioning/promotion is intentionally deferred - it needs its own
design pass around snapshot semantics.

Each test gets a fully isolated app+DB via create_app(database_url=...)
rather than relying on process-global state. 13/13 tests pass; also
verified live end-to-end against a running uvicorn instance.

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