linoyts HF Staff commited on
Commit
e451b04
·
verified ·
1 Parent(s): a418dac

ingredients rename + multi-image sheet builder + real example sheets/clips

Browse files
.gitattributes CHANGED
@@ -35,3 +35,7 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  examples/sheet_camping.jpg filter=lfs diff=lfs merge=lfs -text
37
  examples/sheet_woman_horse.jpg filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  examples/sheet_camping.jpg filter=lfs diff=lfs merge=lfs -text
37
  examples/sheet_woman_horse.jpg filter=lfs diff=lfs merge=lfs -text
38
+ examples/sheet_garden.png filter=lfs diff=lfs merge=lfs -text
39
+ examples/sheet_hiker.png filter=lfs diff=lfs merge=lfs -text
40
+ examples/subj_horse.jpg filter=lfs diff=lfs merge=lfs -text
41
+ examples/subj_woman.jpg filter=lfs diff=lfs merge=lfs -text
app.py CHANGED
@@ -1,9 +1,9 @@
1
  import os
2
 
3
- # ZeroGPU: torch.compile / dynamo are unsupported — disable before torch import.
4
  os.environ.setdefault("TORCH_COMPILE_DISABLE", "1")
5
  os.environ.setdefault("TORCHDYNAMO_DISABLE", "1")
6
 
 
7
  import random
8
  import tempfile
9
 
@@ -11,7 +11,7 @@ import numpy as np
11
  import spaces
12
  import torch
13
  import gradio as gr
14
- from PIL import Image
15
  from huggingface_hub import hf_hub_download
16
  from safetensors.torch import load_file
17
 
@@ -21,7 +21,7 @@ from diffusers.pipelines.ltx2.utils import DISTILLED_SIGMA_VALUES
21
  from diffusers.utils import encode_video
22
 
23
  # --- Config -----------------------------------------------------------------
24
- # FAST distilled variant of the reference-sheet IC-LoRA: 8-step schedule, CFG off.
25
  BASE_MODEL = "diffusers/LTX-2.3-Distilled-Diffusers"
26
  LORA_REPO = "linoyts/LTX-2.3-loras"
27
  LORA_FILE = "ltx-2.3-22b-ic-lora-ingredients-0.9" # no .safetensors extension in the repo
@@ -33,17 +33,39 @@ NUM_STEPS = len(DISTILLED_SIGMA_VALUES) # 8
33
  MAX_SEED = np.iinfo(np.int32).max
34
  HF_TOKEN = os.environ.get("HF_TOKEN")
35
 
36
- # --- Load pipeline once at module scope (ZeroGPU registers it) ---------------
37
  pipe = LTX2InContextPipeline.from_pretrained(BASE_MODEL, torch_dtype=torch.bfloat16)
38
  pipe.to("cuda")
39
  pipe.vae.enable_tiling()
40
-
41
  _lora_path = hf_hub_download(LORA_REPO, LORA_FILE, token=HF_TOKEN)
42
- pipe.load_lora_weights(load_file(_lora_path), adapter_name="refsheet")
43
- pipe.set_adapters("refsheet", LORA_SCALE)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
 
46
- # --- Helpers ----------------------------------------------------------------
47
  def _build_prompt(sheet, action):
48
  return f"Reference sheet: {sheet.strip()}\n\nGenerated video: {action.strip()}"
49
 
@@ -59,14 +81,12 @@ def _duration(*args, **kwargs):
59
  return 200
60
 
61
 
62
- # --- Inference --------------------------------------------------------------
63
  @spaces.GPU(duration=_duration)
64
- def generate(image, sheet, action, lora_scale, seed, randomize,
65
- progress=gr.Progress(track_tqdm=True)):
66
- if image is None:
67
- raise gr.Error("Please upload a reference sheet image.")
68
  if not sheet.strip():
69
- raise gr.Error("Describe the panels in the reference sheet (characters, props, location).")
70
  if not action.strip():
71
  raise gr.Error("Describe the action / shot you want generated.")
72
 
@@ -74,9 +94,10 @@ def generate(image, sheet, action, lora_scale, seed, randomize,
74
  seed = random.randint(0, MAX_SEED)
75
  seed = int(seed)
76
 
77
- sheet_img = image.convert("RGB").resize((WIDTH, HEIGHT), Image.LANCZOS)
 
78
  ref = [sheet_img] * NUM_FRAMES
79
- pipe.set_adapters("refsheet", float(lora_scale))
80
  prompt = _build_prompt(sheet, action)
81
 
82
  def _cb(p, i, t, kw):
@@ -84,8 +105,7 @@ def generate(image, sheet, action, lora_scale, seed, randomize,
84
  return {}
85
 
86
  video_out, audio_out = pipe(
87
- prompt=prompt,
88
- negative_prompt="",
89
  reference_conditions=[LTX2ReferenceCondition(frames=ref, strength=1.0)],
90
  reference_downscale_factor=1,
91
  width=WIDTH, height=HEIGHT, num_frames=NUM_FRAMES, frame_rate=FPS,
@@ -94,24 +114,24 @@ def generate(image, sheet, action, lora_scale, seed, randomize,
94
  generator=torch.Generator(device="cuda").manual_seed(seed),
95
  output_type="np", return_dict=False, callback_on_step_end=_cb,
96
  )
97
-
98
  out_path = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False).name
99
  _export(video_out[0], audio_out, out_path)
100
  return out_path, seed
101
 
102
 
103
- # --- UI ---------------------------------------------------------------------
104
- with gr.Blocks(title="LTX-2.3 Reference Sheet (Fast / Distilled)") as demo:
105
  gr.Markdown(
106
- "# ⚡ LTX-2.3 Reference-Sheet Control — Fast (Distilled)\n"
107
- "Same reference-sheet IC-LoRA on the **distilled** checkpoint with an 8-step schedule for fast "
108
- "generation. Supply a composite reference sheet (characters / props / location) and an action prompt; "
109
- "optionally describe the soundscape for generated audio. For maximum fidelity use the non-distilled demo. "
110
  "IC-LoRA: [`linoyts/LTX-2.3-loras`](https://huggingface.co/linoyts/LTX-2.3-loras)."
111
  )
112
  with gr.Row():
113
  with gr.Column():
114
- image_in = gr.Image(type="pil", label="Reference sheet (one clean panel per element, black background)")
 
 
115
  sheet = gr.Textbox(label="Reference sheet description", lines=3,
116
  placeholder="a young woman with red hair in a green jacket (face close-up + turnaround); a brass pocket watch; a cobblestone alley at night")
117
  action = gr.Textbox(label="Generated video — the action / shot, plus any speech & sounds", lines=3,
@@ -125,25 +145,25 @@ with gr.Blocks(title="LTX-2.3 Reference Sheet (Fast / Distilled)") as demo:
125
  video_out = gr.Video(label="Generated video")
126
  used_seed = gr.Number(label="Seed used", interactive=False)
127
 
128
- run.click(generate, inputs=[image_in, sheet, action, lora_scale, seed, randomize],
129
- outputs=[video_out, used_seed])
130
 
131
  gr.Examples(
132
  examples=[
133
- ["examples/sheet_camping.jpg",
134
- "a young child in a yellow raincoat beside a golden retriever dog (large left panel); a cluster of small orange camping tents in a green field (top right); misty green mountains over a calm lake (bottom right)",
135
- "the child and the golden retriever walk together across the grassy field toward the tents at dawn, gentle handheld camera, soft morning light; happy dog panting and a soft bark, a child giggling, birdsong and a gentle breeze",
136
  1.4, 42, False],
137
- ["examples/sheet_astronaut.jpg",
138
- "an astronaut in a white spacesuit holding the helmet under one arm (large left panel); a vast misty mountain landscape over still water (right panel)",
139
- "the astronaut walks slowly across the misty shoreline, looking around in wonder, slow cinematic dolly-in; crunching footsteps on wet gravel, low wind, soft breathing and a whispered 'incredible'",
140
  1.4, 42, False],
141
- ["examples/sheet_woman_horse.jpg",
142
- "a smiling young woman with curly dark hair in a light top (large left panel); a dappled grey horse standing on grass (top right); a green misty mountain meadow (bottom right)",
143
- "the woman walks up to the grey horse in the meadow and gently strokes its neck, smiling, soft daylight; a woman's warm voice saying 'hey there, good boy', a soft horse nicker, light wind and birdsong",
144
  1.4, 42, False],
145
  ],
146
- inputs=[image_in, sheet, action, lora_scale, seed, randomize],
147
  outputs=[video_out, used_seed], fn=generate, cache_examples=True, cache_mode="lazy",
148
  )
149
 
 
1
  import os
2
 
 
3
  os.environ.setdefault("TORCH_COMPILE_DISABLE", "1")
4
  os.environ.setdefault("TORCHDYNAMO_DISABLE", "1")
5
 
6
+ import math
7
  import random
8
  import tempfile
9
 
 
11
  import spaces
12
  import torch
13
  import gradio as gr
14
+ from PIL import Image, ImageOps
15
  from huggingface_hub import hf_hub_download
16
  from safetensors.torch import load_file
17
 
 
21
  from diffusers.utils import encode_video
22
 
23
  # --- Config -----------------------------------------------------------------
24
+ # FAST distilled variant of the ingredients (reference-sheet) IC-LoRA: 8-step schedule, CFG off.
25
  BASE_MODEL = "diffusers/LTX-2.3-Distilled-Diffusers"
26
  LORA_REPO = "linoyts/LTX-2.3-loras"
27
  LORA_FILE = "ltx-2.3-22b-ic-lora-ingredients-0.9" # no .safetensors extension in the repo
 
33
  MAX_SEED = np.iinfo(np.int32).max
34
  HF_TOKEN = os.environ.get("HF_TOKEN")
35
 
 
36
  pipe = LTX2InContextPipeline.from_pretrained(BASE_MODEL, torch_dtype=torch.bfloat16)
37
  pipe.to("cuda")
38
  pipe.vae.enable_tiling()
 
39
  _lora_path = hf_hub_download(LORA_REPO, LORA_FILE, token=HF_TOKEN)
40
+ pipe.load_lora_weights(load_file(_lora_path), adapter_name="ingredients")
41
+ pipe.set_adapters("ingredients", LORA_SCALE)
42
+
43
+
44
+ def _compose_sheet(paths):
45
+ imgs = [Image.open(p).convert("RGB") for p in paths]
46
+ if len(imgs) == 1:
47
+ return imgs[0]
48
+ CW, CH = 1536, 896
49
+ canvas = Image.new("RGB", (CW, CH), (0, 0, 0))
50
+ n = len(imgs)
51
+ cols = math.ceil(math.sqrt(n))
52
+ rows = math.ceil(n / cols)
53
+ g = 16
54
+ cw = (CW - g * (cols + 1)) // cols
55
+ ch = (CH - g * (rows + 1)) // rows
56
+ for i, im in enumerate(imgs):
57
+ r, c = divmod(i, cols)
58
+ canvas.paste(ImageOps.fit(im, (cw, ch), Image.LANCZOS), (g + c * (cw + g), g + r * (ch + g)))
59
+ return canvas
60
+
61
+
62
+ def build_sheet_preview(files):
63
+ if not files:
64
+ return None
65
+ paths = [f if isinstance(f, str) else f.get("path", f.get("name")) for f in files]
66
+ return _compose_sheet(paths)
67
 
68
 
 
69
  def _build_prompt(sheet, action):
70
  return f"Reference sheet: {sheet.strip()}\n\nGenerated video: {action.strip()}"
71
 
 
81
  return 200
82
 
83
 
 
84
  @spaces.GPU(duration=_duration)
85
+ def generate(files, sheet, action, lora_scale, seed, randomize, progress=gr.Progress(track_tqdm=True)):
86
+ if not files:
87
+ raise gr.Error("Upload a reference sheet image, or several subject images to build one.")
 
88
  if not sheet.strip():
89
+ raise gr.Error("Describe the elements in the reference sheet (characters, props, location).")
90
  if not action.strip():
91
  raise gr.Error("Describe the action / shot you want generated.")
92
 
 
94
  seed = random.randint(0, MAX_SEED)
95
  seed = int(seed)
96
 
97
+ paths = [f if isinstance(f, str) else f.get("path", f.get("name")) for f in files]
98
+ sheet_img = _compose_sheet(paths).resize((WIDTH, HEIGHT), Image.LANCZOS)
99
  ref = [sheet_img] * NUM_FRAMES
100
+ pipe.set_adapters("ingredients", float(lora_scale))
101
  prompt = _build_prompt(sheet, action)
102
 
103
  def _cb(p, i, t, kw):
 
105
  return {}
106
 
107
  video_out, audio_out = pipe(
108
+ prompt=prompt, negative_prompt="",
 
109
  reference_conditions=[LTX2ReferenceCondition(frames=ref, strength=1.0)],
110
  reference_downscale_factor=1,
111
  width=WIDTH, height=HEIGHT, num_frames=NUM_FRAMES, frame_rate=FPS,
 
114
  generator=torch.Generator(device="cuda").manual_seed(seed),
115
  output_type="np", return_dict=False, callback_on_step_end=_cb,
116
  )
 
117
  out_path = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False).name
118
  _export(video_out[0], audio_out, out_path)
119
  return out_path, seed
120
 
121
 
122
+ with gr.Blocks(title="LTX-2.3 Ingredients (Fast)") as demo:
 
123
  gr.Markdown(
124
+ "# ⚡ LTX-2.3 Ingredients — Fast (Distilled)\n"
125
+ "Reference-sheet control on the **distilled** checkpoint (8-step, fast). **Upload a ready reference "
126
+ "sheet, or several subject images and we'll tile them into one.** Describe the sheet and the action "
127
+ "(with speech/sounds for audio). For maximum fidelity use the non-distilled demo. "
128
  "IC-LoRA: [`linoyts/LTX-2.3-loras`](https://huggingface.co/linoyts/LTX-2.3-loras)."
129
  )
130
  with gr.Row():
131
  with gr.Column():
132
+ files = gr.File(label="Reference sheet (1 image) or subject images (several)",
133
+ file_count="multiple", file_types=["image"], type="filepath")
134
+ sheet_preview = gr.Image(label="Reference sheet used", type="pil", interactive=False)
135
  sheet = gr.Textbox(label="Reference sheet description", lines=3,
136
  placeholder="a young woman with red hair in a green jacket (face close-up + turnaround); a brass pocket watch; a cobblestone alley at night")
137
  action = gr.Textbox(label="Generated video — the action / shot, plus any speech & sounds", lines=3,
 
145
  video_out = gr.Video(label="Generated video")
146
  used_seed = gr.Number(label="Seed used", interactive=False)
147
 
148
+ files.change(build_sheet_preview, inputs=files, outputs=sheet_preview)
149
+ run.click(generate, inputs=[files, sheet, action, lora_scale, seed, randomize], outputs=[video_out, used_seed])
150
 
151
  gr.Examples(
152
  examples=[
153
+ [["examples/sheet_garden.png"],
154
+ "a cartoon hedgehog (face close-up and body turnaround) and a cartoon rabbit (turnaround); a green coiled garden hose reel and green spray bottles; the interior of a 'Greenfield Home & Garden' store with shelves of plants",
155
+ "the hedgehog and the rabbit explore the Greenfield Home & Garden store among the plants and garden tools, the rabbit holding a green spray bottle, warm bright store lighting, playful slow camera; cheerful ambient store sounds and soft footsteps",
156
  1.4, 42, False],
157
+ [["examples/sheet_hiker.png"],
158
+ "a young woman hiker in a green shirt and khaki shorts (face close-up and body turnaround); a large blue hiking backpack; a wooden walking stick; a shaggy yak with a colorful woven saddle blanket; a Himalayan stone village with prayer flags and snowy mountains",
159
+ "the woman loads the blue backpack onto the yak in front of snowy Himalayan peaks and a monastery, gentle handheld camera, soft daylight; wind, distant prayer bells and the yak's low grunt",
160
  1.4, 42, False],
161
+ [["examples/subj_woman.jpg", "examples/subj_horse.jpg", "examples/subj_landscape.jpg"],
162
+ "a smiling young woman with curly dark hair; a dappled grey horse; a green misty mountain meadow",
163
+ "the woman walks up to the grey horse in the misty meadow and gently strokes its neck, soft daylight; gentle wind, a soft horse nicker and distant birdsong",
164
  1.4, 42, False],
165
  ],
166
+ inputs=[files, sheet, action, lora_scale, seed, randomize],
167
  outputs=[video_out, used_seed], fn=generate, cache_examples=True, cache_mode="lazy",
168
  )
169
 
examples/sheet_garden.png ADDED

Git LFS Details

  • SHA256: 3267a555541f7dcc202fa0474fbfb9b3c04871ffad863825a34426594537d7cc
  • Pointer size: 132 Bytes
  • Size of remote file: 1.49 MB
examples/sheet_hiker.png ADDED

Git LFS Details

  • SHA256: 8ad98e58ea3f108e60a7143d87a43f07994ec5cacbc7579b5a2700f89884c9dc
  • Pointer size: 132 Bytes
  • Size of remote file: 2.02 MB
examples/subj_horse.jpg ADDED

Git LFS Details

  • SHA256: 9aa2b13f1bbc0ab87291e7ae65cc240bcb3a33daab4c343456827d4a473b6c3e
  • Pointer size: 131 Bytes
  • Size of remote file: 226 kB
examples/subj_landscape.jpg ADDED
examples/subj_woman.jpg ADDED

Git LFS Details

  • SHA256: bd50dea7cae6d4e8dae99a3478aa28b237c7b46c41a081899f04fba9673d445b
  • Pointer size: 131 Bytes
  • Size of remote file: 128 kB