romanbwrk Claude Opus 4.8 commited on
Commit
3aee817
Β·
1 Parent(s): 1520107

Revise spec: LTX-2.3 22B distilled via diffusers, ZeroGPU H200, optional 2x upscale toggle

Browse files
docs/superpowers/specs/2026-06-25-ltx-image-to-video-space-design.md CHANGED
@@ -1,4 +1,4 @@
1
- # LTX Image-to-Video Gradio Space β€” Design
2
 
3
  **Date:** 2026-06-25
4
  **Status:** Approved
@@ -6,90 +6,133 @@
6
 
7
  ## Goal
8
 
9
- A minimal Hugging Face Space where a user uploads an image and types a
10
- prompt, clicks **Generate**, and receives a short MP4 video. Powered by the
11
- LTXV 0.9.x **distilled (2B)** model running on **ZeroGPU**.
 
 
12
 
13
- The referenced project, `WhatDreamsCost/WhatDreamsCost-ComfyUI`, is a ComfyUI
14
- extension built around LTX Video. It is the *inspiration* for the model and
15
- capability only. This Space does **not** run ComfyUI β€” it is a clean, native
16
- Gradio app using the LTX-Video model directly via `diffusers`.
 
 
 
 
 
 
 
 
 
 
17
 
18
  ## Decisions (from brainstorming)
19
 
20
  | Question | Decision |
21
  |----------|----------|
22
- | Relationship to ComfyUI repo | Native Gradio app using the LTX model directly (not ComfyUI) |
23
- | Model variant | LTXV 0.9.x **distilled (2B)** |
24
- | Hardware | **ZeroGPU** (`spaces` package, `@spaces.GPU` decorator, time-budgeted) |
25
- | UI scope | **Minimal** β€” image + prompt + Generate button only |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  ## Architecture
28
 
29
- Single `app.py` with one Gradio `Blocks` UI. The pipeline is constructed once
30
- at module import; the actual generation runs inside a ZeroGPU-decorated worker
31
- function that moves work to the GPU.
32
 
33
  ```
34
  app.py
35
- β”œβ”€ load pipeline (LTXImageToVideoPipeline from diffusers, bf16)
36
- β”œβ”€ @spaces.GPU(duration=120) generate(image, prompt) -> mp4 path
37
- └─ gr.Blocks UI: Image input + Prompt textbox + Generate button -> Video output
38
- requirements.txt (diffusers, transformers, torch, spaces, imageio[ffmpeg])
39
- README.md (already present; keep HF frontmatter unchanged)
 
 
 
40
  ```
41
 
42
- ## Component Details
43
 
44
- ### Model
45
- - `Lightricks/LTX-Video` distilled **2B** variant via the `diffusers`
46
- `LTXImageToVideoPipeline`.
47
- - Precision: `torch.bfloat16`.
48
- - Loaded at module import. GPU placement handled inside the ZeroGPU worker
49
- (ZeroGPU attaches the GPU only during the decorated call).
 
50
 
51
  ### Fixed defaults (hidden from the user)
52
- - Resolution: **768Γ—512**, auto-fit to the uploaded image's aspect ratio,
53
- each dimension rounded to a multiple of 32 (LTX constraint).
54
- - Frame count: **~96 frames @ 24 fps (~4 seconds)**.
55
- - Inference steps: distilled count (~8).
56
- - Guidance: fixed value appropriate for the distilled model.
57
- - Seed: **random each run**.
58
-
59
- ### `generate(image, prompt)`
60
- - Decorated with `@spaces.GPU(duration=120)`.
61
- - Steps: validate inputs β†’ resize/preprocess image to target dims β†’ run the
62
- pipeline β†’ export frames to MP4 (`imageio` / ffmpeg) β†’ return the file path.
63
- - Returns a path to a temporary MP4 for the `gr.Video` output.
64
 
65
  ### UI (`gr.Blocks`)
66
  - `gr.Image(type="pil")` β€” input image.
67
  - `gr.Textbox` β€” prompt.
68
- - `gr.Button("Generate")` β€” triggers `generate`.
69
- - `gr.Video` β€” output.
70
- - Optional: 1–2 `gr.Examples` rows (image + prompt pairs) if example assets
71
- are available.
72
 
73
- ## Error Handling
74
  - Empty image or empty prompt β†’ `gr.Warning`, no generation run.
75
- - Pipeline / OOM / runtime exception β†’ caught and surfaced as a `gr.Error`
76
- with a short human-readable message, so the worker does not crash.
 
 
77
 
78
- ## Out of Scope (YAGNI)
79
- - Negative prompt, sliders, advanced accordion / extra controls.
80
- - ComfyUI runtime, custom nodes, node graph.
81
- - Video editing, timeline, keyframes, audio, IC-LoRA β€” these belong to the
82
- ComfyUI project's scope, not this minimal demo.
83
 
84
  ## Testing
85
  - Diffusion output is not meaningfully unit-testable.
86
  - Validation:
87
- - A `generate()` smoke path with a mocked pipeline (returns dummy frames) to
88
- confirm an MP4 is written and a valid path returned, and that empty-input
89
- guards fire.
90
- - Manual run on the deployed Space to confirm end-to-end behavior on ZeroGPU.
 
91
 
92
- ## Files Touched
93
  - `app.py` (new) β€” the entire application.
94
  - `requirements.txt` (new) β€” Python dependencies.
95
  - `README.md` (existing) β€” unchanged; HF Space frontmatter preserved.
 
 
 
 
 
 
 
 
1
+ # LTX-2.3 Image-to-Video Gradio Space β€” Design
2
 
3
  **Date:** 2026-06-25
4
  **Status:** Approved
 
6
 
7
  ## Goal
8
 
9
+ A Hugging Face Space where a user uploads an image and types a prompt, clicks
10
+ **Generate**, and receives a short MP4 video (with audio). It matches the model
11
+ stack used by the `WhatDreamsCost/WhatDreamsCost-ComfyUI` "LTX Director 2"
12
+ workflow, reimplemented as a native Gradio app using **`diffusers`** β€” not
13
+ ComfyUI.
14
 
15
+ ## Reference workflow
16
+
17
+ Derived from `docs/LTX_Director_2_Workflow_Hotfix.json`. The relevant model
18
+ stack and sampler settings from that graph:
19
+
20
+ | Component | Workflow value |
21
+ |-----------|----------------|
22
+ | Transformer | `ltx-2.3-22b-distilled` (22B distilled, fp8 in the Comfy graph) |
23
+ | Text encoder | Gemma-3-12B (`gemma_3_12B_it`) + LTX text projection |
24
+ | Video VAE | `LTX23_video_vae_bf16` |
25
+ | Audio VAE | `LTX23_audio_vae_bf16` (LTX-2.3 jointly generates audio + video) |
26
+ | Spatial upscaler | `ltx-2.3-spatial-upscaler-x2-1.1` (optional 2nd stage) |
27
+ | Sampler / schedule | euler, linear_quadratic, **8 steps**, **CFG = 1** |
28
+ | Output | **24 fps, 5 s, 120 frames**, two-stage (base β†’ 2Γ— upscale) |
29
 
30
  ## Decisions (from brainstorming)
31
 
32
  | Question | Decision |
33
  |----------|----------|
34
+ | Relationship to ComfyUI repo | Native Gradio app via `diffusers` (not ComfyUI) |
35
+ | Model | **LTX-2.3 22B distilled** (matches the workflow) |
36
+ | Inference library | `diffusers` LTX-2.3 distilled image-to-video pipeline |
37
+ | Hardware | **ZeroGPU** (H200, 70 GB) via `@spaces.GPU` |
38
+ | UI scope | Minimal: image + prompt + Generate, plus one "2Γ— upscale" toggle |
39
+ | Audio | Included (LTX-2.3 generates A/V jointly) |
40
+ | 2Γ— upscale stage | Optional UI toggle, **default OFF** (time-budget safety) |
41
+
42
+ ## Feasibility (verified)
43
+
44
+ - **Inference path:** `diffusers` natively supports LTX-2.3. Use
45
+ `diffusers/LTX-2.3-Distilled-Diffusers` (8 steps, CFG = 1) with the
46
+ image-to-video / IC-LoRA pipeline and the optional two-stage
47
+ generate→upscale recipe. No ComfyUI fp8 safetensors or custom loaders
48
+ required.
49
+ - **VRAM:** ZeroGPU runs on H200 with 70 GB. The 22B distilled is ~46 GB in
50
+ bf16, ~23 GB in fp8; fits in 70 GB alongside Gemma-3-12B with
51
+ `enable_model_cpu_offload()`.
52
+ - **GPU time budget (the real constraint):** ZeroGPU defaults to 60 s per
53
+ call, raised with `@spaces.GPU(duration=...)`, with a hard ceiling and a
54
+ daily quota (longer durations favor PRO). The base 120-frame generation is
55
+ the safe default; the 2Γ— upscale stage is the slow part and is therefore an
56
+ opt-in toggle, default OFF.
57
 
58
  ## Architecture
59
 
60
+ Single `app.py` with one Gradio `Blocks` UI. The pipeline(s) are constructed
61
+ once at module import; generation runs inside a ZeroGPU-decorated worker.
 
62
 
63
  ```
64
  app.py
65
+ β”œβ”€ load diffusers LTX-2.3 distilled pipeline(s) at import
66
+ β”‚ β€’ base image-to-video pipeline (8 steps, CFG=1)
67
+ β”‚ β€’ spatial 2x upscale pipeline (loaded lazily / only used when toggled)
68
+ β”‚ β€’ enable_model_cpu_offload() to fit 70 GB
69
+ β”œβ”€ @spaces.GPU(duration=...) generate(image, prompt, upscale) -> mp4 path
70
+ └─ gr.Blocks UI: Image + Prompt + Upscale checkbox + Generate -> Video
71
+ requirements.txt (diffusers, transformers, torch, spaces, imageio[ffmpeg], ...)
72
+ README.md (existing; HF Space frontmatter preserved)
73
  ```
74
 
75
+ ## Component details
76
 
77
+ ### Models (`diffusers`)
78
+ - LTX-2.3 22B distilled image-to-video pipeline, fp8 where available.
79
+ - Gemma-3-12B text encoder (loaded by the pipeline).
80
+ - Optional `ltx-2.3-spatial-upscaler-x2` pipeline for the 2Γ— stage.
81
+ - `enable_model_cpu_offload()` to stay within 70 GB.
82
+ - Loaded once at module import. GPU placement happens inside the ZeroGPU
83
+ worker (ZeroGPU attaches the GPU only during the decorated call).
84
 
85
  ### Fixed defaults (hidden from the user)
86
+ - Resolution: base resolution per the LTX-2.3 distilled recipe, auto-fit to the
87
+ uploaded image's aspect ratio, each dimension rounded to a multiple of 32.
88
+ - Frames / fps: **120 frames @ 24 fps (~5 s)**.
89
+ - Steps: **8** (distilled). Guidance: **CFG = 1**. Schedule: linear-quadratic.
90
+ - Seed: random each run.
91
+
92
+ ### `generate(image, prompt, upscale)`
93
+ - Decorated with `@spaces.GPU(duration=...)` (set near the ZeroGPU ceiling).
94
+ - Steps: validate inputs β†’ preprocess/resize image to target dims β†’ run base
95
+ image-to-video pipeline β†’ if `upscale` is True, run the 2Γ— spatial-upscale
96
+ stage β†’ mux generated audio β†’ export to MP4 (`imageio` / ffmpeg) β†’ return the
97
+ file path for `gr.Video`.
98
 
99
  ### UI (`gr.Blocks`)
100
  - `gr.Image(type="pil")` β€” input image.
101
  - `gr.Textbox` β€” prompt.
102
+ - `gr.Checkbox("2Γ— high-res upscale", value=False)` β€” opt-in upscale stage.
103
+ - `gr.Button("Generate")`.
104
+ - `gr.Video` β€” output (MP4 with audio).
105
+ - Optional: 1–2 `gr.Examples` rows (image + prompt) if assets are available.
106
 
107
+ ## Error handling
108
  - Empty image or empty prompt β†’ `gr.Warning`, no generation run.
109
+ - Pipeline / OOM / time-limit / runtime exception β†’ caught and surfaced as a
110
+ `gr.Error` with a short human-readable message so the worker does not crash.
111
+ If the upscale stage is the cause, the message suggests retrying with the
112
+ toggle off.
113
 
114
+ ## Out of scope (YAGNI)
115
+ - ComfyUI runtime, custom nodes, node graph, the timeline / Director UI.
116
+ - Video editing, keyframes, retake mode, IC-LoRA style transfer, prompt relay.
117
+ - Negative prompt, extra sliders, manual seed entry, resolution controls.
 
118
 
119
  ## Testing
120
  - Diffusion output is not meaningfully unit-testable.
121
  - Validation:
122
+ - A `generate()` smoke path with a mocked pipeline (dummy frames) confirming
123
+ an MP4 is written and a valid path returned, that empty-input guards fire,
124
+ and that the `upscale` flag selects the right code path.
125
+ - Manual run on the deployed Space to confirm end-to-end behavior, VRAM fit,
126
+ and that the default (no-upscale) path stays within the ZeroGPU time limit.
127
 
128
+ ## Files touched
129
  - `app.py` (new) β€” the entire application.
130
  - `requirements.txt` (new) β€” Python dependencies.
131
  - `README.md` (existing) β€” unchanged; HF Space frontmatter preserved.
132
+
133
+ ## References
134
+ - diffusers LTX-2.3: https://huggingface.co/diffusers/LTX-2.3-Diffusers
135
+ - diffusers LTX-2.3 distilled: https://huggingface.co/diffusers/LTX-2.3-Distilled-Diffusers
136
+ - Lightricks LTX-2.3 weights: https://huggingface.co/Lightricks/LTX-2.3
137
+ - Lightricks LTX-2 inference: https://github.com/Lightricks/LTX-2
138
+ - ZeroGPU docs: https://huggingface.co/docs/hub/en/spaces-zerogpu