Skip to content

Feature/review gate frame capture - #46

Merged
ethanfel merged 7 commits into
ethanfel:mainfrom
Psylenceo:feature/review-gate-frame-capture
Sep 8, 2026
Merged

Feature/review gate frame capture#46
ethanfel merged 7 commits into
ethanfel:mainfrom
Psylenceo:feature/review-gate-frame-capture

Conversation

@Psylenceo

Copy link
Copy Markdown

Summary

  • Adds a "Capture frame..." control to the Review Gate's video preview: scrub to a frame, pick or type a tag, and save it straight into the Project Asset Carousel as a new image asset.
  • Reusing an existing tag (e.g. char-sammy) saves the capture as an updated take with a bare incrementing suffix (char-sammy1, char-sammy2, ...) instead of colliding, so both stay visible in the Carousel.
  • The capture dialog auto-detects the Carousel's actual current project (which can differ from an upstream Plan's run_name) via a small new accessor on the Carousel node, and lets you override it by hand if needed.
  • The Carousel refreshes itself automatically after a successful capture when it's showing the target project, so the new asset shows up without a manual node/page refresh.

Implementation

  • Backend: new POST /minimax_h3_context_loop/project-assets/capture-frame route (chain_nodes.py). Extracts a single frame with ffmpeg using the same -ss/-frames:v pattern as the existing Plan Studio checkpoint-thumbnail builder, then imports it through the existing ProjectAssetStore.import_file() path (same as uploads/imports).
  • project_assets.py: new _capture_family_tag() / ProjectAssetStore.resolve_capture_tag() for the bare-suffix "updated take" numbering, kept separate from the store's existing _unique_tag() (which other flows still use with _2, _3, ... suffixes) so nothing else in the tagging behavior changes.
  • Frontend (web/h3_chain_review_final.js): "Capture frame..." button and a small dialog (frame preview, editable Carousel-project field, tag field with a custom dropdown of existing tags). web/h3_project_asset_manager.js gained a one-line node._h3ProjectAssetCurrentProject accessor so Review Gate can read the Carousel's real project instead of guessing from the Plan.

Test plan

  • Verified the tag-family numbering logic (_capture_family_tag) directly in the project's venv (first reuse -> 1, next -> 2, re-capturing off an already-numbered tag -> next in the family).
  • Exercised the full flow live in ComfyUI: captured a frame from a saved Review Gate segment, picked an existing tag, confirmed it landed in the Asset Carousel under the correct project with the expected incrementing tag, and confirmed the Carousel auto-refreshes.
  • Not tested: multiple simultaneous Review Gate / Carousel node pairs on one canvas (single-canvas, single-pair testing only so far).

Adds a "Capture frame..." control to the Review Gate video preview:
scrub the native player to a frame, pick or type a tag, and save it as
a project asset. Reusing an existing tag appends an incrementing
suffix (via the existing _unique_tag logic) so the new capture is
recognizable as an updated take of a prior image.

Backend: new /project-assets/capture-frame route extracts a single
frame with ffmpeg (same -ss/-frames:v pattern as the Plan Studio
checkpoint thumbnail builder) and imports it through the existing
ProjectAssetStore.import_file path.
The dialog was appended into .h3r-video-panel, which is fixed-height
and overflow:hidden — its title and Save/Cancel buttons were being
clipped off, leaving only the image, tag field, and hint visible.
Anchor it to the widget root instead so it overlays the whole node.
Frame captures reusing an existing tag now read as updated takes of
that subject: @char-sammy -> char-sammy1, then char-sammy2, etc.,
tracking the highest existing suffix in that tag's family. This is
deliberately separate from the store's general _unique_tag() (used by
uploads/imports/duplicates elsewhere), which keeps its "_2", "_3" ...
collision suffix — changing that would ripple into unrelated flows.

The capture dialog's tag field is now a text input paired with a small
dropdown button that reopens the browser's native <datalist> suggestion
list (via showPicker() where supported, a synthetic ArrowDown keydown
otherwise), so existing tags can be picked or a new one typed freely.
Scripted attempts to reopen a <datalist> suggestion popup (showPicker()
fallback, synthetic keydown) don't work in practice — browsers require
a real, trusted user gesture before showing that native UI, so the
dropdown button did nothing visible. Replaced it with a small
self-drawn list (filtered live as you type, click to fill the tag
field) that behaves consistently and stays fully within our control.
The dropdown showing "no tags" with a tag already visible in the
Carousel points at a project-name mismatch (Review Gate defaults the
capture target to the connected Plan's run_name, which may not be the
Carousel project the tag actually lives in) or a silently swallowed
fetch error. Show the resolved project name in the dialog and log
fetch outcomes to the console so this is diagnosable from the browser
devtools instead of guessing blind.
Root cause of the "no tags" report: the capture dialog defaulted its
target project to the connected Plan's run_name, but the Asset
Carousel's project name is independently editable (e.g. Plan run_name
"h3_chain" vs. Carousel project "sammys_house") and can drift from it.

Expose _h3ProjectAssetCurrentProject() on the Carousel node so Review
Gate can read its actual current project directly, preferring an
upstream-connected Carousel and falling back to any Carousel on the
canvas, then to the Plan's run_name only if none exists. The dialog's
project field is now an editable input (not a static readout) so a
wrong guess — or a graph with more than one Carousel — can still be
corrected by hand, and changing it re-fetches that project's tags.
Reuses the Carousel's own node._h3ProjectAssetRefresh() (already called
elsewhere after uploads/imports) instead of requiring a manual page or
node refresh. Only triggers when the on-canvas Carousel is currently
showing the same project the frame was just saved to, since refreshing
a Carousel pointed at a different project would just reload what it
already has.
ethanfel added a commit that referenced this pull request Sep 7, 2026
Integrate PR #46 with safe project targeting, numbered captures, serialized catalog mutations, and nightly ownership fencing. Preserve deferred review and existing catalog recovery checks.

Co-authored-by: Psylenceo <Psylenceo@users.noreply.github.com>
@ethanfel
ethanfel merged commit b2a4969 into ethanfel:main Sep 8, 2026
@Psylenceo
Psylenceo deleted the feature/review-gate-frame-capture branch September 8, 2026 15:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants