shaheerawan3 commited on
Commit
5a6a643
·
verified ·
1 Parent(s): cb13d56

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +175 -51
app.py CHANGED
@@ -1,7 +1,8 @@
1
- import streamlit as st
 
2
  from pathlib import Path
3
  import torch
4
- from transformers import pipeline
5
  from PIL import Image, ImageDraw, ImageFont
6
  import tempfile
7
  import os
@@ -13,6 +14,8 @@ from concurrent.futures import ThreadPoolExecutor
13
  import io
14
  import unicodedata
15
  import re
 
 
16
  import logging
17
  from typing import Optional, List, Dict, Tuple
18
 
@@ -22,13 +25,13 @@ class EnhancedVideoGenerator:
22
  try:
23
  self.setup_logging()
24
  self.setup_device()
 
25
  self.setup_workspace()
26
  self.load_assets()
27
  self.setup_themes()
28
- self.initialize_models()
29
  except Exception as e:
30
- self.logger.error(f"Initialization failed: {str(e)}")
31
- raise RuntimeError(f"Failed to initialize video generator: {str(e)}")
32
 
33
  def setup_logging(self):
34
  """Configure logging for the application"""
@@ -50,15 +53,22 @@ class EnhancedVideoGenerator:
50
  def initialize_models(self):
51
  """Initialize all AI models"""
52
  try:
53
- # Text generation model - using a smaller model for better compatibility
54
  self.text_generator = pipeline(
55
  'text-generation',
56
- model='distilgpt2',
57
  device=0 if self.device == "cuda" else -1
58
  )
 
 
 
 
 
 
 
59
  except Exception as e:
60
  self.logger.error(f"Model initialization failed: {str(e)}")
61
- self.text_generator = None
62
 
63
  def setup_workspace(self):
64
  """Set up working directory and resources"""
@@ -108,29 +118,24 @@ class EnhancedVideoGenerator:
108
 
109
  except Exception as e:
110
  self.logger.error(f"Asset loading failed: {str(e)}")
111
- self.font = ImageFont.load_default()
112
 
113
  def generate_visual_assets(self, script: str, style: str) -> List[Dict]:
114
- """Generate or fetch relevant visual assets based on script content"""
115
  try:
116
- # Generate simple colored backgrounds instead of AI images
117
- colors = [
118
- (240, 248, 255), # AliceBlue
119
- (240, 255, 255), # Azure
120
- (245, 245, 245), # WhiteSmoke
121
- (255, 250, 250), # Snow
122
- (248, 248, 255) # GhostWhite
123
- ]
124
 
125
  assets = []
126
- for i in range(5): # Generate 5 different backgrounds
127
- img = Image.new('RGB', (1920, 1080), colors[i])
128
- assets.append({
129
- 'type': 'image',
130
- 'data': img,
131
- 'topic': f'background_{i}'
132
- })
133
-
 
 
134
  return assets
135
 
136
  except Exception as e:
@@ -144,12 +149,13 @@ class EnhancedVideoGenerator:
144
  frame_number: int,
145
  total_frames: int,
146
  background_image: Optional[Image.Image] = None,
147
- size: Tuple[int, int] = (1920, 1080)
148
  ) -> np.ndarray:
149
  """Create a visually enhanced frame with background, text, and effects"""
150
  try:
151
  # Create base frame
152
  if background_image:
 
153
  bg = background_image.resize(size, Image.LANCZOS)
154
  frame = np.array(bg)
155
  else:
@@ -159,6 +165,15 @@ class EnhancedVideoGenerator:
159
  img = Image.fromarray(frame)
160
  draw = ImageDraw.Draw(img, 'RGBA')
161
 
 
 
 
 
 
 
 
 
 
162
  # Add text with improved styling
163
  text = self.clean_text(text)
164
  wrapped_text = textwrap.fill(text, width=50)
@@ -168,7 +183,7 @@ class EnhancedVideoGenerator:
168
  text_width = text_bbox[2] - text_bbox[0]
169
  text_height = text_bbox[3] - text_bbox[1]
170
  text_x = (size[0] - text_width) // 2
171
- text_y = size[1] - text_height - 100
172
 
173
  # Draw text background
174
  padding = 20
@@ -179,7 +194,7 @@ class EnhancedVideoGenerator:
179
  text_x + text_width + padding,
180
  text_y + text_height + padding
181
  ],
182
- fill=(0, 0, 0, 160)
183
  )
184
 
185
  # Draw text
@@ -190,7 +205,7 @@ class EnhancedVideoGenerator:
190
  font=self.font
191
  )
192
 
193
- # Add progress bar
194
  self.draw_animated_progress_bar(
195
  draw,
196
  frame_number,
@@ -203,6 +218,7 @@ class EnhancedVideoGenerator:
203
 
204
  except Exception as e:
205
  self.logger.error(f"Frame creation failed: {str(e)}")
 
206
  return np.full((size[1], size[0], 3), theme['bg'], dtype=np.uint8)
207
 
208
  def draw_animated_progress_bar(
@@ -213,10 +229,10 @@ class EnhancedVideoGenerator:
213
  size: Tuple[int, int],
214
  theme: dict
215
  ):
216
- """Draw an animated progress bar"""
217
  try:
218
  progress = frame_number / total_frames
219
- bar_width = int(size[0] * 0.8)
220
  bar_height = 6
221
  x_offset = (size[0] - bar_width) // 2
222
  y_position = size[1] - 40
@@ -227,18 +243,28 @@ class EnhancedVideoGenerator:
227
  fill=(200, 200, 200, 160)
228
  )
229
 
230
- # Draw progress
231
  progress_width = int(bar_width * progress)
232
- draw.rectangle(
233
- [x_offset, y_position, x_offset + progress_width, y_position + bar_height],
234
- fill=theme['accent']
235
- )
 
 
 
 
 
 
 
 
 
 
236
 
237
  except Exception as e:
238
  self.logger.error(f"Progress bar drawing failed: {str(e)}")
239
 
240
  def generate_voice_over(self, script: str) -> AudioFileClip:
241
- """Generate voice-over audio"""
242
  try:
243
  audio_path = self.temp_dir / "voice.mp3"
244
  tts = gTTS(
@@ -260,7 +286,7 @@ class EnhancedVideoGenerator:
260
  duration: int,
261
  output_path: str
262
  ) -> str:
263
- """Create full video with all features"""
264
  try:
265
  # Generate visual assets
266
  assets = self.generate_visual_assets(script, style)
@@ -268,7 +294,7 @@ class EnhancedVideoGenerator:
268
  # Generate voice-over
269
  audio = self.generate_voice_over(script)
270
 
271
- # Create frames
272
  frames = []
273
  fps = 30
274
  total_frames = int(duration * fps)
@@ -277,13 +303,16 @@ class EnhancedVideoGenerator:
277
  frame_futures = []
278
 
279
  for i in range(total_frames):
 
280
  progress = i / total_frames
281
  text_index = int(progress * len(script.split()))
282
  current_text = " ".join(script.split()[:text_index + 1])
283
 
 
284
  asset_index = int(progress * len(assets))
285
  current_asset = assets[asset_index] if assets else None
286
 
 
287
  future = executor.submit(
288
  self.create_enhanced_frame,
289
  current_text,
@@ -294,6 +323,7 @@ class EnhancedVideoGenerator:
294
  )
295
  frame_futures.append(future)
296
 
 
297
  frames = [future.result() for future in frame_futures]
298
 
299
  # Create video clip
@@ -302,6 +332,14 @@ class EnhancedVideoGenerator:
302
  # Add voice-over
303
  video = video.set_audio(audio)
304
 
 
 
 
 
 
 
 
 
305
  # Write final video
306
  video.write_videofile(
307
  output_path,
@@ -324,25 +362,84 @@ class EnhancedVideoGenerator:
324
  if not isinstance(text, str):
325
  text = str(text)
326
 
 
327
  text = unicodedata.normalize('NFKD', text)
 
 
328
  text = text.encode('ascii', 'ignore').decode('ascii')
329
 
 
330
  replacements = {
331
- '–': '-',
332
- '—': '-',
333
- '"': '"',
334
- '"': '"',
335
- ''': "'",
336
- ''': "'",
337
- '…': '...',
338
  }
339
  for old, new in replacements.items():
340
  text = text.replace(old, new)
341
 
 
342
  text = re.sub(r'[^\x00-\x7F]+', '', text)
343
 
344
  return text.strip()
345
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  def cleanup(self):
347
  """Clean up temporary files and resources"""
348
  try:
@@ -367,6 +464,7 @@ class EnhancedVideoGenerator:
367
  def __exit__(self, exc_type, exc_val, exc_tb):
368
  self.cleanup()
369
 
 
370
  class VideoGeneratorUI:
371
  def __init__(self):
372
  self.generator = EnhancedVideoGenerator()
@@ -377,10 +475,11 @@ class VideoGeneratorUI:
377
  st.write("Create professional videos with AI-generated content")
378
 
379
  with st.form("video_generator_form"):
 
380
  prompt = st.text_area(
381
- "Enter your video script",
382
  height=100,
383
- help="Enter the text you want in your video"
384
  )
385
 
386
  col1, col2 = st.columns(2)
@@ -399,17 +498,41 @@ class VideoGeneratorUI:
399
  step=10
400
  )
401
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
  submit_button = st.form_submit_button("Generate Video")
403
 
404
  if submit_button:
405
  if not prompt:
406
- st.error("Please enter a script for your video.")
407
  return
408
 
409
  try:
410
  with st.spinner("Generating your video..."):
411
  output_path = f"generated_video_{int(time.time())}.mp4"
412
 
 
 
 
 
413
  video_path = self.generator.create_video(
414
  prompt,
415
  style,
@@ -417,6 +540,7 @@ class VideoGeneratorUI:
417
  output_path
418
  )
419
 
 
420
  st.success("Video generated successfully!")
421
 
422
  with open(video_path, 'rb') as f:
@@ -429,7 +553,7 @@ class VideoGeneratorUI:
429
 
430
  except Exception as e:
431
  st.error(f"Failed to generate video: {str(e)}")
432
- st.error("Please try again with different settings.")
433
 
434
  if __name__ == "__main__":
435
  ui = VideoGeneratorUI()
 
1
+
2
+ import streamlit as st
3
  from pathlib import Path
4
  import torch
5
+ from transformers import pipeline, AutoModelForCausalLM, AutoTokenizer
6
  from PIL import Image, ImageDraw, ImageFont
7
  import tempfile
8
  import os
 
14
  import io
15
  import unicodedata
16
  import re
17
+ import requests
18
+ import random
19
  import logging
20
  from typing import Optional, List, Dict, Tuple
21
 
 
25
  try:
26
  self.setup_logging()
27
  self.setup_device()
28
+ self.initialize_models()
29
  self.setup_workspace()
30
  self.load_assets()
31
  self.setup_themes()
 
32
  except Exception as e:
33
+ logging.error(f"Initialization failed: {str(e)}")
34
+ raise RuntimeError("Failed to initialize video generator")
35
 
36
  def setup_logging(self):
37
  """Configure logging for the application"""
 
53
  def initialize_models(self):
54
  """Initialize all AI models"""
55
  try:
56
+ # Text generation model
57
  self.text_generator = pipeline(
58
  'text-generation',
59
+ model='gpt2',
60
  device=0 if self.device == "cuda" else -1
61
  )
62
+
63
+ # Initialize free image generation model
64
+ self.image_model = AutoModelForCausalLM.from_pretrained(
65
+ "CompVis/stable-diffusion-v1-4",
66
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32
67
+ ).to(self.device)
68
+
69
  except Exception as e:
70
  self.logger.error(f"Model initialization failed: {str(e)}")
71
+ raise
72
 
73
  def setup_workspace(self):
74
  """Set up working directory and resources"""
 
118
 
119
  except Exception as e:
120
  self.logger.error(f"Asset loading failed: {str(e)}")
 
121
 
122
  def generate_visual_assets(self, script: str, style: str) -> List[Dict]:
123
+ """Generate relevant visual assets based on script content"""
124
  try:
125
+ # Extract key topics from script
126
+ topics = self.extract_key_topics(script)
 
 
 
 
 
 
127
 
128
  assets = []
129
+ for topic in topics:
130
+ # Generate AI image
131
+ image = self.generate_ai_image(topic, style)
132
+ if image:
133
+ assets.append({
134
+ 'type': 'image',
135
+ 'data': image,
136
+ 'topic': topic
137
+ })
138
+
139
  return assets
140
 
141
  except Exception as e:
 
149
  frame_number: int,
150
  total_frames: int,
151
  background_image: Optional[Image.Image] = None,
152
+ size: Tuple[int, int] = (1920, 1080) # Upgraded to 1080p
153
  ) -> np.ndarray:
154
  """Create a visually enhanced frame with background, text, and effects"""
155
  try:
156
  # Create base frame
157
  if background_image:
158
+ # Resize and crop background to fit
159
  bg = background_image.resize(size, Image.LANCZOS)
160
  frame = np.array(bg)
161
  else:
 
165
  img = Image.fromarray(frame)
166
  draw = ImageDraw.Draw(img, 'RGBA')
167
 
168
+ # Add subtle gradient overlay
169
+ overlay = Image.new('RGBA', size, (0, 0, 0, 0))
170
+ overlay_draw = ImageDraw.Draw(overlay)
171
+ overlay_draw.rectangle(
172
+ [0, 0, size[0], size[1]],
173
+ fill=(255, 255, 255, 100) # Semi-transparent white
174
+ )
175
+ img = Image.alpha_composite(img.convert('RGBA'), overlay)
176
+
177
  # Add text with improved styling
178
  text = self.clean_text(text)
179
  wrapped_text = textwrap.fill(text, width=50)
 
183
  text_width = text_bbox[2] - text_bbox[0]
184
  text_height = text_bbox[3] - text_bbox[1]
185
  text_x = (size[0] - text_width) // 2
186
+ text_y = size[1] - text_height - 100 # Position at bottom
187
 
188
  # Draw text background
189
  padding = 20
 
194
  text_x + text_width + padding,
195
  text_y + text_height + padding
196
  ],
197
+ fill=(0, 0, 0, 160) # Semi-transparent black
198
  )
199
 
200
  # Draw text
 
205
  font=self.font
206
  )
207
 
208
+ # Add progress bar with animation
209
  self.draw_animated_progress_bar(
210
  draw,
211
  frame_number,
 
218
 
219
  except Exception as e:
220
  self.logger.error(f"Frame creation failed: {str(e)}")
221
+ # Return fallback frame
222
  return np.full((size[1], size[0], 3), theme['bg'], dtype=np.uint8)
223
 
224
  def draw_animated_progress_bar(
 
229
  size: Tuple[int, int],
230
  theme: dict
231
  ):
232
+ """Draw an animated progress bar with effects"""
233
  try:
234
  progress = frame_number / total_frames
235
+ bar_width = int(size[0] * 0.8) # 80% of screen width
236
  bar_height = 6
237
  x_offset = (size[0] - bar_width) // 2
238
  y_position = size[1] - 40
 
243
  fill=(200, 200, 200, 160)
244
  )
245
 
246
+ # Draw progress with gradient effect
247
  progress_width = int(bar_width * progress)
248
+ for x in range(progress_width):
249
+ alpha = int(255 * (x / bar_width)) # Gradient effect
250
+ draw.line(
251
+ [x_offset + x, y_position, x_offset + x, y_position + bar_height],
252
+ fill=(theme['accent'][0], theme['accent'][1], theme['accent'][2], alpha)
253
+ )
254
+
255
+ # Add animated highlight
256
+ highlight_pos = x_offset + progress_width
257
+ if highlight_pos < x_offset + bar_width:
258
+ draw.rectangle(
259
+ [highlight_pos-2, y_position-1, highlight_pos+2, y_position + bar_height+1],
260
+ fill=(255, 255, 255, 200)
261
+ )
262
 
263
  except Exception as e:
264
  self.logger.error(f"Progress bar drawing failed: {str(e)}")
265
 
266
  def generate_voice_over(self, script: str) -> AudioFileClip:
267
+ """Generate voice-over audio using gTTS"""
268
  try:
269
  audio_path = self.temp_dir / "voice.mp3"
270
  tts = gTTS(
 
286
  duration: int,
287
  output_path: str
288
  ) -> str:
289
+ """Create full video with all enhanced features"""
290
  try:
291
  # Generate visual assets
292
  assets = self.generate_visual_assets(script, style)
 
294
  # Generate voice-over
295
  audio = self.generate_voice_over(script)
296
 
297
+ # Create frames with visual assets
298
  frames = []
299
  fps = 30
300
  total_frames = int(duration * fps)
 
303
  frame_futures = []
304
 
305
  for i in range(total_frames):
306
+ # Calculate current text segment
307
  progress = i / total_frames
308
  text_index = int(progress * len(script.split()))
309
  current_text = " ".join(script.split()[:text_index + 1])
310
 
311
+ # Get appropriate background
312
  asset_index = int(progress * len(assets))
313
  current_asset = assets[asset_index] if assets else None
314
 
315
+ # Submit frame creation to thread pool
316
  future = executor.submit(
317
  self.create_enhanced_frame,
318
  current_text,
 
323
  )
324
  frame_futures.append(future)
325
 
326
+ # Collect frames
327
  frames = [future.result() for future in frame_futures]
328
 
329
  # Create video clip
 
332
  # Add voice-over
333
  video = video.set_audio(audio)
334
 
335
+ # Add background music (if available)
336
+ try:
337
+ music = AudioFileClip("assets/music/background.mp3")
338
+ music = music.volumex(0.1).loop(duration=video.duration)
339
+ video = video.set_audio(CompositeAudioClip([video.audio, music]))
340
+ except Exception as e:
341
+ self.logger.warning(f"Background music addition failed: {str(e)}")
342
+
343
  # Write final video
344
  video.write_videofile(
345
  output_path,
 
362
  if not isinstance(text, str):
363
  text = str(text)
364
 
365
+ # Normalize unicode characters
366
  text = unicodedata.normalize('NFKD', text)
367
+
368
+ # Remove non-ASCII characters
369
  text = text.encode('ascii', 'ignore').decode('ascii')
370
 
371
+ # Replace problematic characters
372
  replacements = {
373
+ '–': '-', # en dash
374
+ '—': '-', # em dash
375
+ '"': '"', # smart quotes
376
+ '"': '"', # smart quotes
377
+ ''': "'", # smart apostrophe
378
+ ''': "'", # smart apostrophe
379
+ '…': '...', # ellipsis
380
  }
381
  for old, new in replacements.items():
382
  text = text.replace(old, new)
383
 
384
+ # Remove any remaining non-standard characters
385
  text = re.sub(r'[^\x00-\x7F]+', '', text)
386
 
387
  return text.strip()
388
 
389
+ def extract_key_topics(self, script: str) -> List[str]:
390
+ """Extract main topics from the script for visual asset generation"""
391
+ try:
392
+ # Simple keyword extraction based on noun phrases
393
+ # In a production environment, you might want to use a proper NLP library
394
+ sentences = script.split('.')
395
+ topics = []
396
+
397
+ for sentence in sentences:
398
+ words = sentence.strip().split()
399
+ if len(words) >= 2:
400
+ # Extract potential noun phrases (pairs of words)
401
+ topics.append(' '.join(words[:2]))
402
+
403
+ # Remove duplicates and limit to top 5 topics
404
+ return list(dict.fromkeys(topics))[:5]
405
+
406
+ except Exception as e:
407
+ self.logger.error(f"Topic extraction failed: {str(e)}")
408
+ return ["default topic"]
409
+
410
+ def generate_ai_image(self, prompt: str, style: str) -> Optional[Image.Image]:
411
+ """Generate an AI image using Stability AI"""
412
+ try:
413
+ if not self.stability_api:
414
+ return None
415
+
416
+ # Enhance prompt based on style
417
+ style_prompts = {
418
+ 'Professional': "professional, corporate, clean, modern",
419
+ 'Creative': "artistic, vibrant, innovative, dynamic",
420
+ 'Educational': "clear, informative, academic, detailed"
421
+ }
422
+
423
+ enhanced_prompt = f"{prompt}, {style_prompts.get(style, '')}, high quality, 4k"
424
+
425
+ # Generate image
426
+ response = self.stability_api.generate(
427
+ prompt=enhanced_prompt,
428
+ samples=1,
429
+ width=1920,
430
+ height=1080
431
+ )
432
+
433
+ if response and len(response) > 0:
434
+ image_data = response[0].image
435
+ return Image.open(io.BytesIO(image_data))
436
+
437
+ return None
438
+
439
+ except Exception as e:
440
+ self.logger.error(f"AI image generation failed: {str(e)}")
441
+ return None
442
+
443
  def cleanup(self):
444
  """Clean up temporary files and resources"""
445
  try:
 
464
  def __exit__(self, exc_type, exc_val, exc_tb):
465
  self.cleanup()
466
 
467
+ # Streamlit UI Class
468
  class VideoGeneratorUI:
469
  def __init__(self):
470
  self.generator = EnhancedVideoGenerator()
 
475
  st.write("Create professional videos with AI-generated content")
476
 
477
  with st.form("video_generator_form"):
478
+ # Input fields
479
  prompt = st.text_area(
480
+ "Enter your video topic/prompt",
481
  height=100,
482
+ help="Describe what you want your video to be about"
483
  )
484
 
485
  col1, col2 = st.columns(2)
 
498
  step=10
499
  )
500
 
501
+ advanced_options = st.expander("Advanced Options")
502
+ with advanced_options:
503
+ use_premium_voice = st.checkbox(
504
+ "Use premium voice-over",
505
+ value=False,
506
+ help="Requires ElevenLabs API key"
507
+ )
508
+
509
+ include_music = st.checkbox(
510
+ "Include background music",
511
+ value=True
512
+ )
513
+
514
+ fps = st.slider(
515
+ "Frames per second",
516
+ min_value=24,
517
+ max_value=60,
518
+ value=30
519
+ )
520
+
521
  submit_button = st.form_submit_button("Generate Video")
522
 
523
  if submit_button:
524
  if not prompt:
525
+ st.error("Please enter a prompt for your video.")
526
  return
527
 
528
  try:
529
  with st.spinner("Generating your video..."):
530
  output_path = f"generated_video_{int(time.time())}.mp4"
531
 
532
+ # Update generator settings based on advanced options
533
+ self.generator.use_premium_voice = use_premium_voice
534
+
535
+ # Generate video
536
  video_path = self.generator.create_video(
537
  prompt,
538
  style,
 
540
  output_path
541
  )
542
 
543
+ # Show success message and download button
544
  st.success("Video generated successfully!")
545
 
546
  with open(video_path, 'rb') as f:
 
553
 
554
  except Exception as e:
555
  st.error(f"Failed to generate video: {str(e)}")
556
+ st.error("Please try again with different settings or contact support.")
557
 
558
  if __name__ == "__main__":
559
  ui = VideoGeneratorUI()