ltx-2.3-cpu / app.py
Nekochu's picture
Initial LTX 2.3 CPU feasibility Space
ce45d75
raw
history blame
3.48 kB
"""LTX 2.3 CPU Space — feasibility reference + ZeroGPU upgrade recipe.
This Space documents why LTX 2.3 (22B) on free HF CPU is impractical and
shows the upgrade path. Generation is disabled on CPU; the UI mirrors what
a ZeroGPU fork would look like so users can clone and switch hardware in
one click.
"""
from pathlib import Path
import gradio as gr
FEASIBILITY_TABLE = """\
| Hardware | Per 2-sec clip | Notes |
|-----------------------|----------------|-----------------------------------|
| Free CPU (this Space) | not feasible | 22B at Q3_K_M does not fit in 16 GB |
| CPU Upgrade 32 GB | 30-60 min | marginal, $0.30/clip |
| ZeroGPU (Pro) | 25-40 sec | recommended path |
| GPU L40S 48 GB | ~8 sec | dedicated |
"""
PIPELINE_NOTE = """\
**Path A** (used here): Unsloth `distilled-1.1` GGUF Q3_K_M, 10.6 GB DiT + Gemma-3-12B-it Q3_K_M 6 GB encoder. ComfyUI-GGUF loader.
**Path C** (research): 10Eros fine-tune + cond_safe distill LoRA — fine-tune, not distilled. Larger LoRAs harm 10Eros fine-tune; needs tuning.
**Text encoder cannot be swapped** — diffusion U-Net is bound to `google/gemma-3-12b-it`. Only quantisation, not replacement, is valid.
"""
def cpu_generate_stub(prompt: str, duration_sec: float, steps: int) -> str:
return (
"CPU inference is disabled on this free Space — 22B + 16 GB RAM is\n"
"infeasible. Fork to ZeroGPU (see README) to enable generation.\n\n"
f"Prompt received: {prompt[:100]}\n"
f"Duration: {duration_sec:.1f} s\n"
f"Steps: {steps}"
)
def health() -> str:
return "ok — LTX 2.3 CPU Space (documentation mode)"
DEMO_VIDEOS = sorted(str(p) for p in Path("/app/assets/videos").glob("*.mp4"))
with gr.Blocks(title="LTX 2.3 CPU") as demo:
gr.Markdown("**LTX 2.3 CPU** — feasibility reference + ZeroGPU recipe. 22B video diffusion does not run on free CPU; this is a fork-and-upgrade template.")
with gr.Row(equal_height=True):
with gr.Column(scale=1):
prompt_in = gr.Textbox(label="Prompt", placeholder="A woman walking through a neon-lit Tokyo alley at night, cinematic", lines=3)
with gr.Row():
duration_in = gr.Slider(1.0, 4.0, value=2.0, step=0.5, label="Duration (s)")
steps_in = gr.Slider(4, 16, value=8, step=1, label="Steps (distilled)")
run_btn = gr.Button("Generate (disabled on CPU — fork to ZeroGPU)", variant="primary")
status = gr.Textbox(label="Status", lines=5, interactive=False, show_copy_button=True)
with gr.Column(scale=1):
gr.Markdown("### Feasibility")
gr.Markdown(FEASIBILITY_TABLE)
gr.Markdown("### Pipeline")
gr.Markdown(PIPELINE_NOTE)
if DEMO_VIDEOS:
gr.Examples(
examples=[[v] for v in DEMO_VIDEOS],
inputs=[gr.Video(visible=False)],
examples_per_page=6,
cache_examples=False,
label="Reference outputs (pre-generated on GPU)",
)
run_btn.click(fn=cpu_generate_stub, inputs=[prompt_in, duration_in, steps_in], outputs=[status], api_name="generate")
gr.Button(visible=False).click(fn=health, outputs=[gr.Textbox(visible=False)], api_name="health")
demo.queue(default_concurrency_limit=1)
demo.launch(server_name="0.0.0.0", server_port=7860, theme=gr.themes.Soft())