feat: configurable track forward, track to end, skip-and-mark (REQ-189)
Track 5 Frames becomes Track Forward with a 1-100 count input, remembered in localStorage (default 5). A separate -> End action runs to the last frame behind a confirm and can be cancelled mid-flight. Frames that already hold a shape of the tracked class are skipped instead of re-annotated: hidden and dimmed shapes count as present. Skips are reported in the result banner and marked with a dot plus a class name on the filmstrip thumbnail. frames() now returns the class ids each frame holds, the same query row, no migration. Chaining and seed growth stay out: every frame is still seeded from the drawn box only.
This commit is contained in:
1 parent
f6b0335c93
commit
4f15335092
9 files changed
+226
-52
No files matched your search
@@ -1405,6 +1405,47 @@ read it.
|
||||
(accent border + glow) — no CSS added; **browser eyeball still owed by the user**
|
||||
(375 px 2-col wrap, long class names).
|
||||
|
||||
## Task — Configurable Track Forward + track-to-end (REQ-189) `[DONE]`
|
||||
|
||||
> Status caveat: code, build and docs are verified below; the **end-to-end GPU run in the
|
||||
> user's browser is still owed**, so the feature is not proven on real shapes yet.
|
||||
|
||||
1. **Backend** `backend/batches.py:136` `frames()` — the skip check needs *which* classes a
|
||||
frame holds, and the frontend only ever received `annotation_count`. Added
|
||||
`GROUP_CONCAT(DISTINCT a.class_id)` to the existing subquery (same row, no extra round trip,
|
||||
no migration) and parsed it to `[int]`, `[]` when NULL.
|
||||
→ verify: **[DONE]** `uv run` against the real DB: batch 19 returns 507 frames, the five
|
||||
frames of the earlier manual track run (`22829`–`22833`) come back `class_ids: [2]`, frames
|
||||
with none return `[]`. `EXPLAIN QUERY PLAN` shows both subqueries seek
|
||||
`idx_annotations_frame` (no per-frame scan). Other consumers (`autolabel.py:95`,
|
||||
`dataset.py:480`, `preview.py:35`) only read dict keys — unaffected.
|
||||
2. **Cancel plumbing** `frontend/src/api.js` — `request` takes `signal`, `assist(frameId, body,
|
||||
{ signal })` forwards it. No other caller touched.
|
||||
3. **UI** `frontend/src/pages/ReviewPage.jsx` — `trackForward(toEnd)` now takes an explicit
|
||||
count: N input (1–100, clamped and **persisted on blur** — an effect would save the
|
||||
half-typed value, so typing "15" survives), *Track Forward [T]* with a dynamic tooltip,
|
||||
*→ End* with a confirm showing the real frame count, `AbortController` per run so the
|
||||
"asking SAM3…" indicator becomes a **Cancel** button, skip-on-existing-class, and a banner
|
||||
reading `Tracked N of M — skipped K already had <class> — <failures>`. The banner shows when
|
||||
something was skipped *or* failed — a fully clean run stays silent, as before. A successful
|
||||
assist also unions its `class_id` into the local frame's `class_ids`, so a second run in the
|
||||
same session skips its own output instead of writing duplicates.
|
||||
4. **Filmstrip** `frontend/src/components/Filmstrip.jsx` — optional `markedIds` + `markLabel`
|
||||
props; `frontend/src/app.css` `.thumb .skip-dot` (`--warn` + 2 px dark ring for contrast on
|
||||
light thumbs, top-left so it never collides with the count badge), `.track-count` for the
|
||||
input, and `flex-wrap` on `.frame-bar` so the bar still fits 375 px. Skipped frames also name
|
||||
the class in the thumb tooltip.
|
||||
→ verify: **[DONE]** `npm run build` green; clamp covers `"abc"`, `0`, `999`, `-3`, `""`,
|
||||
`Infinity` and non-numeric `localStorage` garbage (`Number.isFinite` guard → 5), and the
|
||||
slice bound is computed from `Number(trackFrames)` so a string can never concatenate into the
|
||||
slice end; `slice(index+1, index+1+N)` and `slice(index+1)` both bounded; cancel lands as
|
||||
`cancelled — frame n may still be saved by the server` and keeps the shapes already written;
|
||||
skip check reads the `class_ids` array, not `annotation_count`; marks cleared at the start of
|
||||
every run; `Shift+T` deliberately **not** bound (a fat-fingered 500-frame GPU run is not worth
|
||||
a keystroke). Reviewer pass done — 4 findings fixed. **Still owed, user browser + GPU**: set
|
||||
N=3 → 3 shapes, reload → N remembered; to-end over the already-reviewed part of batch 19 →
|
||||
banner reports the skips and dots appear on those thumbs; Cancel mid-run stops it.
|
||||
|
||||
## Task — Track 5 Frames works at all (REQ-189) `[DONE]`
|
||||
|
||||
1. `ReviewPage.jsx:trackForward` read `geometry.coordinates` — a key the backend never emits
|
||||
|
||||
Reference in new issue
Block a user