diff --git a/scripts/barrier_picker_app/app.py b/scripts/barrier_picker_app/app.py index 17490fe..a2d3c02 100644 --- a/scripts/barrier_picker_app/app.py +++ b/scripts/barrier_picker_app/app.py @@ -73,6 +73,7 @@ class QueueItem: duration_s: float | None done: bool metadata: dict # experimental fields aggregated from the merged TSV + existing: dict | None # current barrier_opening.csv row if already picked # ─── Queue building ───────────────────────────────────────────────────── @@ -142,13 +143,19 @@ def _build_queue() -> list[QueueItem]: "duration_s": float(r.duration_s) if pd.notna(r.duration_s) else None, } + existing_by_key: dict[tuple[str, str, str], dict] = {} if OUTPUT_CSV.exists(): out = pd.read_csv(OUTPUT_CSV) - done_keys = set(zip(out["machine_name"], - out["session_date"], - out["session_time"])) - else: - done_keys = set() + for _, r in out.iterrows(): + key = (r["machine_name"], r["session_date"], r["session_time"]) + existing_by_key[key] = { + "opening_s": float(r["opening_s"]) if pd.notna(r["opening_s"]) else None, + "trim_first_s": int(r["trim_first_s"]) if pd.notna(r.get("trim_first_s")) else 0, + "bad_rois": str(r.get("bad_rois", "") or "") if pd.notna(r.get("bad_rois")) else "", + "analyst": str(r.get("analyst", "") or "") if pd.notna(r.get("analyst")) else "", + "notes": str(r.get("notes", "") or "") if pd.notna(r.get("notes")) else "", + } + done_keys = set(existing_by_key) seen: set[tuple[str, str, str]] = set() items: list[QueueItem] = [] @@ -189,6 +196,7 @@ def _build_queue() -> list[QueueItem]: duration_s=inv_row["duration_s"], done=key in done_keys, metadata=metadata, + existing=existing_by_key.get(key), )) return items @@ -217,6 +225,7 @@ async def get_queue() -> JSONResponse: "duration_s": q.duration_s, "done": q.done, "metadata": q.metadata, + "existing": q.existing, } for q in queue ]) diff --git a/scripts/barrier_picker_app/static/index.html b/scripts/barrier_picker_app/static/index.html index 9245077..81ca80a 100644 --- a/scripts/barrier_picker_app/static/index.html +++ b/scripts/barrier_picker_app/static/index.html @@ -107,6 +107,24 @@ font-size: 0.95rem; } #login-submit:hover { background: #3e6; } #login-submit:disabled { background: #444; color: #888; cursor: not-allowed; } + + /* Annotation bar (existing-mark indicator below the video) */ + #annotation-bar { position: relative; width: 100%; max-width: 1400px; + height: 18px; background: #181818; border: 1px solid #333; + border-radius: 3px; margin-top: 0.5rem; cursor: pointer; } + #annotation-bar.empty { background: transparent; border-color: transparent; + cursor: default; height: 0.6rem; } + #annotation-bar .mark-line { position: absolute; top: -2px; bottom: -2px; + width: 3px; background: #f44; + box-shadow: 0 0 4px rgba(255,80,80,0.7); } + #annotation-bar .mark-line:hover { background: #f88; } + #annotation-bar .mark-tooltip { position: absolute; top: 100%; + transform: translateX(-50%); + margin-top: 4px; background: #f44; + color: white; padding: 2px 6px; + font-size: 0.75rem; border-radius: 3px; + font-family: ui-monospace, monospace; + white-space: nowrap; pointer-events: none; }
@@ -178,6 +196,7 @@