Pravin Barapatre commited on
Commit
3498257
·
1 Parent(s): 6a1cccc

Simplify app to avoid NumPy compatibility issues - remove voice features and problematic dependencies

Browse files
app.py CHANGED
@@ -1,13 +1,12 @@
1
  import torch
2
  import gradio as gr
3
  from diffusers import DiffusionPipeline, DPMSolverMultistepScheduler
4
- from diffusers.utils import export_to_video
5
  import numpy as np
6
  import os
7
  import logging
8
- from gtts import gTTS
9
- from moviepy.editor import VideoFileClip, AudioFileClip, CompositeAudioClip
10
  import tempfile
 
 
11
 
12
  # Set up logging
13
  logging.basicConfig(level=logging.INFO)
@@ -20,7 +19,7 @@ class TextToVideoGenerator:
20
  self.device = "cuda" if torch.cuda.is_available() else "cpu"
21
  logger.info(f"Using device: {self.device}")
22
 
23
- # Available models - including the advanced Wan2.1 model
24
  self.models = {
25
  "damo-vilab/text-to-video-ms-1.7b": {
26
  "name": "DAMO Text-to-Video MS-1.7B",
@@ -37,70 +36,8 @@ class TextToVideoGenerator:
37
  "fps": 6,
38
  "quality": "Excellent",
39
  "speed": "Medium"
40
- },
41
- "Wan-AI/Wan2.1-T2V-14B": {
42
- "name": "Wan2.1-T2V-14B (SOTA)",
43
- "description": "State-of-the-art text-to-video model with 14B parameters",
44
- "max_frames": 32,
45
- "fps": 8,
46
- "quality": "SOTA",
47
- "speed": "Medium",
48
- "resolutions": ["480P", "720P"],
49
- "features": ["Chinese & English text", "High motion dynamics", "Best quality"]
50
  }
51
  }
52
-
53
- # Voice options (gTTS only supports language, not gender/age)
54
- self.voices = {
55
- "Default (English)": "en"
56
- }
57
-
58
- def generate_audio(self, text, voice_type):
59
- """Generate audio from text using gTTS"""
60
- try:
61
- lang = self.voices[voice_type]
62
- tts = gTTS(text=text, lang=lang)
63
- with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as temp_audio:
64
- audio_path = temp_audio.name
65
- tts.save(audio_path)
66
- logger.info(f"Audio generated successfully: {audio_path}")
67
- return audio_path
68
- except Exception as e:
69
- logger.error(f"Error generating audio: {str(e)}")
70
- return None
71
-
72
- def merge_audio_video(self, video_path, audio_path, output_path):
73
- """Merge audio and video using moviepy"""
74
- try:
75
- # Load video and audio
76
- video_clip = VideoFileClip(video_path)
77
- audio_clip = AudioFileClip(audio_path)
78
-
79
- # Ensure audio duration matches video duration
80
- if audio_clip.duration > video_clip.duration:
81
- audio_clip = audio_clip.subclip(0, video_clip.duration)
82
- elif audio_clip.duration < video_clip.duration:
83
- # Loop audio if it's shorter than video
84
- loops_needed = int(video_clip.duration / audio_clip.duration) + 1
85
- audio_clip = CompositeAudioClip([audio_clip] * loops_needed).subclip(0, video_clip.duration)
86
-
87
- # Merge audio and video
88
- final_clip = video_clip.set_audio(audio_clip)
89
-
90
- # Write final video with audio
91
- final_clip.write_videofile(output_path, codec='libx264', audio_codec='aac')
92
-
93
- # Clean up
94
- video_clip.close()
95
- audio_clip.close()
96
- final_clip.close()
97
-
98
- logger.info(f"Audio and video merged successfully: {output_path}")
99
- return output_path
100
-
101
- except Exception as e:
102
- logger.error(f"Error merging audio and video: {str(e)}")
103
- return None
104
 
105
  def load_model(self, model_id):
106
  """Load the specified model"""
@@ -114,22 +51,12 @@ class TextToVideoGenerator:
114
  if torch.cuda.is_available():
115
  torch.cuda.empty_cache()
116
 
117
- # Special handling for Wan2.1 model
118
- if model_id == "Wan-AI/Wan2.1-T2V-14B":
119
- # Wan2.1 requires specific configuration
120
- self.pipeline = DiffusionPipeline.from_pretrained(
121
- model_id,
122
- torch_dtype=torch.float16 if self.device == "cuda" else torch.float32,
123
- variant="fp16" if self.device == "cuda" else None,
124
- use_safetensors=True
125
- )
126
- else:
127
- # Standard loading for other models
128
- self.pipeline = DiffusionPipeline.from_pretrained(
129
- model_id,
130
- torch_dtype=torch.float16 if self.device == "cuda" else torch.float32,
131
- variant="fp16" if self.device == "cuda" else None
132
- )
133
 
134
  # Move to device
135
  self.pipeline = self.pipeline.to(self.device)
@@ -153,13 +80,9 @@ class TextToVideoGenerator:
153
  logger.error(f"Error loading model: {str(e)}")
154
  return f"Error loading model: {str(e)}"
155
 
156
- def generate_video(self, prompt, model_id, num_frames=16, fps=8, num_inference_steps=25, guidance_scale=7.5, seed=None, resolution="480P", voice_script="", voice_type="Default (English)", add_voice=True):
157
- """Generate video from text prompt with optional voice"""
158
  try:
159
- # Use prompt as voice script if voice_script is empty
160
- if not voice_script.strip() and add_voice:
161
- voice_script = prompt
162
-
163
  # Load model if not already loaded
164
  if self.current_model != model_id:
165
  load_result = self.load_model(model_id)
@@ -177,245 +100,85 @@ class TextToVideoGenerator:
177
  num_frames = min(num_frames, model_config["max_frames"])
178
  fps = model_config["fps"]
179
 
180
- # Special handling for Wan2.1 model
181
- if model_id == "Wan-AI/Wan2.1-T2V-14B":
182
- # Wan2.1 specific parameters
183
- if resolution == "720P":
184
- width, height = 1280, 720
185
- else: # 480P
186
- width, height = 832, 480
187
-
188
- logger.info(f"Generating Wan2.1 video with prompt: {prompt}")
189
- logger.info(f"Parameters: frames={num_frames}, fps={fps}, steps={num_inference_steps}, resolution={resolution}")
190
-
191
- # Generate video with Wan2.1 specific settings
192
- result = self.pipeline(
193
- prompt,
194
- num_inference_steps=num_inference_steps,
195
- guidance_scale=guidance_scale,
196
- num_frames=num_frames,
197
- width=width,
198
- height=height
199
- )
200
- video_frames = result['frames'] if isinstance(result, dict) else result.frames
201
- else:
202
- # Standard generation for other models
203
- logger.info(f"Generating video with prompt: {prompt}")
204
- logger.info(f"Parameters: frames={num_frames}, fps={fps}, steps={num_inference_steps}")
205
-
206
- result = self.pipeline(
207
- prompt,
208
- num_inference_steps=num_inference_steps,
209
- guidance_scale=guidance_scale,
210
- num_frames=num_frames
211
- )
212
- video_frames = result['frames'] if isinstance(result, dict) else result.frames
213
 
214
- # Convert to numpy array
215
- video_frames = np.array(video_frames)
 
 
 
 
 
216
 
217
  # Save video
218
- output_path = f"generated_video_{seed if seed else 'random'}.mp4"
 
 
 
219
  export_to_video(video_frames, output_path, fps=fps)
220
 
221
- logger.info(f"Video saved to: {output_path}")
222
-
223
- # Add voice if requested
224
- if add_voice and voice_script.strip():
225
- logger.info(f"Generating voice for script: {voice_script}")
226
-
227
- # Generate audio
228
- audio_path = self.generate_audio(voice_script, voice_type)
229
-
230
- if audio_path:
231
- # Create final output path with voice
232
- final_output_path = f"generated_video_with_voice_{seed if seed else 'random'}.mp4"
233
-
234
- # Merge audio and video
235
- final_path = self.merge_audio_video(output_path, audio_path, final_output_path)
236
-
237
- # Clean up temporary files
238
- try:
239
- os.unlink(audio_path)
240
- os.unlink(output_path)
241
- except:
242
- pass
243
-
244
- if final_path:
245
- return final_path, f"Video with voice generated successfully! Saved as {final_path}"
246
- else:
247
- return output_path, f"Video generated but voice merging failed. Saved as {output_path}"
248
- else:
249
- return output_path, f"Video generated but voice generation failed. Saved as {output_path}"
250
- else:
251
- return output_path, f"Video generated successfully! Saved as {output_path}"
252
 
253
  except Exception as e:
254
  logger.error(f"Error generating video: {str(e)}")
255
  return None, f"Error generating video: {str(e)}"
256
 
257
  def get_available_models(self):
258
- """Get list of available models"""
259
  return list(self.models.keys())
260
 
261
  def get_model_info(self, model_id):
262
- """Get information about a specific model"""
263
  if model_id in self.models:
264
  return self.models[model_id]
265
- return None
266
-
267
- def get_available_voices(self):
268
- """Get list of available voices"""
269
- return list(self.voices.keys())
270
-
271
- # Initialize the generator
272
- generator = TextToVideoGenerator()
273
 
274
  def create_interface():
275
- """Create Gradio interface"""
 
276
 
277
- def generate_video_interface(prompt, model_id, num_frames, fps, num_inference_steps, guidance_scale, seed, resolution, voice_script, voice_type, add_voice):
 
278
  if not prompt.strip():
279
- return None, "Please enter a prompt"
280
 
281
- return generator.generate_video(
282
  prompt=prompt,
283
  model_id=model_id,
284
  num_frames=num_frames,
285
  fps=fps,
286
  num_inference_steps=num_inference_steps,
287
  guidance_scale=guidance_scale,
288
- seed=seed,
289
- resolution=resolution,
290
- voice_script=voice_script,
291
- voice_type=voice_type,
292
- add_voice=add_voice
293
  )
 
 
294
 
295
- # Custom CSS for professional styling
296
  custom_css = """
297
  .gradio-container {
298
  max-width: 1200px !important;
299
  margin: 0 auto !important;
300
  }
301
-
302
- .header {
303
- text-align: center;
304
- padding: 2rem 0;
305
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
306
- color: white;
307
- border-radius: 15px;
308
- margin-bottom: 2rem;
309
- }
310
-
311
- .header h1 {
312
- font-size: 2.5rem;
313
- font-weight: 700;
314
- margin: 0;
315
- text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
316
- }
317
-
318
- .header p {
319
- font-size: 1.1rem;
320
- margin: 0.5rem 0 0 0;
321
- opacity: 0.9;
322
- }
323
-
324
- .feature-card {
325
- background: white;
326
- border-radius: 10px;
327
- padding: 1.5rem;
328
- box-shadow: 0 4px 6px rgba(0,0,0,0.1);
329
- margin-bottom: 1rem;
330
- border-left: 4px solid #667eea;
331
- }
332
-
333
- .feature-card h3 {
334
- color: #333;
335
- margin: 0 0 0.5rem 0;
336
- font-size: 1.2rem;
337
- }
338
-
339
- .feature-card p {
340
- color: #666;
341
- margin: 0;
342
- font-size: 0.9rem;
343
- }
344
-
345
- .model-info {
346
- background: #f8f9fa;
347
- border-radius: 8px;
348
- padding: 1rem;
349
- border: 1px solid #e9ecef;
350
- }
351
-
352
- .model-info h4 {
353
- color: #495057;
354
- margin: 0 0 0.5rem 0;
355
- font-size: 1rem;
356
- }
357
-
358
- .model-info p {
359
- color: #6c757d;
360
- margin: 0.25rem 0;
361
- font-size: 0.85rem;
362
- }
363
-
364
  .generate-btn {
365
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
366
  border: none !important;
367
  color: white !important;
368
- font-weight: 600 !important;
369
- padding: 1rem 2rem !important;
370
- border-radius: 10px !important;
371
- font-size: 1.1rem !important;
372
- transition: all 0.3s ease !important;
373
- }
374
-
375
- .generate-btn:hover {
376
- transform: translateY(-2px) !important;
377
- box-shadow: 0 6px 12px rgba(102, 126, 234, 0.4) !important;
378
  }
379
-
380
- .example-card {
381
- background: #f8f9fa;
382
- border-radius: 8px;
383
- padding: 1rem;
384
- margin: 0.5rem 0;
385
- border: 1px solid #e9ecef;
386
- cursor: pointer;
387
- transition: all 0.2s ease;
388
- }
389
-
390
- .example-card:hover {
391
- background: #e9ecef;
392
- transform: translateX(5px);
393
- }
394
-
395
  .status-box {
396
- background: #e3f2fd;
397
- border: 1px solid #2196f3;
398
- border-radius: 8px;
399
- padding: 1rem;
400
- }
401
-
402
- .pricing-info {
403
- background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
404
- border-radius: 10px;
405
- padding: 1rem;
406
- text-align: center;
407
- margin: 1rem 0;
408
- }
409
-
410
- .pricing-info h4 {
411
- color: #d84315;
412
- margin: 0 0 0.5rem 0;
413
- }
414
-
415
- .pricing-info p {
416
- color: #bf360c;
417
- margin: 0;
418
- font-size: 0.9rem;
419
  }
420
  """
421
 
@@ -443,23 +206,13 @@ def create_interface():
443
  container=True
444
  )
445
 
446
- with gr.Row():
447
- model_id = gr.Dropdown(
448
- choices=generator.get_available_models(),
449
- value=generator.get_available_models()[0],
450
- label="🤖 AI Model",
451
- info="Choose the AI model for video generation",
452
- container=True
453
- )
454
-
455
- resolution = gr.Dropdown(
456
- choices=["480P", "720P"],
457
- value="480P",
458
- label="📐 Resolution (Wan2.1 only)",
459
- info="Select video resolution",
460
- visible=False,
461
- container=True
462
- )
463
 
464
  with gr.Row():
465
  num_frames = gr.Slider(
@@ -506,34 +259,6 @@ def create_interface():
506
  container=True
507
  )
508
 
509
- # Voice Section
510
- with gr.Group():
511
- gr.Markdown("## 🎤 Voice & Audio")
512
-
513
- with gr.Row():
514
- add_voice = gr.Checkbox(
515
- label="🎵 Add Voice Narration",
516
- value=True,
517
- info="Enable to add professional voice-over"
518
- )
519
-
520
- voice_type = gr.Dropdown(
521
- choices=generator.get_available_voices(),
522
- value="Default (English)",
523
- label="🗣️ Voice Type",
524
- info="Select the voice for narration",
525
- container=True
526
- )
527
-
528
- voice_script = gr.Textbox(
529
- label="📜 Narration Script (Optional)",
530
- placeholder="Enter your narration script here... (Leave blank to use video description)",
531
- lines=2,
532
- max_lines=3,
533
- info="If left blank, the video description will be used as narration",
534
- container=True
535
- )
536
-
537
  # Generate Button
538
  generate_btn = gr.Button("🚀 Generate Professional Video", variant="primary", size="lg")
539
 
@@ -549,21 +274,6 @@ def create_interface():
549
  gr.Markdown("## 🤖 AI Model Details")
550
  model_info = gr.JSON(label="Current Model Specifications")
551
 
552
- # Pricing Information
553
- with gr.Group():
554
- gr.Markdown("## 💰 Pricing")
555
- gr.Markdown("""
556
- **Free Tier:** 5 videos per day
557
-
558
- **Pro Plan:** $9.99/month
559
- - Unlimited videos
560
- - Priority processing
561
- - HD quality
562
- - Advanced features
563
-
564
- **Enterprise:** Contact us
565
- """)
566
-
567
  # Examples
568
  with gr.Group():
569
  gr.Markdown("## 💡 Inspiration Examples")
@@ -575,7 +285,6 @@ def create_interface():
575
  • A futuristic city with flying cars and neon lights
576
  • A butterfly emerging from a cocoon in a garden
577
  • A rocket launching into space with fire and smoke
578
- • Two anthropomorphic cats in comfy boxing gear and bright gloves fight intensely on a spotlighted stage
579
  • A majestic dragon soaring through a mystical forest with glowing mushrooms
580
  """)
581
 
@@ -587,13 +296,8 @@ def create_interface():
587
  - State-of-the-art video generation
588
  - Quality vs speed options
589
 
590
- 🎤 **Professional Voice-Over**
591
- - Multiple voice types
592
- - Custom narration scripts
593
-
594
  🎨 **Advanced Controls**
595
  - Quality settings
596
- - Resolution options
597
  - Reproducible results
598
 
599
  ⚡ **Fast Processing**
@@ -604,7 +308,7 @@ def create_interface():
604
  # Event handlers
605
  generate_btn.click(
606
  fn=generate_video_interface,
607
- inputs=[prompt, model_id, num_frames, fps, num_inference_steps, guidance_scale, seed, resolution, voice_script, voice_type, add_voice],
608
  outputs=[video_output, status_text]
609
  )
610
 
@@ -613,25 +317,12 @@ def create_interface():
613
  info = generator.get_model_info(model_id)
614
  return info
615
 
616
- # Show/hide resolution selector based on model
617
- def update_resolution_visibility(model_id):
618
- if model_id == "Wan-AI/Wan2.1-T2V-14B":
619
- return gr.Dropdown(visible=True)
620
- else:
621
- return gr.Dropdown(visible=False)
622
-
623
  model_id.change(
624
  fn=update_model_info,
625
  inputs=model_id,
626
  outputs=model_info
627
  )
628
 
629
- model_id.change(
630
- fn=update_resolution_visibility,
631
- inputs=model_id,
632
- outputs=resolution
633
- )
634
-
635
  # Load initial model info
636
  interface.load(lambda: generator.get_model_info(generator.get_available_models()[0]), outputs=model_info)
637
 
 
1
  import torch
2
  import gradio as gr
3
  from diffusers import DiffusionPipeline, DPMSolverMultistepScheduler
 
4
  import numpy as np
5
  import os
6
  import logging
 
 
7
  import tempfile
8
+ import subprocess
9
+ import json
10
 
11
  # Set up logging
12
  logging.basicConfig(level=logging.INFO)
 
19
  self.device = "cuda" if torch.cuda.is_available() else "cpu"
20
  logger.info(f"Using device: {self.device}")
21
 
22
+ # Available models - simplified for compatibility
23
  self.models = {
24
  "damo-vilab/text-to-video-ms-1.7b": {
25
  "name": "DAMO Text-to-Video MS-1.7B",
 
36
  "fps": 6,
37
  "quality": "Excellent",
38
  "speed": "Medium"
 
 
 
 
 
 
 
 
 
 
39
  }
40
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  def load_model(self, model_id):
43
  """Load the specified model"""
 
51
  if torch.cuda.is_available():
52
  torch.cuda.empty_cache()
53
 
54
+ # Standard loading for models
55
+ self.pipeline = DiffusionPipeline.from_pretrained(
56
+ model_id,
57
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32,
58
+ variant="fp16" if self.device == "cuda" else None
59
+ )
 
 
 
 
 
 
 
 
 
 
60
 
61
  # Move to device
62
  self.pipeline = self.pipeline.to(self.device)
 
80
  logger.error(f"Error loading model: {str(e)}")
81
  return f"Error loading model: {str(e)}"
82
 
83
+ def generate_video(self, prompt, model_id, num_frames=16, fps=8, num_inference_steps=25, guidance_scale=7.5, seed=None):
84
+ """Generate video from text prompt"""
85
  try:
 
 
 
 
86
  # Load model if not already loaded
87
  if self.current_model != model_id:
88
  load_result = self.load_model(model_id)
 
100
  num_frames = min(num_frames, model_config["max_frames"])
101
  fps = model_config["fps"]
102
 
103
+ logger.info(f"Generating video with prompt: {prompt}")
104
+ logger.info(f"Parameters: frames={num_frames}, fps={fps}, steps={num_inference_steps}")
105
+
106
+ # Generate video
107
+ result = self.pipeline(
108
+ prompt,
109
+ num_inference_steps=num_inference_steps,
110
+ guidance_scale=guidance_scale,
111
+ num_frames=num_frames
112
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
+ # Extract frames
115
+ if hasattr(result, 'frames'):
116
+ video_frames = result.frames
117
+ elif isinstance(result, dict) and 'frames' in result:
118
+ video_frames = result['frames']
119
+ else:
120
+ video_frames = result
121
 
122
  # Save video
123
+ output_path = tempfile.mktemp(suffix=".mp4")
124
+
125
+ # Use diffusers export_to_video function
126
+ from diffusers.utils import export_to_video
127
  export_to_video(video_frames, output_path, fps=fps)
128
 
129
+ logger.info(f"Video generated successfully: {output_path}")
130
+ return output_path, f"Video generated successfully! Model: {model_config['name']}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
 
132
  except Exception as e:
133
  logger.error(f"Error generating video: {str(e)}")
134
  return None, f"Error generating video: {str(e)}"
135
 
136
  def get_available_models(self):
137
+ """Get list of available model IDs"""
138
  return list(self.models.keys())
139
 
140
  def get_model_info(self, model_id):
141
+ """Get detailed information about a model"""
142
  if model_id in self.models:
143
  return self.models[model_id]
144
+ return {"error": "Model not found"}
 
 
 
 
 
 
 
145
 
146
  def create_interface():
147
+ """Create the Gradio interface"""
148
+ generator = TextToVideoGenerator()
149
 
150
+ def generate_video_interface(prompt, model_id, num_frames, fps, num_inference_steps, guidance_scale, seed):
151
+ """Interface function for video generation"""
152
  if not prompt.strip():
153
+ return None, "Please enter a video description"
154
 
155
+ video_path, status = generator.generate_video(
156
  prompt=prompt,
157
  model_id=model_id,
158
  num_frames=num_frames,
159
  fps=fps,
160
  num_inference_steps=num_inference_steps,
161
  guidance_scale=guidance_scale,
162
+ seed=seed
 
 
 
 
163
  )
164
+
165
+ return video_path, status
166
 
167
+ # Custom CSS for better styling
168
  custom_css = """
169
  .gradio-container {
170
  max-width: 1200px !important;
171
  margin: 0 auto !important;
172
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  .generate-btn {
174
+ background: linear-gradient(45deg, #667eea 0%, #764ba2 100%) !important;
175
  border: none !important;
176
  color: white !important;
177
+ font-weight: bold !important;
 
 
 
 
 
 
 
 
 
178
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  .status-box {
180
+ background-color: #f8f9fa !important;
181
+ border: 1px solid #dee2e6 !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  }
183
  """
184
 
 
206
  container=True
207
  )
208
 
209
+ model_id = gr.Dropdown(
210
+ choices=generator.get_available_models(),
211
+ value=generator.get_available_models()[0],
212
+ label="🤖 AI Model",
213
+ info="Choose the AI model for video generation",
214
+ container=True
215
+ )
 
 
 
 
 
 
 
 
 
 
216
 
217
  with gr.Row():
218
  num_frames = gr.Slider(
 
259
  container=True
260
  )
261
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  # Generate Button
263
  generate_btn = gr.Button("🚀 Generate Professional Video", variant="primary", size="lg")
264
 
 
274
  gr.Markdown("## 🤖 AI Model Details")
275
  model_info = gr.JSON(label="Current Model Specifications")
276
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  # Examples
278
  with gr.Group():
279
  gr.Markdown("## 💡 Inspiration Examples")
 
285
  • A futuristic city with flying cars and neon lights
286
  • A butterfly emerging from a cocoon in a garden
287
  • A rocket launching into space with fire and smoke
 
288
  • A majestic dragon soaring through a mystical forest with glowing mushrooms
289
  """)
290
 
 
296
  - State-of-the-art video generation
297
  - Quality vs speed options
298
 
 
 
 
 
299
  🎨 **Advanced Controls**
300
  - Quality settings
 
301
  - Reproducible results
302
 
303
  ⚡ **Fast Processing**
 
308
  # Event handlers
309
  generate_btn.click(
310
  fn=generate_video_interface,
311
+ inputs=[prompt, model_id, num_frames, fps, num_inference_steps, guidance_scale, seed],
312
  outputs=[video_output, status_text]
313
  )
314
 
 
317
  info = generator.get_model_info(model_id)
318
  return info
319
 
 
 
 
 
 
 
 
320
  model_id.change(
321
  fn=update_model_info,
322
  inputs=model_id,
323
  outputs=model_info
324
  )
325
 
 
 
 
 
 
 
326
  # Load initial model info
327
  interface.load(lambda: generator.get_model_info(generator.get_available_models()[0]), outputs=model_info)
328
 
requirements.txt CHANGED
@@ -11,6 +11,4 @@ gradio==4.25.0
11
  huggingface-hub==0.23.0
12
  xformers==0.0.25
13
  imageio==2.34.0
14
- imageio-ffmpeg==0.4.9
15
- gTTS==2.5.1
16
- moviepy==1.0.3
 
11
  huggingface-hub==0.23.0
12
  xformers==0.0.25
13
  imageio==2.34.0
14
+ imageio-ffmpeg==0.4.9
 
 
text-to-video-generator/app.py CHANGED
@@ -1,13 +1,12 @@
1
  import torch
2
  import gradio as gr
3
  from diffusers import DiffusionPipeline, DPMSolverMultistepScheduler
4
- from diffusers.utils import export_to_video
5
  import numpy as np
6
  import os
7
  import logging
8
- from gtts import gTTS
9
- from moviepy.editor import VideoFileClip, AudioFileClip, CompositeAudioClip
10
  import tempfile
 
 
11
 
12
  # Set up logging
13
  logging.basicConfig(level=logging.INFO)
@@ -20,7 +19,7 @@ class TextToVideoGenerator:
20
  self.device = "cuda" if torch.cuda.is_available() else "cpu"
21
  logger.info(f"Using device: {self.device}")
22
 
23
- # Available models - including the advanced Wan2.1 model
24
  self.models = {
25
  "damo-vilab/text-to-video-ms-1.7b": {
26
  "name": "DAMO Text-to-Video MS-1.7B",
@@ -37,70 +36,8 @@ class TextToVideoGenerator:
37
  "fps": 6,
38
  "quality": "Excellent",
39
  "speed": "Medium"
40
- },
41
- "Wan-AI/Wan2.1-T2V-14B": {
42
- "name": "Wan2.1-T2V-14B (SOTA)",
43
- "description": "State-of-the-art text-to-video model with 14B parameters",
44
- "max_frames": 32,
45
- "fps": 8,
46
- "quality": "SOTA",
47
- "speed": "Medium",
48
- "resolutions": ["480P", "720P"],
49
- "features": ["Chinese & English text", "High motion dynamics", "Best quality"]
50
  }
51
  }
52
-
53
- # Voice options (gTTS only supports language, not gender/age)
54
- self.voices = {
55
- "Default (English)": "en"
56
- }
57
-
58
- def generate_audio(self, text, voice_type):
59
- """Generate audio from text using gTTS"""
60
- try:
61
- lang = self.voices[voice_type]
62
- tts = gTTS(text=text, lang=lang)
63
- with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as temp_audio:
64
- audio_path = temp_audio.name
65
- tts.save(audio_path)
66
- logger.info(f"Audio generated successfully: {audio_path}")
67
- return audio_path
68
- except Exception as e:
69
- logger.error(f"Error generating audio: {str(e)}")
70
- return None
71
-
72
- def merge_audio_video(self, video_path, audio_path, output_path):
73
- """Merge audio and video using moviepy"""
74
- try:
75
- # Load video and audio
76
- video_clip = VideoFileClip(video_path)
77
- audio_clip = AudioFileClip(audio_path)
78
-
79
- # Ensure audio duration matches video duration
80
- if audio_clip.duration > video_clip.duration:
81
- audio_clip = audio_clip.subclip(0, video_clip.duration)
82
- elif audio_clip.duration < video_clip.duration:
83
- # Loop audio if it's shorter than video
84
- loops_needed = int(video_clip.duration / audio_clip.duration) + 1
85
- audio_clip = CompositeAudioClip([audio_clip] * loops_needed).subclip(0, video_clip.duration)
86
-
87
- # Merge audio and video
88
- final_clip = video_clip.set_audio(audio_clip)
89
-
90
- # Write final video with audio
91
- final_clip.write_videofile(output_path, codec='libx264', audio_codec='aac')
92
-
93
- # Clean up
94
- video_clip.close()
95
- audio_clip.close()
96
- final_clip.close()
97
-
98
- logger.info(f"Audio and video merged successfully: {output_path}")
99
- return output_path
100
-
101
- except Exception as e:
102
- logger.error(f"Error merging audio and video: {str(e)}")
103
- return None
104
 
105
  def load_model(self, model_id):
106
  """Load the specified model"""
@@ -114,22 +51,12 @@ class TextToVideoGenerator:
114
  if torch.cuda.is_available():
115
  torch.cuda.empty_cache()
116
 
117
- # Special handling for Wan2.1 model
118
- if model_id == "Wan-AI/Wan2.1-T2V-14B":
119
- # Wan2.1 requires specific configuration
120
- self.pipeline = DiffusionPipeline.from_pretrained(
121
- model_id,
122
- torch_dtype=torch.float16 if self.device == "cuda" else torch.float32,
123
- variant="fp16" if self.device == "cuda" else None,
124
- use_safetensors=True
125
- )
126
- else:
127
- # Standard loading for other models
128
- self.pipeline = DiffusionPipeline.from_pretrained(
129
- model_id,
130
- torch_dtype=torch.float16 if self.device == "cuda" else torch.float32,
131
- variant="fp16" if self.device == "cuda" else None
132
- )
133
 
134
  # Move to device
135
  self.pipeline = self.pipeline.to(self.device)
@@ -153,13 +80,9 @@ class TextToVideoGenerator:
153
  logger.error(f"Error loading model: {str(e)}")
154
  return f"Error loading model: {str(e)}"
155
 
156
- def generate_video(self, prompt, model_id, num_frames=16, fps=8, num_inference_steps=25, guidance_scale=7.5, seed=None, resolution="480P", voice_script="", voice_type="Default (English)", add_voice=True):
157
- """Generate video from text prompt with optional voice"""
158
  try:
159
- # Use prompt as voice script if voice_script is empty
160
- if not voice_script.strip() and add_voice:
161
- voice_script = prompt
162
-
163
  # Load model if not already loaded
164
  if self.current_model != model_id:
165
  load_result = self.load_model(model_id)
@@ -177,245 +100,85 @@ class TextToVideoGenerator:
177
  num_frames = min(num_frames, model_config["max_frames"])
178
  fps = model_config["fps"]
179
 
180
- # Special handling for Wan2.1 model
181
- if model_id == "Wan-AI/Wan2.1-T2V-14B":
182
- # Wan2.1 specific parameters
183
- if resolution == "720P":
184
- width, height = 1280, 720
185
- else: # 480P
186
- width, height = 832, 480
187
-
188
- logger.info(f"Generating Wan2.1 video with prompt: {prompt}")
189
- logger.info(f"Parameters: frames={num_frames}, fps={fps}, steps={num_inference_steps}, resolution={resolution}")
190
-
191
- # Generate video with Wan2.1 specific settings
192
- result = self.pipeline(
193
- prompt,
194
- num_inference_steps=num_inference_steps,
195
- guidance_scale=guidance_scale,
196
- num_frames=num_frames,
197
- width=width,
198
- height=height
199
- )
200
- video_frames = result['frames'] if isinstance(result, dict) else result.frames
201
- else:
202
- # Standard generation for other models
203
- logger.info(f"Generating video with prompt: {prompt}")
204
- logger.info(f"Parameters: frames={num_frames}, fps={fps}, steps={num_inference_steps}")
205
-
206
- result = self.pipeline(
207
- prompt,
208
- num_inference_steps=num_inference_steps,
209
- guidance_scale=guidance_scale,
210
- num_frames=num_frames
211
- )
212
- video_frames = result['frames'] if isinstance(result, dict) else result.frames
213
 
214
- # Convert to numpy array
215
- video_frames = np.array(video_frames)
 
 
 
 
 
216
 
217
  # Save video
218
- output_path = f"generated_video_{seed if seed else 'random'}.mp4"
 
 
 
219
  export_to_video(video_frames, output_path, fps=fps)
220
 
221
- logger.info(f"Video saved to: {output_path}")
222
-
223
- # Add voice if requested
224
- if add_voice and voice_script.strip():
225
- logger.info(f"Generating voice for script: {voice_script}")
226
-
227
- # Generate audio
228
- audio_path = self.generate_audio(voice_script, voice_type)
229
-
230
- if audio_path:
231
- # Create final output path with voice
232
- final_output_path = f"generated_video_with_voice_{seed if seed else 'random'}.mp4"
233
-
234
- # Merge audio and video
235
- final_path = self.merge_audio_video(output_path, audio_path, final_output_path)
236
-
237
- # Clean up temporary files
238
- try:
239
- os.unlink(audio_path)
240
- os.unlink(output_path)
241
- except:
242
- pass
243
-
244
- if final_path:
245
- return final_path, f"Video with voice generated successfully! Saved as {final_path}"
246
- else:
247
- return output_path, f"Video generated but voice merging failed. Saved as {output_path}"
248
- else:
249
- return output_path, f"Video generated but voice generation failed. Saved as {output_path}"
250
- else:
251
- return output_path, f"Video generated successfully! Saved as {output_path}"
252
 
253
  except Exception as e:
254
  logger.error(f"Error generating video: {str(e)}")
255
  return None, f"Error generating video: {str(e)}"
256
 
257
  def get_available_models(self):
258
- """Get list of available models"""
259
  return list(self.models.keys())
260
 
261
  def get_model_info(self, model_id):
262
- """Get information about a specific model"""
263
  if model_id in self.models:
264
  return self.models[model_id]
265
- return None
266
-
267
- def get_available_voices(self):
268
- """Get list of available voices"""
269
- return list(self.voices.keys())
270
-
271
- # Initialize the generator
272
- generator = TextToVideoGenerator()
273
 
274
  def create_interface():
275
- """Create Gradio interface"""
 
276
 
277
- def generate_video_interface(prompt, model_id, num_frames, fps, num_inference_steps, guidance_scale, seed, resolution, voice_script, voice_type, add_voice):
 
278
  if not prompt.strip():
279
- return None, "Please enter a prompt"
280
 
281
- return generator.generate_video(
282
  prompt=prompt,
283
  model_id=model_id,
284
  num_frames=num_frames,
285
  fps=fps,
286
  num_inference_steps=num_inference_steps,
287
  guidance_scale=guidance_scale,
288
- seed=seed,
289
- resolution=resolution,
290
- voice_script=voice_script,
291
- voice_type=voice_type,
292
- add_voice=add_voice
293
  )
 
 
294
 
295
- # Custom CSS for professional styling
296
  custom_css = """
297
  .gradio-container {
298
  max-width: 1200px !important;
299
  margin: 0 auto !important;
300
  }
301
-
302
- .header {
303
- text-align: center;
304
- padding: 2rem 0;
305
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
306
- color: white;
307
- border-radius: 15px;
308
- margin-bottom: 2rem;
309
- }
310
-
311
- .header h1 {
312
- font-size: 2.5rem;
313
- font-weight: 700;
314
- margin: 0;
315
- text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
316
- }
317
-
318
- .header p {
319
- font-size: 1.1rem;
320
- margin: 0.5rem 0 0 0;
321
- opacity: 0.9;
322
- }
323
-
324
- .feature-card {
325
- background: white;
326
- border-radius: 10px;
327
- padding: 1.5rem;
328
- box-shadow: 0 4px 6px rgba(0,0,0,0.1);
329
- margin-bottom: 1rem;
330
- border-left: 4px solid #667eea;
331
- }
332
-
333
- .feature-card h3 {
334
- color: #333;
335
- margin: 0 0 0.5rem 0;
336
- font-size: 1.2rem;
337
- }
338
-
339
- .feature-card p {
340
- color: #666;
341
- margin: 0;
342
- font-size: 0.9rem;
343
- }
344
-
345
- .model-info {
346
- background: #f8f9fa;
347
- border-radius: 8px;
348
- padding: 1rem;
349
- border: 1px solid #e9ecef;
350
- }
351
-
352
- .model-info h4 {
353
- color: #495057;
354
- margin: 0 0 0.5rem 0;
355
- font-size: 1rem;
356
- }
357
-
358
- .model-info p {
359
- color: #6c757d;
360
- margin: 0.25rem 0;
361
- font-size: 0.85rem;
362
- }
363
-
364
  .generate-btn {
365
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
366
  border: none !important;
367
  color: white !important;
368
- font-weight: 600 !important;
369
- padding: 1rem 2rem !important;
370
- border-radius: 10px !important;
371
- font-size: 1.1rem !important;
372
- transition: all 0.3s ease !important;
373
- }
374
-
375
- .generate-btn:hover {
376
- transform: translateY(-2px) !important;
377
- box-shadow: 0 6px 12px rgba(102, 126, 234, 0.4) !important;
378
  }
379
-
380
- .example-card {
381
- background: #f8f9fa;
382
- border-radius: 8px;
383
- padding: 1rem;
384
- margin: 0.5rem 0;
385
- border: 1px solid #e9ecef;
386
- cursor: pointer;
387
- transition: all 0.2s ease;
388
- }
389
-
390
- .example-card:hover {
391
- background: #e9ecef;
392
- transform: translateX(5px);
393
- }
394
-
395
  .status-box {
396
- background: #e3f2fd;
397
- border: 1px solid #2196f3;
398
- border-radius: 8px;
399
- padding: 1rem;
400
- }
401
-
402
- .pricing-info {
403
- background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
404
- border-radius: 10px;
405
- padding: 1rem;
406
- text-align: center;
407
- margin: 1rem 0;
408
- }
409
-
410
- .pricing-info h4 {
411
- color: #d84315;
412
- margin: 0 0 0.5rem 0;
413
- }
414
-
415
- .pricing-info p {
416
- color: #bf360c;
417
- margin: 0;
418
- font-size: 0.9rem;
419
  }
420
  """
421
 
@@ -443,23 +206,13 @@ def create_interface():
443
  container=True
444
  )
445
 
446
- with gr.Row():
447
- model_id = gr.Dropdown(
448
- choices=generator.get_available_models(),
449
- value=generator.get_available_models()[0],
450
- label="🤖 AI Model",
451
- info="Choose the AI model for video generation",
452
- container=True
453
- )
454
-
455
- resolution = gr.Dropdown(
456
- choices=["480P", "720P"],
457
- value="480P",
458
- label="📐 Resolution (Wan2.1 only)",
459
- info="Select video resolution",
460
- visible=False,
461
- container=True
462
- )
463
 
464
  with gr.Row():
465
  num_frames = gr.Slider(
@@ -506,34 +259,6 @@ def create_interface():
506
  container=True
507
  )
508
 
509
- # Voice Section
510
- with gr.Group():
511
- gr.Markdown("## 🎤 Voice & Audio")
512
-
513
- with gr.Row():
514
- add_voice = gr.Checkbox(
515
- label="🎵 Add Voice Narration",
516
- value=True,
517
- info="Enable to add professional voice-over"
518
- )
519
-
520
- voice_type = gr.Dropdown(
521
- choices=generator.get_available_voices(),
522
- value="Default (English)",
523
- label="🗣️ Voice Type",
524
- info="Select the voice for narration",
525
- container=True
526
- )
527
-
528
- voice_script = gr.Textbox(
529
- label="📜 Narration Script (Optional)",
530
- placeholder="Enter your narration script here... (Leave blank to use video description)",
531
- lines=2,
532
- max_lines=3,
533
- info="If left blank, the video description will be used as narration",
534
- container=True
535
- )
536
-
537
  # Generate Button
538
  generate_btn = gr.Button("🚀 Generate Professional Video", variant="primary", size="lg")
539
 
@@ -549,21 +274,6 @@ def create_interface():
549
  gr.Markdown("## 🤖 AI Model Details")
550
  model_info = gr.JSON(label="Current Model Specifications")
551
 
552
- # Pricing Information
553
- with gr.Group():
554
- gr.Markdown("## 💰 Pricing")
555
- gr.Markdown("""
556
- **Free Tier:** 5 videos per day
557
-
558
- **Pro Plan:** $9.99/month
559
- - Unlimited videos
560
- - Priority processing
561
- - HD quality
562
- - Advanced features
563
-
564
- **Enterprise:** Contact us
565
- """)
566
-
567
  # Examples
568
  with gr.Group():
569
  gr.Markdown("## 💡 Inspiration Examples")
@@ -575,7 +285,6 @@ def create_interface():
575
  • A futuristic city with flying cars and neon lights
576
  • A butterfly emerging from a cocoon in a garden
577
  • A rocket launching into space with fire and smoke
578
- • Two anthropomorphic cats in comfy boxing gear and bright gloves fight intensely on a spotlighted stage
579
  • A majestic dragon soaring through a mystical forest with glowing mushrooms
580
  """)
581
 
@@ -587,13 +296,8 @@ def create_interface():
587
  - State-of-the-art video generation
588
  - Quality vs speed options
589
 
590
- 🎤 **Professional Voice-Over**
591
- - Multiple voice types
592
- - Custom narration scripts
593
-
594
  🎨 **Advanced Controls**
595
  - Quality settings
596
- - Resolution options
597
  - Reproducible results
598
 
599
  ⚡ **Fast Processing**
@@ -604,7 +308,7 @@ def create_interface():
604
  # Event handlers
605
  generate_btn.click(
606
  fn=generate_video_interface,
607
- inputs=[prompt, model_id, num_frames, fps, num_inference_steps, guidance_scale, seed, resolution, voice_script, voice_type, add_voice],
608
  outputs=[video_output, status_text]
609
  )
610
 
@@ -613,25 +317,12 @@ def create_interface():
613
  info = generator.get_model_info(model_id)
614
  return info
615
 
616
- # Show/hide resolution selector based on model
617
- def update_resolution_visibility(model_id):
618
- if model_id == "Wan-AI/Wan2.1-T2V-14B":
619
- return gr.Dropdown(visible=True)
620
- else:
621
- return gr.Dropdown(visible=False)
622
-
623
  model_id.change(
624
  fn=update_model_info,
625
  inputs=model_id,
626
  outputs=model_info
627
  )
628
 
629
- model_id.change(
630
- fn=update_resolution_visibility,
631
- inputs=model_id,
632
- outputs=resolution
633
- )
634
-
635
  # Load initial model info
636
  interface.load(lambda: generator.get_model_info(generator.get_available_models()[0]), outputs=model_info)
637
 
 
1
  import torch
2
  import gradio as gr
3
  from diffusers import DiffusionPipeline, DPMSolverMultistepScheduler
 
4
  import numpy as np
5
  import os
6
  import logging
 
 
7
  import tempfile
8
+ import subprocess
9
+ import json
10
 
11
  # Set up logging
12
  logging.basicConfig(level=logging.INFO)
 
19
  self.device = "cuda" if torch.cuda.is_available() else "cpu"
20
  logger.info(f"Using device: {self.device}")
21
 
22
+ # Available models - simplified for compatibility
23
  self.models = {
24
  "damo-vilab/text-to-video-ms-1.7b": {
25
  "name": "DAMO Text-to-Video MS-1.7B",
 
36
  "fps": 6,
37
  "quality": "Excellent",
38
  "speed": "Medium"
 
 
 
 
 
 
 
 
 
 
39
  }
40
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  def load_model(self, model_id):
43
  """Load the specified model"""
 
51
  if torch.cuda.is_available():
52
  torch.cuda.empty_cache()
53
 
54
+ # Standard loading for models
55
+ self.pipeline = DiffusionPipeline.from_pretrained(
56
+ model_id,
57
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32,
58
+ variant="fp16" if self.device == "cuda" else None
59
+ )
 
 
 
 
 
 
 
 
 
 
60
 
61
  # Move to device
62
  self.pipeline = self.pipeline.to(self.device)
 
80
  logger.error(f"Error loading model: {str(e)}")
81
  return f"Error loading model: {str(e)}"
82
 
83
+ def generate_video(self, prompt, model_id, num_frames=16, fps=8, num_inference_steps=25, guidance_scale=7.5, seed=None):
84
+ """Generate video from text prompt"""
85
  try:
 
 
 
 
86
  # Load model if not already loaded
87
  if self.current_model != model_id:
88
  load_result = self.load_model(model_id)
 
100
  num_frames = min(num_frames, model_config["max_frames"])
101
  fps = model_config["fps"]
102
 
103
+ logger.info(f"Generating video with prompt: {prompt}")
104
+ logger.info(f"Parameters: frames={num_frames}, fps={fps}, steps={num_inference_steps}")
105
+
106
+ # Generate video
107
+ result = self.pipeline(
108
+ prompt,
109
+ num_inference_steps=num_inference_steps,
110
+ guidance_scale=guidance_scale,
111
+ num_frames=num_frames
112
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
+ # Extract frames
115
+ if hasattr(result, 'frames'):
116
+ video_frames = result.frames
117
+ elif isinstance(result, dict) and 'frames' in result:
118
+ video_frames = result['frames']
119
+ else:
120
+ video_frames = result
121
 
122
  # Save video
123
+ output_path = tempfile.mktemp(suffix=".mp4")
124
+
125
+ # Use diffusers export_to_video function
126
+ from diffusers.utils import export_to_video
127
  export_to_video(video_frames, output_path, fps=fps)
128
 
129
+ logger.info(f"Video generated successfully: {output_path}")
130
+ return output_path, f"Video generated successfully! Model: {model_config['name']}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
 
132
  except Exception as e:
133
  logger.error(f"Error generating video: {str(e)}")
134
  return None, f"Error generating video: {str(e)}"
135
 
136
  def get_available_models(self):
137
+ """Get list of available model IDs"""
138
  return list(self.models.keys())
139
 
140
  def get_model_info(self, model_id):
141
+ """Get detailed information about a model"""
142
  if model_id in self.models:
143
  return self.models[model_id]
144
+ return {"error": "Model not found"}
 
 
 
 
 
 
 
145
 
146
  def create_interface():
147
+ """Create the Gradio interface"""
148
+ generator = TextToVideoGenerator()
149
 
150
+ def generate_video_interface(prompt, model_id, num_frames, fps, num_inference_steps, guidance_scale, seed):
151
+ """Interface function for video generation"""
152
  if not prompt.strip():
153
+ return None, "Please enter a video description"
154
 
155
+ video_path, status = generator.generate_video(
156
  prompt=prompt,
157
  model_id=model_id,
158
  num_frames=num_frames,
159
  fps=fps,
160
  num_inference_steps=num_inference_steps,
161
  guidance_scale=guidance_scale,
162
+ seed=seed
 
 
 
 
163
  )
164
+
165
+ return video_path, status
166
 
167
+ # Custom CSS for better styling
168
  custom_css = """
169
  .gradio-container {
170
  max-width: 1200px !important;
171
  margin: 0 auto !important;
172
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  .generate-btn {
174
+ background: linear-gradient(45deg, #667eea 0%, #764ba2 100%) !important;
175
  border: none !important;
176
  color: white !important;
177
+ font-weight: bold !important;
 
 
 
 
 
 
 
 
 
178
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  .status-box {
180
+ background-color: #f8f9fa !important;
181
+ border: 1px solid #dee2e6 !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  }
183
  """
184
 
 
206
  container=True
207
  )
208
 
209
+ model_id = gr.Dropdown(
210
+ choices=generator.get_available_models(),
211
+ value=generator.get_available_models()[0],
212
+ label="🤖 AI Model",
213
+ info="Choose the AI model for video generation",
214
+ container=True
215
+ )
 
 
 
 
 
 
 
 
 
 
216
 
217
  with gr.Row():
218
  num_frames = gr.Slider(
 
259
  container=True
260
  )
261
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  # Generate Button
263
  generate_btn = gr.Button("🚀 Generate Professional Video", variant="primary", size="lg")
264
 
 
274
  gr.Markdown("## 🤖 AI Model Details")
275
  model_info = gr.JSON(label="Current Model Specifications")
276
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  # Examples
278
  with gr.Group():
279
  gr.Markdown("## 💡 Inspiration Examples")
 
285
  • A futuristic city with flying cars and neon lights
286
  • A butterfly emerging from a cocoon in a garden
287
  • A rocket launching into space with fire and smoke
 
288
  • A majestic dragon soaring through a mystical forest with glowing mushrooms
289
  """)
290
 
 
296
  - State-of-the-art video generation
297
  - Quality vs speed options
298
 
 
 
 
 
299
  🎨 **Advanced Controls**
300
  - Quality settings
 
301
  - Reproducible results
302
 
303
  ⚡ **Fast Processing**
 
308
  # Event handlers
309
  generate_btn.click(
310
  fn=generate_video_interface,
311
+ inputs=[prompt, model_id, num_frames, fps, num_inference_steps, guidance_scale, seed],
312
  outputs=[video_output, status_text]
313
  )
314
 
 
317
  info = generator.get_model_info(model_id)
318
  return info
319
 
 
 
 
 
 
 
 
320
  model_id.change(
321
  fn=update_model_info,
322
  inputs=model_id,
323
  outputs=model_info
324
  )
325
 
 
 
 
 
 
 
326
  # Load initial model info
327
  interface.load(lambda: generator.get_model_info(generator.get_available_models()[0]), outputs=model_info)
328
 
text-to-video-generator/requirements.txt CHANGED
@@ -11,6 +11,4 @@ gradio==4.25.0
11
  huggingface-hub==0.23.0
12
  xformers==0.0.25
13
  imageio==2.34.0
14
- imageio-ffmpeg==0.4.9
15
- gTTS==2.5.1
16
- moviepy==1.0.3
 
11
  huggingface-hub==0.23.0
12
  xformers==0.0.25
13
  imageio==2.34.0
14
+ imageio-ffmpeg==0.4.9