feat(examples): vllm-video-studio — a standalone browser console for MiniMax-H3 - #291
feat(examples): vllm-video-studio — a standalone browser console for MiniMax-H3#291localai-bot wants to merge 3 commits into
Conversation
…MiniMax-H3
Driving three modalities from curl means hand-writing JSON and, for fl2va and
ref2va, producing a binary PPM at exactly the output resolution first. This is a
console that does both, plus a job queue and playback.
DELIBERATELY ITS OWN BINARY. The first attempt put this in examples/server and
grew the shared library to serve it (a static mount, engine-lifecycle routes).
That was wrong twice over: examples/server is the OpenAI-compatible API surface
and a browser console does not belong in it, and adding library surface for one
consumer's benefit is exactly what ARCH-ONE-SURFACE exists to stop. The API
server and api_server.{h,cpp} are untouched by this change.
It is a THIN CLIENT of the public C ABI -- `vllm.h` and nothing from the internal
tree. Loading a checkpoint, generating, swapping the loaded weights and building
the ffmpeg argv are all ABI calls, which is the point: everything the console can
do, an FFI consumer can do. The one process spawn (ffmpeg) lives here rather than
in the library, matching the ratified boundary.
Three things the engine's shape dictated:
* The browser converts images. Reference frames must be binary PPM (P6) AT the
output geometry and no codec or resampler is vendored, so the page resamples
in a canvas (cover-fit, centre-crop, so an odd aspect ratio never letterboxes
black into the conditioning) and posts a data: URL.
* The LEDGER is the interface, not the form. A render is 13 minutes to 2.5
hours, so what matters is live elapsed time, a step-rate ETA, and jobs kept in
localStorage because a render outlives the tab.
* Renders are SERIALISED, one at a time. These checkpoints are tens of GB
resident and this class of box OOMs -- and an OOM here takes the machine
down, not just the request.
Checkpoint swapping needs no library change: vllm_video_engine_free +
vllm_video_engine_load were already on the ABI. UNLOAD HAPPENS FIRST, so the old
weights are never held while the new ones are built; a failed load leaves nothing
loaded and says so rather than quietly serving the partition the caller just
asked to leave.
VERIFIED LIVE on a real build, not just compiled: `GET /` returns 200 and 16,567
bytes of the console, `/api/engine` reports {"loaded":false} with no --dit,
`/api/jobs` returns [], and startup logs "no --dit; load one from the console".
No shell is used for paths (std::filesystem) and none for the mux (fork/execvp on
the library-built argv).
FOLLOWING_AGENTS_PROTOCOL
Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: ClaudeCode:claude-opus-5 [ClaudeCode]
… — all found by using it
Four rounds of fixes from actually driving the console on the GPU box, each of
which the earlier "it serves 200 OK" verification could not have caught.
DISCOVERY, not a path field. --models-dir scans a directory and /api/models
offers what is on disk, with size and partition. The partition is GUESSED from
the filename because a community GGUF strips the release metadata and the two
partitions are byte-structurally identical -- there is nothing in the file to
read. When the guess fails the card says so LOUDLY and names which partition it
will be loaded as, because the alternative is discovering the mistake after a
25-minute load. The Qwen encoder is filtered out: it is a .gguf in the same
folder that cannot render.
A WIZARD, because the decisions constrain each other. Task -> checkpoint (only
those that can serve it, and whether a swap is needed) -> prompt and image ->
size, with real time estimates per preset. The flat form asked everything at once
and let a user assemble a combination that could not work. Step one is phrased by
intent ("Starting from my image") with the task name demoted to a tag.
THE DOCS PALETTE. website/assets/css/site.css, verbatim: teal #0f7f96, warm
paper, Iowan Old Style, and the same dark-mode set. The first version invented an
unrelated amber palette, which made the console look like a different project.
A RESULT VIEW, and a ledger that updates IN PLACE. The list rebuilt itself from
innerHTML every second, which destroyed and recreated the <video> element under
the player each tick -- playback could not survive long enough to start. Rows are
now created once and only their clock, status and dot are touched; a finished
render opens its own view with the player, the prompt, the real render time and a
download. One delegated click listener rather than per-row handlers, since
re-binding to rows that get rewritten was part of the same churn.
Also: .pick set `font:inherit` but no `color`, so the card titles fell back to
the UA default black and vanished against dark paper. `font` carries the font,
never the colour. Audited every other control for the same omission; it was the
only one.
VERIFIED ON THE BOX, main @ f323907 with the four real checkpoints: all four
discovered with correct partitions, the pruned Q8 swap that previously failed now
loads in 52 s (the AdaLN curve form drops the DiT from 33.12B to 20.11B, so there
is far less to dequantise), and the UI serves from disk per request, so a fix
lands on reload without restarting or reloading weights.
FOLLOWING_AGENTS_PROTOCOL
Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: ClaudeCode:claude-opus-5 [ClaudeCode]
This branch was behind main and its CI red was stale-base rather than defects. The clearest tell was documentation-checkpoint demanding STATUS, BENCHMARKS **and NOW** -- the pre-#374 lifecycle triple. NOW.md left that triple when the live position became derived, so the branch was being judged against a rule that no longer exists. Merged cleanly, no conflicts. check-agent-record, check-doc-checkpoint, check-now-current and check-public-doc-tables green on the merged tree. Amended: the first attempt at this merge kept git's default message and therefore carried no trailers at all, which reds the trailer gate. `git merge` had already created the commit, so the `git commit -F` that was meant to supply the message was a no-op against an empty index -- and its failure was invisible because the output was silenced. Message supplied here by amend. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
e4ab023 to
34c6b84
Compare
…r console (#291) Lands the work from PR #291, rebuilt on current main. A standalone browser console for MiniMax-H3, deliberately SEPARATE from the OpenAI-compatible API server: examples/server is the API surface and a UI does not belong in it. The studio owns its own endpoints and drives the public C ABI (vllm_video_*) like any other FFI consumer, which makes it a worked example of that ABI as much as a tool. Three things were wrong with the branch, and only the first was cosmetic. Its own two commits carried malformed trailers -- FOLLOWING_AGENTS_PROTOCOL glued to Assisted-by with no blank line between them, both Following-Agents-Protocol and AI-Assisted missing, and an Assisted-by identity with a space before the colon that the format cannot parse. Repaired; content byte-identical. check-doc-checkpoint refused it for adding a user-facing executable without documenting it, and that was a REAL gap rather than the stale-base artifact the other reds turned out to be. A browser console anyone can run is exactly what USAGE.md exists to describe. Because that gate is PER COMMIT, a later fix commit could not satisfy it, so the branch is squashed to one commit carrying the example and its documentation together. Most seriously, the branch's tip reverted main's `.scale(0.0)` strengthening in tests/vllm/test_hf_config.cpp and test_gguf_qwen36_loader.cpp -- a stale-base artifact, since main tightened those assertions after the branch last merged. That revert is DROPPED. The comment it would have deleted records why the strengthening matters: a bare doctest::Approx(1e-6) carries an absolute tolerance of ~1.19e-5 and therefore accepts any eps below it, including the 1e-05 the same file uses for another family, verified by mutation. Landing the branch as it stood would have silently weakened a test that was deliberately made strict. Gate: scripts/agent-preflight.sh rc=0 on the row branch. CI is queue-blocked (#274) -- recent runs are queued or cancelled -- so the operator's own gate run is the authority, as AGENTS.md prescribes. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [Claude Code]
|
Landed on Three things needed fixing, and only the first was cosmetic:
Gate: |
Supersedes #286, which put this in
examples/server.Driving three modalities from
curlmeans hand-writing JSON and — for fl2va and ref2va — producing a binary PPM at exactly the output resolution first. This is a console that does both, with a job queue and playback.Why it is its own binary
My first attempt put the UI in
examples/serverand grew the shared library to serve it (a static mount, plus engine-lifecycle routes onApiServer). That was wrong twice over:examples/serveris the OpenAI-compatible API surface and a browser console doesn't belong in it, and adding library surface for one consumer's benefit is exactly what ARCH-ONE-SURFACE exists to stop.The API server and
api_server.{h,cpp}are untouched by this change.It's a thin client of the public C ABI —
vllm.hand nothing from the internal tree. Loading, generating, swapping weights, building the ffmpeg argv: all ABI calls. Everything the console can do, an FFI consumer can do.Three things the engine's shape dictated
data:URL.localStoragebecause a render outlives the tab.Checkpoint swapping, with no library change
vllm_video_engine_free+vllm_video_engine_loadwere already on the ABI. Unload happens first, so the old weights are never held while the new ones are built; a failed load leaves nothing loaded and says so, rather than quietly serving the partition you just asked to leave.Verified live
No shell for paths (
std::filesystem) and none for the mux (fork/execvpon the library-built argv).Usage
--ditis optional: start bare and load a checkpoint from the console.