feat: add browser-based WebUI for CorridorKey#164
feat: add browser-based WebUI for CorridorKey#164JamesNyeVRGuy wants to merge 9 commits intonikopueringer:mainfrom
Conversation
Code Review — Community ContributionHey @JamesNyeVRGuy, this is a feature-rich PR. The WebUI concept is great for accessibility. I've focused my review on the changes to existing files since those affect all users, not just WebUI users. Changes to existing files1. This is a legitimate fix. PyTorch's 2. This is an additive, backwards-compatible change (default= 3. Clean — 4. Uses a separate 5. Appropriate additions. General observations on the WebUI code (new
|
|
cd65cec to
25c5488
Compare
|
Follow-up review (condensed): I reviewed the existing-file edits in this PR.
Net: the |
shezmic
left a comment
There was a problem hiding this comment.
Reviewed the changes to existing files and the web/api/ backend. Frontend (Svelte) components not reviewed in depth.
NOTE — Depends on #165 and #166 to function
Two bugs exist on main that affect the WebUI:
backend/service.pyline 196:props.total_mem→props.total_memory(fixes VRAM query always returning{}on CUDA; PR #165 addresses this)gvm_core/wrapper.py:process_sequence()doesn't acceptprogress_callbackyet, which causesTypeErroron everyservice.run_gvm()call (PR #166 addresses this)
Both are tracked separately — worth coordinating merge order so the WebUI doesn't land on a broken base.
NOTE — Projects/ and ClipsForInference/ are not the same root
web/api/routes/clips.py uses Projects/ as the clip storage root. The CLI wizard uses ClipsForInference/. A clip set up via the WebUI won't be visible to the CLI wizard and vice versa — they scan different directories. This isn't necessarily wrong (isolated modes can be valid), but it isn't documented anywhere in the PR or the README additions. Users who switch between CLI and WebUI for the same footage will get confused.
Fix: Add a note to the WebUI section of the README clarifying that the WebUI manages clips under Projects/ and the CLI uses ClipsForInference/, and that the two directories are independent.
SUGGESTION — Mac/MLX path not validated
The PR was tested on Linux with NVIDIA GPU (CUDA 12.8) only. The uvicorn non-Docker path (uv run uvicorn web.api.app:create_app --factory --port 3000) should work on Mac, but nothing in the submission confirms it. Specifically: nvidia-smi returns nothing on Mac, which the /api/system/vram endpoint handles correctly (falls back to VRAMResponse(available=False)), but the actual inference path through MLX is untested.
Not a blocker for merging with appropriate documentation, but the README should note that Mac support for the WebUI is not yet validated.
SUGGESTION — web/api/worker.py VRAM check only applies to CUDA
_get_free_vram_gb() in web/api/worker.py returns None if CUDA is not available, and _can_start_gpu_job() returns True when None is returned:
if free is None:
return True # can't check, allow itOn Mac with MLX, this means the VRAM concurrency gate never activates — multiple GPU jobs can be submitted simultaneously with no throttle. For a single-user local tool this is probably fine, but it silently disables the feature for the non-CUDA case. A comment in _can_start_gpu_job() noting that MLX VRAM checking is not yet implemented would prevent confusion.
No no-go zones touched. The web/ code goes through backend.service — it doesn't call inference engines directly.
|
First off, this looks amazing, and would work great with how our computers are set up for the team at Corridor. Merging this into the project now, however, would mean having to also maintain and review all future bug fixes and feature tweaks on the WebUI. I think the best approach would be to run this as a separate project or fork, and if there are any tweaks we need to make to the main branch in order to make it plug-and-play with the WebUI, we can do so. It would make sense to give people the option to download and implement the WebUI as an add-on or a separate version. Are there any efficient changes we would need to make to the main repo here to facilitate that? |
|
I hear you on maintenance scope; that's a fair concern. Both of those small PRs I needed for this to run smoothly already merged though (thank youuuu), so the WebUI now works against main as-is with zero changes to existing code. The practical concern with a separate repo is user friction. Right now someone can clone CorridorKey and run Ideally a GitHub Container Registry image can be published so users don't even need to build. Just pull and run: # docker-compose.yml — no clone or build required
services:
corridorkey-web:
image: ghcr.io/nikopueringer/corridorkey-web:latest
ports: ["3000:3000"]
gpus: all
volumes:
- ./Projects:/app/Projects
- ./CorridorKeyModule/checkpoints:/app/CorridorKeyModule/checkpoints
- ./gvm_core/weights:/app/gvm_core/weights
- ./VideoMaMaInferenceModule/checkpoints:/app/VideoMaMaInferenceModule/checkpoints
# These can point to local paths or network drives (NAS, NFS, SMB, etc.)
# e.g. //server/vfx/projects:/app/ProjectsA CI workflow could auto-publish that image on each release; zero friction for end users. Instant deployment and updates to production. A middle ground: keep it in-tree under If keeping it in-tree doesn't work for you, happy to set it up as its own repo; just let me know. Glad to hear it matches your setup at Corridor! Coming from the film industry myself this is how I would see people using it. If you have any other feature requests or needs please let me know. |
|
Thanks for the additional thoughts and suggestions! What you’re saying makes sense, though I am a bit inexperienced with GitHub’s process so I’ll be pulling in another person or two to help guide me on the best way to implement this. It sounds like you laid out a good approach for maintaining this hand-in-hand with the main repo. Let’s give this some discussion so we can strategize on the best way to get this out to users while keeping the main repo focused on core inference and functionality. |
fc989e6 to
cf48dde
Compare
|
Agreed and understood! I found a small bug for queuing jobs on a single GPU, so I've updated it as well. More than happy to talk thru discussions as need be. Will try to keep this PR up to date with main I will note I setup a GitHub Container Registry image on my fork that depends on this feature branch: This allows it (and the future nodes improvement) to be run on any machine without needing CLI or batch files. |
06483ac to
fe6f441
Compare
|
Updated the PR with fixes from testing and community feedback. Bug fixes:
Improvements:
On the The internal
Other files outside |
Full-stack web interface served via FastAPI + SvelteKit, accessible at localhost:3000 via `docker compose --profile web up -d --build`. Backend (web/api/): - FastAPI app with lifespan management, SPA fallback routing - Clip scanning, detail, deletion, and move-between-projects endpoints - Job submission with full pipeline chaining (extract → alpha → inference) - Parallel worker pool: CPU jobs (extraction) run alongside GPU jobs, configurable VRAM limit for GPU job concurrency - Video upload with auto frame extraction, zip frame/alpha/mask upload - Preview: single-frame PNG (EXR converted on-the-fly), ffmpeg-stitched MP4 video with caching and encode-lock, ZIP download per pass - Project CRUD (create, rename, delete, list with nested clips) - System endpoints: device detection, system-wide VRAM via nvidia-smi, model weight download from HuggingFace, VRAM limit control - WebSocket for real-time job progress, status, VRAM updates Frontend (web/frontend/): - SvelteKit SPA with Svelte 5 runes, adapter-static build - Corridor Digital branding with cinematic dark theme - Project-grouped clip browser with collapsible sections - Drag-and-drop upload, clip moving, right-click context menus - Frame viewer with playback, A/B comparison, per-pass download - Job queue with real-time progress, ETA, expandable error logs - Settings: weight management, auto-extract, VRAM limit, inference defaults - Toast notifications, keyboard shortcuts (?), global activity bar
…ment - README: document that WebUI uses Projects/ while CLI uses ClipsForInference/, and how to unify via CK_CLIPS_DIR - README: note that Mac/MLX WebUI support is not yet validated - worker.py: clarify that VRAM concurrency gate is CUDA-only, MLX unified memory checking not yet implemented
max_gpu_workers defaulted to 2, allowing two GPU jobs (e.g. inference + GVM) to run simultaneously on a single GPU. Since CorridorKey needs ~23GB VRAM and models can't coexist, the second job would force-unload the first mid-processing. Now auto-detects GPU count and sets max_gpu_workers = 1 per GPU. On a single GPU system, GPU jobs run strictly sequentially — the second job queues until the first completes.
The job queue tracked only a single _current_job, so when a second job was claimed (by a remote node or parallel worker), the first disappeared from the UI. Now: - GPUJobQueue uses _running_jobs list instead of _current_job singleton - API returns running: list[Job] alongside current (backward compat) - Frontend runningJobs store tracks all running jobs - Jobs page "RUNNING" section shows all active jobs with count badge - Activity bar shows a progress bar for each running job - Deduplication checks all running jobs, not just one - cancel_all cancels all running jobs - find_job_by_id searches all running jobs
- Dockerfile.web: create /app/Projects owned by appuser before
switching to non-root user
- docker-compose.yml: add user: "${UID:-1000}:${GID:-1000}" to
web service so bind-mounted volumes match host permissions
Auto-refresh: - Clip detail page subscribes to the clips store and re-fetches when the clip's state changes (e.g. job completes via WebSocket) - No more navigating away and back to see new outputs Batch delete: - Right-click a project → "Delete All Clips" removes all clips in the project with confirmation - Clip thumbnails already working (first frame from comp or input)
GZip middleware compresses all HTTP responses > 1KB. Significantly reduces transfer time for PNG frame sequences to remote nodes. Browser push notifications fire when jobs complete or fail, but only when the tab is in the background (document.hidden). Permission requested on first visit.
fe6f441 to
af5ef98
Compare




Full-stack web interface served via FastAPI + SvelteKit, accessible at localhost:3000 via
docker compose --profile web up -d --build.Backend (web/api/):
Frontend (web/frontend/):
Infrastructure:
Existing code changes:
What does this change?
Adds a persistent WebUI that wraps the existing
backend/service layer. Users can manage clips, configure inference, monitor jobs, and preview results from a browser instead of using the CLI wizard. The WebUI is entirely optional — no changes to the CLI workflow. All new code lives inweb/except two small fixes to existing files:backend/service.py—props.total_mem→props.total_memory(attribute renamed in recent PyTorch versions, caused silent VRAM query failures)gvm_core/wrapper.py— addedprogress_callbackparameter toprocess_sequence()so the WebUI can report per-batch GVM progress via WebSocketHow was it tested?
docker compose --profile web up -d --buildon Linux with an NVIDIA RTX 5090 (CUDA 12.8)uv run ruff check web/passesuv run ruff format --check web/passesChecklist
uv run pytestpassesuv run ruff checkpassesuv run ruff format --checkpasses