ozilion commited on
Commit
8e5115d
Β·
verified Β·
1 Parent(s): 9bfc43b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +359 -4
app.py CHANGED
@@ -1,6 +1,361 @@
1
  import gradio as gr
 
 
 
 
 
 
 
 
2
 
3
- gr.load(
4
- "models/Lightricks/LTX-Video",
5
- provider="fal-ai",
6
- ).launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ import torch
3
+ import os
4
+ import gc
5
+ import numpy as np
6
+ from PIL import Image
7
+ import tempfile
8
+ from typing import Optional, Tuple
9
+ import time
10
 
11
+ # Check if we're running on Hugging Face Spaces
12
+ IS_SPACES = os.environ.get("SPACE_ID") is not None
13
+
14
+ def check_system():
15
+ """Check system capabilities"""
16
+ gpu_available = torch.cuda.is_available()
17
+ gpu_memory = 0
18
+ if gpu_available:
19
+ gpu_memory = torch.cuda.get_device_properties(0).total_memory / (1024**3)
20
+
21
+ return {
22
+ "gpu_available": gpu_available,
23
+ "gpu_memory": gpu_memory,
24
+ "is_spaces": IS_SPACES
25
+ }
26
+
27
+ def load_ltx_model():
28
+ """Load LTX-Video model with optimizations for HF Spaces"""
29
+ try:
30
+ from diffusers import LTXVideoPipeline
31
+ from diffusers.utils import export_to_video
32
+
33
+ system_info = check_system()
34
+
35
+ # Model loading strategy based on available resources
36
+ model_id = "Lightricks/LTX-Video"
37
+
38
+ if system_info["gpu_available"] and system_info["gpu_memory"] > 12:
39
+ # High-end GPU setup
40
+ pipe = LTXVideoPipeline.from_pretrained(
41
+ model_id,
42
+ torch_dtype=torch.bfloat16,
43
+ variant="fp16"
44
+ ).to("cuda")
45
+ device = "cuda"
46
+ dtype = torch.bfloat16
47
+ elif system_info["gpu_available"] and system_info["gpu_memory"] > 6:
48
+ # Mid-range GPU setup with optimizations
49
+ pipe = LTXVideoPipeline.from_pretrained(
50
+ model_id,
51
+ torch_dtype=torch.float16,
52
+ variant="fp16",
53
+ low_cpu_mem_usage=True
54
+ ).to("cuda")
55
+ device = "cuda"
56
+ dtype = torch.float16
57
+ else:
58
+ # CPU fallback or low memory GPU
59
+ pipe = LTXVideoPipeline.from_pretrained(
60
+ model_id,
61
+ torch_dtype=torch.float32,
62
+ low_cpu_mem_usage=True
63
+ )
64
+ device = "cpu"
65
+ dtype = torch.float32
66
+
67
+ # Enable memory efficient attention if available
68
+ if hasattr(pipe, "enable_memory_efficient_attention"):
69
+ pipe.enable_memory_efficient_attention()
70
+
71
+ # Enable CPU offload for low memory setups
72
+ if system_info["gpu_memory"] < 16 and device == "cuda":
73
+ pipe.enable_sequential_cpu_offload()
74
+
75
+ return pipe, device, dtype, system_info
76
+
77
+ except ImportError:
78
+ return None, "cpu", torch.float32, {"error": "diffusers library not installed or LTX model not available"}
79
+ except Exception as e:
80
+ return None, "cpu", torch.float32, {"error": f"Model loading failed: {str(e)}"}
81
+
82
+ # Initialize model
83
+ print("Loading LTX-Video model...")
84
+ PIPE, DEVICE, DTYPE, SYSTEM_INFO = load_ltx_model()
85
+
86
+ def generate_video(
87
+ prompt: str,
88
+ negative_prompt: str = "",
89
+ num_frames: int = 25,
90
+ height: int = 512,
91
+ width: int = 512,
92
+ num_inference_steps: int = 20,
93
+ guidance_scale: float = 7.5,
94
+ seed: int = -1
95
+ ) -> Tuple[Optional[str], str]:
96
+ """Generate video using LTX-Video model"""
97
+
98
+ if PIPE is None:
99
+ error_msg = f"❌ Model not loaded: {SYSTEM_INFO.get('error', 'Unknown error')}"
100
+ return None, error_msg
101
+
102
+ # Input validation
103
+ if not prompt.strip():
104
+ return None, "❌ Please enter a valid prompt."
105
+
106
+ if len(prompt) > 500:
107
+ return None, "❌ Prompt too long. Please keep it under 500 characters."
108
+
109
+ # Adjust parameters based on system capabilities
110
+ if DEVICE == "cpu":
111
+ num_frames = min(num_frames, 16) # Limit frames for CPU
112
+ num_inference_steps = min(num_inference_steps, 15)
113
+ height = min(height, 256)
114
+ width = min(width, 256)
115
+ elif SYSTEM_INFO.get("gpu_memory", 0) < 8:
116
+ num_frames = min(num_frames, 20)
117
+ height = min(height, 512)
118
+ width = min(width, 512)
119
+
120
+ try:
121
+ # Clear cache
122
+ if DEVICE == "cuda":
123
+ torch.cuda.empty_cache()
124
+ gc.collect()
125
+
126
+ # Set seed for reproducibility
127
+ generator = None
128
+ if seed != -1:
129
+ generator = torch.Generator(device=DEVICE).manual_seed(seed)
130
+ else:
131
+ seed = np.random.randint(0, 2**32 - 1)
132
+ generator = torch.Generator(device=DEVICE).manual_seed(seed)
133
+
134
+ start_time = time.time()
135
+
136
+ # Generate video
137
+ with torch.autocast(DEVICE, dtype=DTYPE):
138
+ result = PIPE(
139
+ prompt=prompt,
140
+ negative_prompt=negative_prompt if negative_prompt else None,
141
+ num_frames=num_frames,
142
+ height=height,
143
+ width=width,
144
+ num_inference_steps=num_inference_steps,
145
+ guidance_scale=guidance_scale,
146
+ generator=generator
147
+ )
148
+
149
+ end_time = time.time()
150
+ generation_time = end_time - start_time
151
+
152
+ # Save video to temporary file
153
+ video_frames = result.frames[0]
154
+
155
+ with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp_file:
156
+ # Convert frames to video
157
+ from diffusers.utils import export_to_video
158
+ export_to_video(video_frames, tmp_file.name, fps=8)
159
+ video_path = tmp_file.name
160
+
161
+ success_msg = f"""
162
+ βœ… Video generated successfully!
163
+
164
+ πŸ“ Prompt: {prompt}
165
+ 🎬 Frames: {num_frames}
166
+ πŸ“ Resolution: {width}x{height}
167
+ βš™οΈ Steps: {num_inference_steps}
168
+ 🎯 Guidance: {guidance_scale}
169
+ 🎲 Seed: {seed}
170
+ ⏱️ Generation Time: {generation_time:.1f}s
171
+ πŸ–₯️ Device: {DEVICE}
172
+ """
173
+
174
+ return video_path, success_msg
175
+
176
+ except torch.cuda.OutOfMemoryError:
177
+ return None, "❌ GPU memory exceeded. Try reducing resolution, frames, or inference steps."
178
+ except Exception as e:
179
+ return None, f"❌ Generation failed: {str(e)}"
180
+
181
+ def get_system_info():
182
+ """Get detailed system information"""
183
+ info = f"""
184
+ ## πŸ–₯️ System Information
185
+
186
+ **Hardware:**
187
+ - GPU Available: {'βœ…' if SYSTEM_INFO.get('gpu_available', False) else '❌'}
188
+ - GPU Memory: {SYSTEM_INFO.get('gpu_memory', 0):.1f} GB
189
+ - Device: {DEVICE}
190
+ - Data Type: {DTYPE}
191
+
192
+ **Environment:**
193
+ - Hugging Face Spaces: {'βœ…' if IS_SPACES else '❌'}
194
+ - PyTorch Version: {torch.__version__}
195
+
196
+ **Model Status:**
197
+ - LTX-Video Loaded: {'βœ…' if PIPE is not None else '❌'}
198
+ """
199
+
200
+ if "error" in SYSTEM_INFO:
201
+ info += f"\n**Error:** {SYSTEM_INFO['error']}"
202
+
203
+ return info
204
+
205
+ # Create Gradio interface
206
+ with gr.Blocks(title="LTX-Video Generator", theme=gr.themes.Soft()) as demo:
207
+
208
+ gr.Markdown("""
209
+ # 🎬 LTX-Video Generator by Lightricks
210
+
211
+ Generate high-quality videos from text descriptions using the LTX-Video model.
212
+ """)
213
+
214
+ with gr.Tab("πŸŽ₯ Generate Video"):
215
+ with gr.Row():
216
+ with gr.Column(scale=1):
217
+ prompt_input = gr.Textbox(
218
+ label="πŸ“ Video Prompt",
219
+ placeholder="A serene lake surrounded by mountains at sunset...",
220
+ lines=3,
221
+ max_lines=5
222
+ )
223
+
224
+ negative_prompt_input = gr.Textbox(
225
+ label="🚫 Negative Prompt (Optional)",
226
+ placeholder="blurry, low quality, distorted...",
227
+ lines=2
228
+ )
229
+
230
+ with gr.Row():
231
+ num_frames = gr.Slider(
232
+ minimum=8,
233
+ maximum=50,
234
+ value=25,
235
+ step=1,
236
+ label="🎬 Number of Frames"
237
+ )
238
+
239
+ num_steps = gr.Slider(
240
+ minimum=10,
241
+ maximum=50,
242
+ value=20,
243
+ step=1,
244
+ label="βš™οΈ Inference Steps"
245
+ )
246
+
247
+ with gr.Row():
248
+ width = gr.Dropdown(
249
+ choices=[256, 512, 768, 1024],
250
+ value=512,
251
+ label="πŸ“ Width"
252
+ )
253
+
254
+ height = gr.Dropdown(
255
+ choices=[256, 512, 768, 1024],
256
+ value=512,
257
+ label="πŸ“ Height"
258
+ )
259
+
260
+ with gr.Row():
261
+ guidance_scale = gr.Slider(
262
+ minimum=1.0,
263
+ maximum=20.0,
264
+ value=7.5,
265
+ step=0.5,
266
+ label="🎯 Guidance Scale"
267
+ )
268
+
269
+ seed = gr.Number(
270
+ label="🎲 Seed (-1 for random)",
271
+ value=-1,
272
+ precision=0
273
+ )
274
+
275
+ generate_btn = gr.Button("🎬 Generate Video", variant="primary", size="lg")
276
+
277
+ with gr.Column(scale=1):
278
+ video_output = gr.Video(
279
+ label="πŸŽ₯ Generated Video",
280
+ height=400
281
+ )
282
+
283
+ result_text = gr.Textbox(
284
+ label="πŸ“‹ Generation Info",
285
+ lines=8,
286
+ show_copy_button=True
287
+ )
288
+
289
+ # Event handler
290
+ generate_btn.click(
291
+ fn=generate_video,
292
+ inputs=[
293
+ prompt_input, negative_prompt_input, num_frames,
294
+ height, width, num_steps, guidance_scale, seed
295
+ ],
296
+ outputs=[video_output, result_text]
297
+ )
298
+
299
+ # Example prompts
300
+ gr.Examples(
301
+ examples=[
302
+ ["A majestic waterfall cascading down rocky cliffs", "", 25, 512, 512, 20, 7.5, 42],
303
+ ["A cute kitten playing with colorful yarn balls", "blurry, low quality", 20, 512, 512, 20, 8.0, 123],
304
+ ["Time-lapse of clouds moving over a city skyline", "", 30, 768, 512, 25, 7.0, 456],
305
+ ["A peaceful forest with sunlight filtering through trees", "dark, gloomy", 25, 512, 768, 20, 7.5, 789]
306
+ ],
307
+ inputs=[prompt_input, negative_prompt_input, num_frames, height, width, num_steps, guidance_scale, seed]
308
+ )
309
+
310
+ with gr.Tab("ℹ️ System Info"):
311
+ with gr.Row():
312
+ info_btn = gr.Button("πŸ” Check System Status", variant="secondary")
313
+
314
+ system_output = gr.Markdown()
315
+
316
+ info_btn.click(
317
+ fn=get_system_info,
318
+ outputs=system_output
319
+ )
320
+
321
+ # Initial system info display
322
+ demo.load(
323
+ fn=get_system_info,
324
+ outputs=system_output
325
+ )
326
+
327
+ with gr.Tab("πŸ“š Usage Tips"):
328
+ gr.Markdown("""
329
+ ## πŸ’‘ Tips for Better Results
330
+
331
+ **Prompt Writing:**
332
+ - Be descriptive and specific
333
+ - Include camera movements (zoom, pan, etc.)
334
+ - Specify lighting and mood
335
+ - Mention style if desired (cinematic, artistic, etc.)
336
+
337
+ **Parameter Tuning:**
338
+ - **Frames:** More frames = longer video but slower generation
339
+ - **Inference Steps:** Higher steps = better quality but slower
340
+ - **Guidance Scale:** 7-9 usually works best
341
+ - **Resolution:** Start with 512x512 for faster results
342
+
343
+ **Performance:**
344
+ - CPU generation is slower but works on all systems
345
+ - GPU generation requires sufficient VRAM
346
+ - Lower settings if you encounter memory errors
347
+
348
+ **Negative Prompts:** Help avoid unwanted elements
349
+ - Common: "blurry, low quality, distorted, pixelated"
350
+ - Specific: "text, watermark, signature, logo"
351
+ """)
352
+
353
+ # Launch configuration
354
+ if __name__ == "__main__":
355
+ demo.launch(
356
+ share=False,
357
+ server_name="0.0.0.0",
358
+ server_port=7860,
359
+ show_error=True,
360
+ show_api=False
361
+ )