dagloop5 commited on
Commit
14a0485
·
verified ·
1 Parent(s): 4ade838

Upload 4 files

Browse files
Files changed (4) hide show
  1. README.md +5 -5
  2. app.py +530 -0
  3. gitattributes +35 -0
  4. requirements.txt +9 -0
README.md CHANGED
@@ -1,10 +1,10 @@
1
  ---
2
- title: Testing1
3
- emoji: 🐢
4
- colorFrom: blue
5
- colorTo: indigo
6
  sdk: gradio
7
- sdk_version: 6.9.0
8
  python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
 
1
  ---
2
+ title: LTX 2.3 Distilled
3
+ emoji: 📚
4
+ colorFrom: indigo
5
+ colorTo: green
6
  sdk: gradio
7
+ sdk_version: 6.8.0
8
  python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
app.py ADDED
@@ -0,0 +1,530 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import subprocess
3
+ import sys
4
+
5
+ # Disable torch.compile / dynamo before any torch import
6
+ os.environ["TORCH_COMPILE_DISABLE"] = "1"
7
+ os.environ["TORCHDYNAMO_DISABLE"] = "1"
8
+
9
+ # Install xformers for memory-efficient attention
10
+ subprocess.run([sys.executable, "-m", "pip", "install", "xformers==0.0.32.post2", "--no-build-isolation"], check=False)
11
+
12
+ # Clone LTX-2 repo and install packages
13
+ LTX_REPO_URL = "https://github.com/Lightricks/LTX-2.git"
14
+ LTX_REPO_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "LTX-2")
15
+
16
+ if not os.path.exists(LTX_REPO_DIR):
17
+ print(f"Cloning {LTX_REPO_URL}...")
18
+ subprocess.run(["git", "clone", "--depth", "1", LTX_REPO_URL, LTX_REPO_DIR], check=True)
19
+
20
+ print("Installing ltx-core and ltx-pipelines from cloned repo...")
21
+ subprocess.run(
22
+ [sys.executable, "-m", "pip", "install", "--force-reinstall", "--no-deps", "-e",
23
+ os.path.join(LTX_REPO_DIR, "packages", "ltx-core"),
24
+ "-e", os.path.join(LTX_REPO_DIR, "packages", "ltx-pipelines")],
25
+ check=True,
26
+ )
27
+
28
+ sys.path.insert(0, os.path.join(LTX_REPO_DIR, "packages", "ltx-pipelines", "src"))
29
+ sys.path.insert(0, os.path.join(LTX_REPO_DIR, "packages", "ltx-core", "src"))
30
+
31
+ import logging
32
+ import random
33
+ import tempfile
34
+ from pathlib import Path
35
+
36
+ import torch
37
+ torch._dynamo.config.suppress_errors = True
38
+ torch._dynamo.config.disable = True
39
+
40
+ import spaces
41
+ import gradio as gr
42
+ import numpy as np
43
+ from huggingface_hub import hf_hub_download, snapshot_download
44
+
45
+ from ltx_core.components.diffusion_steps import EulerDiffusionStep
46
+ from ltx_core.components.noisers import GaussianNoiser
47
+ from ltx_core.model.audio_vae import encode_audio as vae_encode_audio
48
+ from ltx_core.model.upsampler import upsample_video
49
+ from ltx_core.model.video_vae import TilingConfig, get_video_chunks_number, decode_video as vae_decode_video
50
+ from ltx_core.quantization import QuantizationPolicy
51
+ from ltx_core.types import Audio, AudioLatentShape, VideoPixelShape
52
+ from ltx_pipelines.distilled import DistilledPipeline
53
+ from ltx_pipelines.utils import euler_denoising_loop
54
+ from ltx_pipelines.utils.args import ImageConditioningInput
55
+ from ltx_pipelines.utils.constants import DISTILLED_SIGMA_VALUES, STAGE_2_DISTILLED_SIGMA_VALUES
56
+ from ltx_pipelines.utils.helpers import (
57
+ cleanup_memory,
58
+ combined_image_conditionings,
59
+ denoise_video_only,
60
+ encode_prompts,
61
+ simple_denoising_func,
62
+ )
63
+ from ltx_pipelines.utils.media_io import decode_audio_from_file, encode_video
64
+
65
+ # Force-patch xformers attention into the LTX attention module.
66
+ from ltx_core.model.transformer import attention as _attn_mod
67
+ print(f"[ATTN] Before patch: memory_efficient_attention={_attn_mod.memory_efficient_attention}")
68
+ try:
69
+ from xformers.ops import memory_efficient_attention as _mea
70
+ _attn_mod.memory_efficient_attention = _mea
71
+ print(f"[ATTN] After patch: memory_efficient_attention={_attn_mod.memory_efficient_attention}")
72
+ except Exception as e:
73
+ print(f"[ATTN] xformers patch FAILED: {type(e).__name__}: {e}")
74
+
75
+ logging.getLogger().setLevel(logging.INFO)
76
+
77
+ MAX_SEED = np.iinfo(np.int32).max
78
+ DEFAULT_PROMPT = (
79
+ "An astronaut hatches from a fragile egg on the surface of the Moon, "
80
+ "the shell cracking and peeling apart in gentle low-gravity motion. "
81
+ "Fine lunar dust lifts and drifts outward with each movement, floating "
82
+ "in slow arcs before settling back onto the ground."
83
+ )
84
+ DEFAULT_FRAME_RATE = 24.0
85
+
86
+ # Resolution presets: (width, height)
87
+ RESOLUTIONS = {
88
+ "high": {"16:9": (1536, 1024), "9:16": (1024, 1536), "1:1": (1024, 1024)},
89
+ "low": {"16:9": (768, 512), "9:16": (512, 768), "1:1": (768, 768)},
90
+ }
91
+
92
+
93
+ class LTX23DistilledA2VPipeline(DistilledPipeline):
94
+ """DistilledPipeline with optional audio conditioning."""
95
+
96
+ def __call__(
97
+ self,
98
+ prompt: str,
99
+ seed: int,
100
+ height: int,
101
+ width: int,
102
+ num_frames: int,
103
+ frame_rate: float,
104
+ images: list[ImageConditioningInput],
105
+ audio_path: str | None = None,
106
+ tiling_config: TilingConfig | None = None,
107
+ enhance_prompt: bool = False,
108
+ ):
109
+ # Standard path when no audio input is provided.
110
+ print(prompt)
111
+ if audio_path is None:
112
+ return super().__call__(
113
+ prompt=prompt,
114
+ seed=seed,
115
+ height=height,
116
+ width=width,
117
+ num_frames=num_frames,
118
+ frame_rate=frame_rate,
119
+ images=images,
120
+ tiling_config=tiling_config,
121
+ enhance_prompt=enhance_prompt,
122
+ )
123
+
124
+ generator = torch.Generator(device=self.device).manual_seed(seed)
125
+ noiser = GaussianNoiser(generator=generator)
126
+ stepper = EulerDiffusionStep()
127
+ dtype = torch.bfloat16
128
+
129
+ (ctx_p,) = encode_prompts(
130
+ [prompt],
131
+ self.model_ledger,
132
+ enhance_first_prompt=enhance_prompt,
133
+ enhance_prompt_image=images[0].path if len(images) > 0 else None,
134
+ )
135
+ video_context, audio_context = ctx_p.video_encoding, ctx_p.audio_encoding
136
+
137
+ video_duration = num_frames / frame_rate
138
+ decoded_audio = decode_audio_from_file(audio_path, self.device, 0.0, video_duration)
139
+ if decoded_audio is None:
140
+ raise ValueError(f"Could not extract audio stream from {audio_path}")
141
+
142
+ encoded_audio_latent = vae_encode_audio(decoded_audio, self.model_ledger.audio_encoder())
143
+ audio_shape = AudioLatentShape.from_duration(batch=1, duration=video_duration, channels=8, mel_bins=16)
144
+ expected_frames = audio_shape.frames
145
+ actual_frames = encoded_audio_latent.shape[2]
146
+
147
+ if actual_frames > expected_frames:
148
+ encoded_audio_latent = encoded_audio_latent[:, :, :expected_frames, :]
149
+ elif actual_frames < expected_frames:
150
+ pad = torch.zeros(
151
+ encoded_audio_latent.shape[0],
152
+ encoded_audio_latent.shape[1],
153
+ expected_frames - actual_frames,
154
+ encoded_audio_latent.shape[3],
155
+ device=encoded_audio_latent.device,
156
+ dtype=encoded_audio_latent.dtype,
157
+ )
158
+ encoded_audio_latent = torch.cat([encoded_audio_latent, pad], dim=2)
159
+
160
+ video_encoder = self.model_ledger.video_encoder()
161
+ transformer = self.model_ledger.transformer()
162
+ stage_1_sigmas = torch.tensor(DISTILLED_SIGMA_VALUES, device=self.device)
163
+
164
+ def denoising_loop(sigmas, video_state, audio_state, stepper):
165
+ return euler_denoising_loop(
166
+ sigmas=sigmas,
167
+ video_state=video_state,
168
+ audio_state=audio_state,
169
+ stepper=stepper,
170
+ denoise_fn=simple_denoising_func(
171
+ video_context=video_context,
172
+ audio_context=audio_context,
173
+ transformer=transformer,
174
+ ),
175
+ )
176
+
177
+ stage_1_output_shape = VideoPixelShape(
178
+ batch=1,
179
+ frames=num_frames,
180
+ width=width // 2,
181
+ height=height // 2,
182
+ fps=frame_rate,
183
+ )
184
+ stage_1_conditionings = combined_image_conditionings(
185
+ images=images,
186
+ height=stage_1_output_shape.height,
187
+ width=stage_1_output_shape.width,
188
+ video_encoder=video_encoder,
189
+ dtype=dtype,
190
+ device=self.device,
191
+ )
192
+ video_state = denoise_video_only(
193
+ output_shape=stage_1_output_shape,
194
+ conditionings=stage_1_conditionings,
195
+ noiser=noiser,
196
+ sigmas=stage_1_sigmas,
197
+ stepper=stepper,
198
+ denoising_loop_fn=denoising_loop,
199
+ components=self.pipeline_components,
200
+ dtype=dtype,
201
+ device=self.device,
202
+ initial_audio_latent=encoded_audio_latent,
203
+ )
204
+
205
+ torch.cuda.synchronize()
206
+ cleanup_memory()
207
+
208
+ upscaled_video_latent = upsample_video(
209
+ latent=video_state.latent[:1],
210
+ video_encoder=video_encoder,
211
+ upsampler=self.model_ledger.spatial_upsampler(),
212
+ )
213
+ stage_2_sigmas = torch.tensor(STAGE_2_DISTILLED_SIGMA_VALUES, device=self.device)
214
+ stage_2_output_shape = VideoPixelShape(batch=1, frames=num_frames, width=width, height=height, fps=frame_rate)
215
+ stage_2_conditionings = combined_image_conditionings(
216
+ images=images,
217
+ height=stage_2_output_shape.height,
218
+ width=stage_2_output_shape.width,
219
+ video_encoder=video_encoder,
220
+ dtype=dtype,
221
+ device=self.device,
222
+ )
223
+ video_state = denoise_video_only(
224
+ output_shape=stage_2_output_shape,
225
+ conditionings=stage_2_conditionings,
226
+ noiser=noiser,
227
+ sigmas=stage_2_sigmas,
228
+ stepper=stepper,
229
+ denoising_loop_fn=denoising_loop,
230
+ components=self.pipeline_components,
231
+ dtype=dtype,
232
+ device=self.device,
233
+ noise_scale=stage_2_sigmas[0],
234
+ initial_video_latent=upscaled_video_latent,
235
+ initial_audio_latent=encoded_audio_latent,
236
+ )
237
+
238
+ torch.cuda.synchronize()
239
+ del transformer
240
+ del video_encoder
241
+ cleanup_memory()
242
+
243
+ decoded_video = vae_decode_video(
244
+ video_state.latent,
245
+ self.model_ledger.video_decoder(),
246
+ tiling_config,
247
+ generator,
248
+ )
249
+ original_audio = Audio(
250
+ waveform=decoded_audio.waveform.squeeze(0),
251
+ sampling_rate=decoded_audio.sampling_rate,
252
+ )
253
+ return decoded_video, original_audio
254
+
255
+
256
+ # Model repos
257
+ LTX_MODEL_REPO = "Lightricks/LTX-2.3"
258
+ GEMMA_REPO ="rahul7star/gemma-3-12b-it-heretic"
259
+
260
+
261
+ # Download model checkpoints
262
+ print("=" * 80)
263
+ print("Downloading LTX-2.3 distilled model + Gemma...")
264
+ print("=" * 80)
265
+
266
+ checkpoint_path = hf_hub_download(repo_id=LTX_MODEL_REPO, filename="ltx-2.3-22b-distilled.safetensors")
267
+ spatial_upsampler_path = hf_hub_download(repo_id=LTX_MODEL_REPO, filename="ltx-2.3-spatial-upscaler-x2-1.0.safetensors")
268
+ gemma_root = snapshot_download(repo_id=GEMMA_REPO)
269
+
270
+ print(f"Checkpoint: {checkpoint_path}")
271
+ print(f"Spatial upsampler: {spatial_upsampler_path}")
272
+ print(f"Gemma root: {gemma_root}")
273
+
274
+ # Initialize pipeline WITH text encoder and optional audio support
275
+ pipeline = LTX23DistilledA2VPipeline(
276
+ distilled_checkpoint_path=checkpoint_path,
277
+ spatial_upsampler_path=spatial_upsampler_path,
278
+ gemma_root=gemma_root,
279
+ loras=[],
280
+ quantization=QuantizationPolicy.fp8_cast(),
281
+ )
282
+
283
+ # Preload all models for ZeroGPU tensor packing.
284
+ print("Preloading all models (including Gemma and audio components)...")
285
+ ledger = pipeline.model_ledger
286
+ _transformer = ledger.transformer()
287
+ _video_encoder = ledger.video_encoder()
288
+ _video_decoder = ledger.video_decoder()
289
+ _audio_encoder = ledger.audio_encoder()
290
+ _audio_decoder = ledger.audio_decoder()
291
+ _vocoder = ledger.vocoder()
292
+ _spatial_upsampler = ledger.spatial_upsampler()
293
+ _text_encoder = ledger.text_encoder()
294
+ _embeddings_processor = ledger.gemma_embeddings_processor()
295
+
296
+ ledger.transformer = lambda: _transformer
297
+ ledger.video_encoder = lambda: _video_encoder
298
+ ledger.video_decoder = lambda: _video_decoder
299
+ ledger.audio_encoder = lambda: _audio_encoder
300
+ ledger.audio_decoder = lambda: _audio_decoder
301
+ ledger.vocoder = lambda: _vocoder
302
+ ledger.spatial_upsampler = lambda: _spatial_upsampler
303
+ ledger.text_encoder = lambda: _text_encoder
304
+ ledger.gemma_embeddings_processor = lambda: _embeddings_processor
305
+ print("All models preloaded (including Gemma text encoder and audio encoder)!")
306
+
307
+ print("=" * 80)
308
+ print("Pipeline ready!")
309
+ print("=" * 80)
310
+
311
+
312
+ def log_memory(tag: str):
313
+ if torch.cuda.is_available():
314
+ allocated = torch.cuda.memory_allocated() / 1024**3
315
+ peak = torch.cuda.max_memory_allocated() / 1024**3
316
+ free, total = torch.cuda.mem_get_info()
317
+ print(f"[VRAM {tag}] allocated={allocated:.2f}GB peak={peak:.2f}GB free={free / 1024**3:.2f}GB total={total / 1024**3:.2f}GB")
318
+
319
+
320
+ def detect_aspect_ratio(image) -> str:
321
+ if image is None:
322
+ return "16:9"
323
+ if hasattr(image, "size"):
324
+ w, h = image.size
325
+ elif hasattr(image, "shape"):
326
+ h, w = image.shape[:2]
327
+ else:
328
+ return "16:9"
329
+ ratio = w / h
330
+ candidates = {"16:9": 16 / 9, "9:16": 9 / 16, "1:1": 1.0}
331
+ return min(candidates, key=lambda k: abs(ratio - candidates[k]))
332
+
333
+
334
+ def on_image_upload(first_image, last_image, high_res):
335
+ ref_image = first_image if first_image is not None else last_image
336
+ aspect = detect_aspect_ratio(ref_image)
337
+ tier = "high" if high_res else "low"
338
+ w, h = RESOLUTIONS[tier][aspect]
339
+ return gr.update(value=w), gr.update(value=h)
340
+
341
+
342
+ def on_highres_toggle(first_image, last_image, high_res):
343
+ ref_image = first_image if first_image is not None else last_image
344
+ aspect = detect_aspect_ratio(ref_image)
345
+ tier = "high" if high_res else "low"
346
+ w, h = RESOLUTIONS[tier][aspect]
347
+ return gr.update(value=w), gr.update(value=h)
348
+
349
+
350
+ @spaces.GPU(duration=75)
351
+ @torch.inference_mode()
352
+ def generate_video(
353
+ first_image,
354
+ last_image,
355
+ input_audio,
356
+ prompt: str,
357
+ duration: float,
358
+ enhance_prompt: bool = True,
359
+ seed: int = 42,
360
+ randomize_seed: bool = True,
361
+ height: int = 1024,
362
+ width: int = 1536,
363
+ progress=gr.Progress(track_tqdm=True),
364
+ ):
365
+ try:
366
+ torch.cuda.reset_peak_memory_stats()
367
+ log_memory("start")
368
+
369
+ current_seed = random.randint(0, MAX_SEED) if randomize_seed else int(seed)
370
+
371
+ frame_rate = DEFAULT_FRAME_RATE
372
+ num_frames = int(duration * frame_rate) + 1
373
+ num_frames = ((num_frames - 1 + 7) // 8) * 8 + 1
374
+
375
+ print(f"Generating: {height}x{width}, {num_frames} frames ({duration}s), seed={current_seed}")
376
+
377
+ images = []
378
+ output_dir = Path("outputs")
379
+ output_dir.mkdir(exist_ok=True)
380
+
381
+ if first_image is not None:
382
+ temp_first_path = output_dir / f"temp_first_{current_seed}.jpg"
383
+ if hasattr(first_image, "save"):
384
+ first_image.save(temp_first_path)
385
+ else:
386
+ temp_first_path = Path(first_image)
387
+ images.append(ImageConditioningInput(path=str(temp_first_path), frame_idx=0, strength=1.0))
388
+
389
+ if last_image is not None:
390
+ temp_last_path = output_dir / f"temp_last_{current_seed}.jpg"
391
+ if hasattr(last_image, "save"):
392
+ last_image.save(temp_last_path)
393
+ else:
394
+ temp_last_path = Path(last_image)
395
+ images.append(ImageConditioningInput(path=str(temp_last_path), frame_idx=num_frames - 1, strength=1.0))
396
+
397
+ tiling_config = TilingConfig.default()
398
+ video_chunks_number = get_video_chunks_number(num_frames, tiling_config)
399
+
400
+ log_memory("before pipeline call")
401
+
402
+ video, audio = pipeline(
403
+ prompt=prompt,
404
+ seed=current_seed,
405
+ height=int(height),
406
+ width=int(width),
407
+ num_frames=num_frames,
408
+ frame_rate=frame_rate,
409
+ images=images,
410
+ audio_path=input_audio,
411
+ tiling_config=tiling_config,
412
+ enhance_prompt=enhance_prompt,
413
+ )
414
+
415
+ log_memory("after pipeline call")
416
+
417
+ output_path = tempfile.mktemp(suffix=".mp4")
418
+ encode_video(
419
+ video=video,
420
+ fps=frame_rate,
421
+ audio=audio,
422
+ output_path=output_path,
423
+ video_chunks_number=video_chunks_number,
424
+ )
425
+
426
+ log_memory("after encode_video")
427
+ return str(output_path), current_seed
428
+
429
+ except Exception as e:
430
+ import traceback
431
+ log_memory("on error")
432
+ print(f"Error: {str(e)}\n{traceback.format_exc()}")
433
+ return None, current_seed
434
+
435
+
436
+ with gr.Blocks(title="LTX-2.3 Heretic Distilled") as demo:
437
+ gr.Markdown("# LTX-2.3 F2LF:Heretic with Fast Audio-Video Generation with Frame Conditioning")
438
+
439
+
440
+ with gr.Row():
441
+ with gr.Column():
442
+ with gr.Row():
443
+ first_image = gr.Image(label="First Frame (Optional)", type="pil")
444
+ last_image = gr.Image(label="Last Frame (Optional)", type="pil")
445
+ input_audio = gr.Audio(label="Audio Input (Optional)", type="filepath")
446
+ prompt = gr.Textbox(
447
+ label="Prompt",
448
+ info="for best results - make it as elaborate as possible",
449
+ value="Make this image come alive with cinematic motion, smooth animation",
450
+ lines=3,
451
+ placeholder="Describe the motion and animation you want...",
452
+ )
453
+ duration = gr.Slider(label="Duration (seconds)", minimum=1.0, maximum=10.0, value=3.0, step=0.1)
454
+
455
+
456
+ generate_btn = gr.Button("Generate Video", variant="primary", size="lg")
457
+
458
+ with gr.Accordion("Advanced Settings", open=False):
459
+ seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, value=10, step=1)
460
+ randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
461
+ with gr.Row():
462
+ width = gr.Number(label="Width", value=1536, precision=0)
463
+ height = gr.Number(label="Height", value=1024, precision=0)
464
+ with gr.Row():
465
+ enhance_prompt = gr.Checkbox(label="Enhance Prompt", value=False)
466
+ high_res = gr.Checkbox(label="High Resolution", value=True)
467
+
468
+ with gr.Column():
469
+ output_video = gr.Video(label="Generated Video", autoplay=True)
470
+
471
+ gr.Examples(
472
+ examples=[
473
+ [
474
+ None,
475
+ "pinkknit.jpg",
476
+ None,
477
+ "The camera falls downward through darkness as if dropped into a tunnel. "
478
+ "As it slows, five friends wearing pink knitted hats and sunglasses lean "
479
+ "over and look down toward the camera with curious expressions. The lens "
480
+ "has a strong fisheye effect, creating a circular frame around them. They "
481
+ "crowd together closely, forming a symmetrical cluster while staring "
482
+ "directly into the lens.",
483
+ 3.0,
484
+ False,
485
+ 42,
486
+ True,
487
+ 1024,
488
+ 1024,
489
+ ],
490
+ ],
491
+ inputs=[
492
+ first_image, last_image, input_audio, prompt, duration,
493
+ enhance_prompt, seed, randomize_seed, height, width,
494
+ ],
495
+ )
496
+
497
+ first_image.change(
498
+ fn=on_image_upload,
499
+ inputs=[first_image, last_image, high_res],
500
+ outputs=[width, height],
501
+ )
502
+
503
+ last_image.change(
504
+ fn=on_image_upload,
505
+ inputs=[first_image, last_image, high_res],
506
+ outputs=[width, height],
507
+ )
508
+
509
+ high_res.change(
510
+ fn=on_highres_toggle,
511
+ inputs=[first_image, last_image, high_res],
512
+ outputs=[width, height],
513
+ )
514
+
515
+ generate_btn.click(
516
+ fn=generate_video,
517
+ inputs=[
518
+ first_image, last_image, input_audio, prompt, duration, enhance_prompt,
519
+ seed, randomize_seed, height, width,
520
+ ],
521
+ outputs=[output_video, seed],
522
+ )
523
+
524
+
525
+ css = """
526
+ .fillable{max-width: 1200px !important}
527
+ """
528
+
529
+ if __name__ == "__main__":
530
+ demo.launch(theme=gr.themes.Citrus(), css=css)
gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ transformers==4.57.6
2
+ accelerate
3
+ torch==2.8.0
4
+ einops
5
+ scipy
6
+ av
7
+ scikit-image>=0.25.2
8
+ flashpack==0.1.2
9
+ torchaudio==2.8.0