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>
75 lines
1.9 KiB
HTML
75 lines
1.9 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>SpelunkAI Labeling Tool</title>
|
|
<link rel="stylesheet" href="style.css" />
|
|
</head>
|
|
<body>
|
|
<header class="topbar">
|
|
<h1>SpelunkAI Labeling</h1>
|
|
|
|
<label>
|
|
Set
|
|
<select id="set-select"><option value="">Loading…</option></select>
|
|
</label>
|
|
|
|
<label>
|
|
Session
|
|
<input id="session-filter" type="text" placeholder="all sessions" />
|
|
</label>
|
|
|
|
<label>
|
|
Status
|
|
<select id="status-filter">
|
|
<option value="">all</option>
|
|
<option value="unlabeled">unlabeled</option>
|
|
<option value="auto_labeled">auto_labeled</option>
|
|
<option value="reviewed">reviewed</option>
|
|
</select>
|
|
</label>
|
|
|
|
<button id="apply-filters">Apply</button>
|
|
|
|
<span id="frame-position" class="frame-position"></span>
|
|
</header>
|
|
|
|
<main class="workspace">
|
|
<section class="canvas-area">
|
|
<div id="image-container">
|
|
<img id="frame-image" draggable="false" alt="" />
|
|
<div id="bbox-layer"></div>
|
|
</div>
|
|
|
|
<div class="nav-controls">
|
|
<button id="prev-frame">← Prev</button>
|
|
<label>
|
|
Frame status
|
|
<select id="frame-status" disabled>
|
|
<option value="unlabeled">unlabeled</option>
|
|
<option value="auto_labeled">auto_labeled</option>
|
|
<option value="reviewed">reviewed</option>
|
|
</select>
|
|
</label>
|
|
<button id="next-frame">Next →</button>
|
|
</div>
|
|
</section>
|
|
|
|
<aside class="sidebar">
|
|
<h2>Classes</h2>
|
|
<div id="class-list"><p class="hint">Pick a set first.</p></div>
|
|
|
|
<p class="hint">
|
|
Click a class, then drag on the image to draw a box.<br />
|
|
Click an existing box to select it (Delete/Backspace removes it, drag
|
|
the body to move, drag the bottom-right handle to resize).<br />
|
|
Left/Right arrow keys move between frames.
|
|
</p>
|
|
</aside>
|
|
</main>
|
|
|
|
<script src="app.js" defer></script>
|
|
</body>
|
|
</html>
|