Spaces:
Running on Zero
Running on Zero
Commit History
-
Merge pull request #1 from techfreakworm/soma/ltx-upscaler-hotfix Running
Unverified signaturefix(models): remap retired x2 spatial upscaler to v1.18ad8791
-
fix(models): remap retired x2 spatial upscaler to v1.1
Unverified signatureLightricks deleted ltx-2.3-spatial-upscaler-x2-1.0.safetensors from the Lightricks/LTX-2.3 repo on 2026-08-10 and the URL now 404s. Every mode sampled to completion, then aborted at LatentUpscaleModelLoader with "Model in folder 'latent_upscale_models' ... not found" and returned an empty video path — the Space broke without a redeploy. The six workflow JSONs are regenerated by tools/extract_modes.py from the user's master export, so editing them would be lost on the next export. load_template is the only reader of workflows/*.json and is upstream of both consumers (the dict handed to PromptExecutor and the walk_workflow_for_models download pass), so the rename map applies there. README's preload_from_hub entry is a build-time fetch and would fail the next deploy while naming a 404 file, so it moves to v1.1 as well.2420cdb
-
Revert "feat(spaces): user-controlled GPU budget slider + pre-flight gate"
Verified signatureThis reverts commit ecc159588e928140424b9f985f7f40d5fbc03157.a2c44d8 -
feat(ui): add Discord community link to tipbar and drawer
Verified signatureTwo entry points for "Chat with the maker on Discord": - Tipbar: appended as a third bullet next to the support / follow row, unobtrusive but persistent. - Drawer: new "Community" section at the bottom with a styled amber-on-slate button (border-brighten + arrow nudge on hover), matching the Topaz Cinema Slate palette. Both open `https://discord.gg/qbn3exeEXa` in a new tab.a5c8e5e -
feat(spaces): user-controlled GPU budget slider + pre-flight gate
Verified signatureThe fixed 240 s ceiling in `_duration_for` was the only thing standing between heavy modes (style, lipsync at high frame counts) and HF Pro+ / credit-topped accounts whose per-call cap actually allows longer durations. Replace it with a per-call budget the user picks, plus a pre-flight gate so jobs that won't fit are refused before submitting — no GPU time wasted after several minutes of compute. - `_duration_for` honours `user_budget` when set; otherwise returns the unclamped estimate (only the 60 s floor remains). - `_estimate_duration_unclamped` helper exposes the formula for the pre-flight diff message in app.py. - GPU-budget slider in the sidebar drawer: 60-1800 s, default 240 s, step 30 s, placed under the mode list for discoverability. - Pre-flight refuses with a friendly diff: "config estimates ~X s, slider is Y s" - user raises the slider or reduces preset/frames. - `illegal_duration` + `gpu_timeout` friendly errors now point at the slider as the first thing to try.…ecc1595 -
feat(spaces): prune output dir before each generation
Verified signatureWithout cleanup, every video lands in `~/comfyui/output/` and stays there until the container restarts. The ephemeral disk is 150 GB and preload already eats ~111 GB, so accumulating generations on the ~39 GB headroom fills the disk and the replica goes unhealthy — observed today as a stuck `RUNNING` Space with `replicas.current=0` and the iframe returning `net::ERR_ABORTED`. Restart cleared it; this prevents the recurrence. 4 h TTL sweep at the top of `_on_generate`. Per-file `OSError` is swallowed so one bad inode can't abort the cleanup. Tests cover older-than-threshold deletion, recent-file retention, recursive descent into ComfyUI's `LTX2.3/` subdir, missing-dir tolerance, and directory preservation.de6853a
-
docs: revamp README + add AGENTS.md + refresh SKILLS.md
Unverified signature- README.md: opensource-style intro with badges, modes table, architecture diagram, project layout, tech stack, design, license + credits (Danielle Falco / FutuTek for the original All-In-One ComfyUI workflow). - AGENTS.md: new tool-agnostic agent rulebook — seven rules, project shape, locked-architecture-decisions table, commit / verification / testing rules, out-of-scope list. - SKILLS.md: cross-refs AGENTS.md from intro; push section now flags the master:main refspec (orphan-branch trap); repo-structure listing includes AGENTS.md.5a81fc9 -
chore(ui): refresh tipbar copy and add @techfreakworm follow link
Unverified signatureAligns with z-image-studio's CTA so the call-to-action wording is consistent across techfreakworm HF Spaces. No styling changes — keeps the existing .aio-tipbar / .aio-heart CSS and class names.c090367
-
feat(ui): add universal 'HF Spaces tip' callout above Generate
Unverified signatureSome setting combinations (Cinematic preset + high resolution + long output) target local hardware and can exceed ZeroGPU's per-call duration cap on HF Spaces, aborting mid-run and burning the user's daily quota with nothing to show for it. Surface this as a low-key gray callout above the Generate button in every mode panel — last visual cue before the user commits to a run. Visual hierarchy: - amber strip on style-mode inputs: 'this mode is intrinsically heavy' - gray strip above Generate (all modes): 'these COMBOS can blow the cap' The two coexist on the style tab — different scopes, complementary.5ff6d0b
-
feat(ui): add style-mode compute-cost warning callout
Unverified signatureStyle Transfer is meaningfully heavier than other modes: it runs DWPose on the entire source clip and concatenates the pose latents into the diffusion attention sequence, so even Fast preset commonly hits ZeroGPU's per-call duration cap on free/anonymous tier — and a failed run still consumes the user's daily Pro quota. Surface this as an amber-accented inline callout inside the Style tab so users on the Space don't burn quota learning this empirically. Recommends HF Pro, resolution <= 1024x576, and source video <= 8s for reliable runs. UI-only change, scoped to the style mode panel. No effect on other modes.3e29eba -
fix(spaces): bump duration cap, drop broken auto-retry, add friendly errors + like banner
Unverified signatureLogs from run #202 (style transfer) confirmed the cascade: 1. style submitted, ran ~127s of GPU time 2. @spaces.GPU(duration=120) cap hit -> 'GPU task aborted' (line 217) 3. our auto-retry fired with the SAME captured request 4. retry's schedule call -> 'Expired ZeroGPU proxy token' (401, line 226) because the captured request's X-IP-Token had aged past TTL during run 1 The visible 'expired token' was the symptom of the abort. Two real bugs: - 120s cap was too tight for style+lipsync detailer paths (~120-180s actual on H200) - auto-retry captured stale request tokens; second attempt always 401'd Fixes: - _duration_for: clamp [60, 240]. Pro identity accepts these; if a server rejects, the user sees a clear illegal_duration error. - _on_generate: drop the for attempt in (0,1) retry. Single attempt; timeout/expired surfaces as a friendly message; user clicks Generate again -> fresh request -> fresh token -> succeeds. - _classify expanded: expired_t…3c69062 -
docs: add item #11 — local style perf / GGUF Q4 toggle
Unverified signatureTrack the architectural mismatch causing ~37x slower per-step style generations on Apple Silicon vs ZeroGPU H200. Root cause is LTXAddVideoICLoRAGuide doubling the attention sequence + no flash-attn-2 on MPS. A GGUF Q4 transformer toggle would mitigate but is v1.1+ scope.b3e0fc9 -
revert: remove hf_oauth and LoginButton (OAuth was a misdiagnosis)
Unverified signatureThe original 'GPU quota exceeded' issue turned out to be a contextvar propagation bug in our worker thread, not a Pro-attribution issue. ZeroGPU reads identity from the X-IP-Token header that HF's reverse proxy sets from the standard huggingface.co cookie — completely independent of OAuth. Once 1e054fe propagated the Gradio request contextvar to the worker thread, attribution worked without OAuth. Removing the unused machinery: - README hf_oauth: true -> false - README hf_oauth_expiration_minutes (delete) - app.py: drop the gr.LoginButton + Account section in the drawer If we ever want per-user features (gr.OAuthProfile for logging the generating user, gr.OAuthToken for HF API calls on their behalf), re-enable both at that time.12ca777 -
fix(spaces): clamp _duration_for to 120s (ZeroGPU per-call hard max)
Unverified signatureAfter fixing the contextvar propagation in 1e054fe, requests now reach the scheduler with the user's X-IP-Token. The next failure mode surfaced: ZeroGPU illegal duration (raised at spaces/zero/client.py:137 when res.wait < timedelta(0) from the scheduler) The server enforces a per-call duration cap of 120s on the standard ZeroGPU tier, regardless of the user's remaining daily quota. Our _duration_for was clamping to 900s which the scheduler rejected for any preset+mode combination above ~2 minutes of estimated work. Drop the ceiling to 120s. On H200 every preset we ship completes well under that; longer requested durations just fail the guard check before any GPU is attached.444a596 -
fix(spaces): propagate Gradio request contextvar to GPU worker thread
Unverified signatureReal root cause of 'Space app has reached its GPU limit. Try re-running outside of examples' (raised after a few gens, while the user dashboard still shows 0/25 minutes used). ZeroGPU's @spaces.GPU wrapper reads the user's identity from the current Gradio request via gradio.context.LocalContext.request — a contextvar. The wrapper at spaces/zero/wrappers.py:187 does: request = request_var.get(None) schedule_response = client.schedule(task_id, request=request, ...) Then spaces/zero/client.py:_get_token_and_payload reads X-IP-Token from the request headers (set by HF's reverse proxy when the user is signed into huggingface.co). If the token is None, client.schedule:138 raises the 'Space app has reached its GPU limit' message and falls back to the per-Space anonymous rate limit — which exhausts after a few calls. Our backend ran _execute_workflow from a plain threading.Thread for the event-streaming pattern. Python threads don't inherit contextvars, so inside the worker the req…1e054fe -
fix(spaces): _duration_for must accept progress kwarg to match _execute_workflow
Unverified signatureZeroGPU calls the duration estimator with the same args it'll pass to the @spaces.GPU function. After adding progress as the 7th arg to _execute_workflow in 27ffbbc, _duration_for raised TypeError on every generation. Add progress to its signature; we ignore it for estimation.0a98b65 -
docs(skills): use cat ~/.cache/huggingface/token (hf auth token removed)
Unverified signature10af3aa -
feat(spaces+style): hf_oauth + gr.Progress + style 2-input + DWPose deps
Unverified signatureSpaces — Pro quota attribution: enable hf_oauth in README YAML and add a gr.LoginButton in the drawer (rendered only when OAUTH_CLIENT_ID is set, so local dev stays clean). Without OAuth the Space scheduler bucketed Pro users as signed-in/free (300s/day), causing "GPU quota exceeded" errors after a few generations while the profile dashboard still showed 0/25 used. Spaces — progress bar through @spaces.GPU subprocess: thread a gr.Progress instance from _make_handler -> _on_generate -> backend.submit -> _execute_workflow. The existing event-based ProgressEvent flow can't cross the @spaces.GPU subprocess boundary on Spaces (asyncio.run_coroutine_threadsafe targets the parent loop the subprocess never inherits). gr.Progress is the only progress channel ZeroGPU's IPC wraps. Inside _execute_workflow, install a ComfyUI PROGRESS_BAR_HOOK that calls progress(v/t, desc=...) and chains to the prior hook so the local event-driven status banner keeps working. Style mode — actually use the upload…27ffbbc -
docs: rewrite CLAUDE.md with Spaces lessons + add SKILLS.md process guide
Unverified signatureCLAUDE.md (heavily updated): - Spaces deployment specifics: preload_from_hub + cache mirror, allowed_paths, HF widget z-index coexistence, dynamic ZeroGPU duration + auto-retry, history_result-across-subprocess gotcha, custom node pinning - New section on Gradio scoping facts (CSS prefix, script stripping, z-index 40 baseline) - Per-mode behavior summary - Common pitfalls section restructured by area (ComfyUI/models, Gradio/UI, Spaces, authoring) SKILLS.md (new): - Process rules: investigate before fix, Playwright before patch, web-search literal errors, sequential-thinking on 2nd failed fix - Verification: local before push, smoke tests, isolated function tests - Run/stop the local server, get LAN IP for WiFi testing - Push lifecycle and when not to push - Spaces deploy lifecycle - Memory entries (cross-session preferences) - Useful one-liners for stage/sha/registry auditsc3b8732
-
feat(spaces): dynamic ZeroGPU duration + auto-retry on timeout
Unverified signatureTier 1 — dynamic duration estimator: @spaces.GPU(duration=callable) where the callable receives the same args as _execute_workflow and returns int seconds. Estimate from (mode, preset, frames) with per-mode base (t2v 90s, lipsync 240s, style 360s, etc.), preset multiplier (fast 1×, balanced 1.5×, quality 3×), +60s cold-cache buffer, +0.3s/frame VAE decode. Clamped to [60s, 900s]. Effect: light T2V calls reserve ~190s and jump the ZeroGPU queue; heavy lipsync/style calls reserve real headroom only when needed. No more one-size-fits-all 300s/600s wall. Tier 2 — auto-retry on timeout: ErrorEvent.category 'gpu_timeout' is now distinguished from generic execution errors via _classify (matches "GPU task aborted" in the exception message). The _on_generate handler catches this on the first attempt only, shows a friendly "Retrying with extended budget" banner, then re-submits with duration_multiplier=2.0 (which clamps to the same 900s ceiling). One retry — if that…14dcc06
-
fix(spaces): bump @spaces.GPU duration 300s → 600s
Unverified signatureLipsync hit GPU task aborted exactly at the 300s wall. The workflow runs: init/load (~3 min on cold cache) + sampler 1 (~50s) + sampler 2 (~30s) + VAE decode + ffmpeg audio-mux. Total ran 305s — killed mid-mux just as the video was about to land on disk. The duration param is a timeout, not a billing cap (HF bills actual usage). Bumping to 600s (10 min) gives heavy modes — lipsync, future keyframe and style transfer with bigger workflows — headroom on cold caches without affecting lighter T2V calls (those still finish in ~30s and release the GPU back to the pool immediately).d3e4302 -
feat(spaces): mirror build-time HF cache to runtime-writable tree
Unverified signaturepreload_from_hub populates ~/.cache/huggingface/ as the build user, leaving it read-only for runtime uid 1000. Lazy hf_hub_download calls for non-preloaded files (GGUF, camera LoRAs) failed with "Permission denied". chmod couldn't help — wrong inode owner. _mirror_preload_hf_cache() walks the preload tree once at bootstrap, building a parallel ~/hf-cache-rw/ that we own: - blobs/<sha>: hardlinked (zero-copy, shared inode, instant reads). Falls back to symlink on EXDEV (cross-device). - snapshots/<commit>/<file>: relative symlinks preserved. Targets resolve within the mirror tree, no extra walking. - refs/<branch>: byte-copied — HF lib overwrites these on etag check, hardlinks would fail there. - everything else: byte-copied (safest default for unknown files). Sets HF_HOME + HF_HUB_CACHE so HF lib reads/writes through the mirror. After this: - preloaded files: instant cache hit (no network) - new lazy downloads: write to dirs we created → no permission errors Tested locally on…14fcab5 -
fix(ui): mode-button auto-close also resets hamburger ≡ + aria-expanded
Unverified signatureaf37c06 -
fix(ui): conditional header z-index — z-15 default, z-60 only when drawer open
Unverified signatureHF injects #huggingface-space-header at fixed z-index 20 in the top-right of the iframe (the heart/share widget). Our .aio-header was z-60 always, covering it. Lower default to z-15; bump to z-60 via .drawer-elevated class only while the drawer overlay is up. JS toggles `.drawer-elevated` on .aio-header in lockstep with `.drawer-open` on .aio-shell — three call sites: hamburger onclick, document click-outside dismisser (in <head>), and the mode-button auto-close. Hamburger × stays clickable when drawer is open; HF widget visible when it's closed.5a2e5ec -
fix(spaces): three runtime fixes — input staging dir, walker, cache perms
Unverified signature1. _COMFY_INPUT_DIR was hardcoded to <repo>/comfyui/input — fine locally but on Spaces ComfyUI lives at ~/comfyui, so user uploads were being staged to a directory ComfyUI never reads from. Mirror the bootstrap logic so the staging dir matches comfy_dir on each platform. 2. walk_workflow_for_models() was returning every filename mentioned in Power Lora Loader rows, including those with on:false. ensure_models then tried to download those (camera LoRAs) at runtime which failed noisily and pointlessly. Skip rows whose on flag is falsy. 3. After preload_from_hub bakes ~111 GB into ~/.cache/huggingface/, that directory tree's permissions can block runtime hf_hub_download writes (xet log dir, blob targets). chmod -R u+rwX in bootstrap so any model NOT covered by preload (the GGUF, conditional LoRAs) can still lazy-download. Failure to chmod is non-fatal.b348d5e -
fix(spaces): drop 123 GB of unused preload (storage cap was 150 GB)
Unverified signatureHF evicted the workload at first deploy with "storage limit exceeded (150G)" — total preload was ~234 GB. Trimming to fit: - Drop ltx-2.3-22b-dev.safetensors and ltx-2.3-22b-distilled.safetensors from Lightricks/LTX-2.3 (84 GB combined). Neither is referenced by any workflow JSON we ship; the active transformer path uses the Kijai bf16 variant. - Drop the unsloth/LTX-2.3-GGUF entry entirely (39 GB). Only used by a hypothetical low-VRAM preset that we don't currently route. New total: ~111 GB. Marks future_improvements items 1 and 2 done.c53ac67 -
fix(spaces): trim preload_from_hub to 10 entries (HF cap) + future-work doc
Unverified signatureHF caps preload_from_hub at 10 entries; we had 16 → Configuration error. Dropped the 6 lightest entries (4 Dolly camera LoRAs at ~0.30 GB each, Motion-Track IC-LoRA at 0.30 GB, Pose-Control IC-LoRA at 0.61 GB). Those still lazy-download on first use of their respective modes. Captured deeper optimizations (drop unused 84 GB Lightricks-side transformer preload, drop GGUF, auto-sync README<->registry, etc.) in docs/future_improvements.md for follow-up rather than bundling here.099a5f3 -
feat(spaces): preload_from_hub bakes models into image at build time
Unverified signatureAdds the YAML directive to README so HF's build pipeline pre-downloads all 80 GB of models into the Docker image's HF cache before the app starts. Net effect: - Models persist across container restarts AND redeploys (cached image) - Available at app startup, not on first inference (UX win) - $0 extra cost (uses Pro's existing build infrastructure) - Compatible with sdk: gradio so ZeroGPU still works (Docker SDK would break ZeroGPU) - Code-only pushes don't re-run the preload step (cache layer keyed on README content) Tradeoff: first push triggers a one-time ~20-30 min build while HF's internal infra fetches 80 GB. Subsequent code pushes are fast.7bdb311 -
fix(spaces): add ComfyUI-MediaMixer custom node
Unverified signatureLipsync mode crashed with KeyError: 'FinalFrameSelector' on Spaces. That class lives in DoctorDiffusion/ComfyUI-MediaMixer (I'd mis-attributed it to KJNodes during the earlier audit). Adding the pack to CUSTOM_NODES_PINNED at the SHA mirroring the working local install.db02171
-
fix(backend): compute video path inside @spaces.GPU + filesystem fallback
Unverified signatureexecutor.history_result wasn't surviving ZeroGPU's GPU-context wrap reliably — sampler completed and files were written to disk, but the parent process saw an empty history_result, so the OutputEvent's video_path was "" and the gr.Video output stayed blank. Two changes: 1. _execute_workflow now reads history_result and returns the video path inline (a plain str pickles cleanly across the boundary). 2. If that still returns "", _newest_recent_video scans the output dir for the newest mp4/webm/mov modified in the last 60 s — files are on shared disk so they're visible from the parent regardless of how ZeroGPU isolates state. Also adds a "[backend] workflow done; video_path=..." log line so the next time this hiccups we see where the chain breaks.e8627ee -
fix(ui): allowed_paths includes ComfyUI output dir so generated videos display
Unverified signatureGradio 5 refuses to serve files outside cwd/tempdir/allowed_paths. On Spaces, ComfyUI writes to ~/comfyui/output/ which is outside the app cwd, causing InvalidPathError on first Generate. Whitelist the output directory at launch and pre-create it so cold-start mkdir never races.ebc9cea -
fix(ui): drawer top padding clears header + scroll instead of clip on overflow
Unverified signature2e44e41 -
fix(ui): bump drawer/scrim/header z-index above Gradio's z-index:40 labels
Unverified signaturee113b13 -
fix(ui): move drawer dismisser to gr.Blocks head= + opaque scrim
Unverified signature0853bf6 -
fix(ui): click-outside dismisses drawer + darker scrim with blur + ≡⇄× affordance
Unverified signature337d12c -
fix(ui): drawer toggle via JS class-flip — Gradio CSS scope breaks :has()
Unverified signature6bd9581 -
fix(ui): drawer slides via left, not transform, to avoid containing-block weirdness
Unverified signature00814ae -
fix(ui): drawer + scrim use position: fixed on mobile so they anchor to viewport
Unverified signature630b298 -
fix(ui): cleanups from Task 2 code review (selector id, font stacks, base display)
Unverified signature49da39f -
feat(ui): mode tag updates + auto-close drawer on mobile select
Unverified signature666a16c -
feat(ui): drawer markup + header (hamburger / title / mode tag)
Unverified signaturec726478 -
fix(ui): css cleanup — id selector, font stacks, drawer base display
Unverified signature5a26e1f -
feat(ui): rewrite _CUSTOM_CSS for Topaz palette + drawer mechanics
Unverified signature3fab083 -
fix(ui): correct neutral_hue c300 from olive (#909700) to slate (#9097A0)
Unverified signature1a16457 -
feat(ui): apply Topaz Cinema Slate theme tokens
Unverified signature04f17ac -
docs: implementation plan for Topaz Cinema Slate + drawer redesign
Unverified signatureed3abc0 -
fix(models): walker recurses into Power Lora Loader nested dict + spatial upscaler comfy_type
Unverified signatureTwo issues surfaced when models actually downloaded but the workflow still failed at execution: 1. walk_workflow_for_models was a flat values() loop — Power Lora Loader stores rows as inputs.lora_1 = {on, lora, strength} (nested dict), so ltx-2.3-22b-distilled-lora-dynamic_fro09_avg_rank_105_bf16.safetensors was never returned to ensure_models. Recurse through dicts/lists. 2. ltx-2.3-spatial-upscaler-x2-1.0.safetensors was registered with comfy_type="upscale_models" but ComfyUI core's LatentUpscaleModelLoader reads from "latent_upscale_models" — same filesystem prefix, different folder. Fix the registry to match.8b4f49e -
fix(models): subfolder= on Kijai VAE/text-encoder entries
Unverified signatureKijai/LTX2.3_comfy keeps its files in vae/, text_encoders/, etc. The three entries missing subfolder= were 404ing on hf_hub_download. The exception fallback then rglobbed the cache and matched HF's .no_exist/ marker stubs — 0-byte files. Symlinking those to comfyui/models/vae/ left ComfyUI loading a 0-byte safetensors which crashes with "Error while deserializing header: header too small". Also harden the fallback to skip .no_exist/ paths and any file under 64 bytes so this class of stub-induced corruption can't recur.e168977 -
docs: spec for Topaz Cinema Slate palette + drawer layout
Unverified signaturefc74e8b -
fix: include Sway Dance seed video in deploy
Unverified signature*.mp4 was matching the seed-input placeholder. Add the assets/seed_inputs exception in .gitignore and stage the missing file so VHS_LoadVideo on Spaces stops warning about /home/user/comfyui/input/Sway Dance Lesson 31s.mp4 not found.33862a6