shaheerawan3 commited on
Commit
8e46c45
·
verified ·
1 Parent(s): 8b3e939

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +180 -125
app.py CHANGED
@@ -9,103 +9,123 @@ from moviepy.editor import *
9
  import numpy as np
10
  from gtts import gTTS
11
  import textwrap
 
 
 
 
12
 
13
- # Move the script generation to a standalone cached function
14
- @st.cache_data
15
- def generate_script_cached(prompt, style, length, model_output):
16
- """Cached version of script generation"""
17
- style_prompts = {
18
- 'Professional': "Write a clear, professional script about:",
19
- 'Creative': "Write an engaging, creative script about:",
20
- 'Educational': "Write an informative educational script about:"
21
- }
22
-
23
- # Clean up the generated text
24
- script = model_output[0]['generated_text']
25
- script = script.replace(style_prompts[style], '').strip()
26
- return script
27
-
28
- class EnhancedVideoGenerator:
29
  def __init__(self):
30
- # Use device agnostic setup
31
  self.device = "cuda" if torch.cuda.is_available() else "cpu"
32
 
33
- # Initialize text generation with a faster model
34
  self.text_generator = pipeline(
35
  'text-generation',
36
- model='distilgpt2', # Smaller, faster model
37
  device=0 if self.device == "cuda" else -1
38
  )
39
 
40
  # Create temp directory
41
  self.temp_dir = Path(tempfile.mkdtemp())
42
 
43
- # Store theme colors
44
  self.themes = {
45
  'Professional': {
46
  'bg': (245, 245, 245),
47
  'text': (33, 33, 33),
48
- 'accent': (0, 102, 204)
 
49
  },
50
  'Creative': {
51
  'bg': (255, 240, 245),
52
  'text': (51, 51, 51),
53
- 'accent': (255, 64, 129)
 
54
  },
55
  'Educational': {
56
  'bg': (240, 249, 255),
57
  'text': (25, 25, 25),
58
- 'accent': (0, 151, 167)
 
59
  }
60
  }
61
 
62
- def generate_script(self, prompt, style, length):
63
- """Generate engaging script based on style and length"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  style_prompts = {
65
- 'Professional': "Write a clear, professional script about:",
66
- 'Creative': "Write an engaging, creative script about:",
67
- 'Educational': "Write an informative educational script about:"
68
  }
69
 
70
- max_length = int(length * 2.5) # Approximate words needed for duration
71
 
72
- # Generate the text
73
- output = self.text_generator(
74
- f"{style_prompts[style]} {prompt}. Keep it concise and engaging.",
75
- max_length=max_length,
76
- num_return_sequences=1,
77
- temperature=0.7
78
- )
79
 
80
- # Use the cached function to process the output
81
- return generate_script_cached(prompt, style, length, output)
 
82
 
83
- def create_styled_frame(self, text, theme, frame_number, total_frames):
84
- """Create a visually appealing frame with text and progress bar"""
85
- # Create base image
86
- img = Image.new('RGB', (1280, 720), color=theme['bg'])
 
 
 
 
87
  draw = ImageDraw.Draw(img)
88
 
89
  # Wrap text for better presentation
90
  wrapped_text = textwrap.fill(text, width=50)
91
 
92
- # Add text
93
- font_size = 40
94
- try:
95
- font = ImageFont.truetype("arial.ttf", font_size)
96
- except:
97
- font = ImageFont.load_default()
98
-
99
- # Calculate text position for center alignment
100
- text_bbox = draw.textbbox((0, 0), wrapped_text, font=font)
101
- text_width = text_bbox[2] - text_bbox[0]
102
- text_height = text_bbox[3] - text_bbox[1]
103
- text_x = (1280 - text_width) // 2
104
- text_y = (720 - text_height) // 2
105
 
106
- # Draw text with subtle shadow for depth
107
- draw.text((text_x+2, text_y+2), wrapped_text, fill=(0,0,0,128), font=font)
108
- draw.text((text_x, text_y), wrapped_text, fill=theme['text'], font=font)
 
109
 
110
  # Add progress bar
111
  progress = frame_number / total_frames
@@ -115,132 +135,166 @@ class EnhancedVideoGenerator:
115
 
116
  return np.array(img)
117
 
118
- def generate_voiceover(self, script, lang='en'):
119
- """Generate voice narration using gTTS"""
120
- audio_path = self.temp_dir / "voiceover.mp3"
121
- tts = gTTS(text=script, lang=lang, slow=False)
122
- tts.save(str(audio_path))
123
- return audio_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
- def create_video(self, script, theme, duration=30):
126
- """Create video with animated text and voiceover"""
127
- # Generate frames
128
  fps = 24
129
  total_frames = duration * fps
130
 
 
131
  def make_frame(t):
132
  frame_number = int(t * fps)
133
- return self.create_styled_frame(
134
- script,
135
- self.themes[theme],
136
  frame_number,
137
  total_frames
138
  )
139
 
140
- # Create video clip
141
  clip = VideoClip(make_frame, duration=duration)
142
 
143
- # Generate and add voiceover
144
- audio_path = self.generate_voiceover(script)
145
- audio = AudioFileClip(str(audio_path))
146
-
147
- # Combine video and audio
148
- final_clip = clip.set_audio(audio)
149
-
150
- # Save video
151
- output_path = self.temp_dir / "output_video.mp4"
152
- final_clip.write_videofile(str(output_path), fps=fps, codec='libx264')
153
- return output_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
  def main():
156
  st.set_page_config(
157
- page_title=" Smart Video Generator",
158
  layout="wide",
159
  initial_sidebar_state="expanded"
160
  )
161
 
162
- # Custom CSS for better UI
163
  st.markdown("""
164
  <style>
165
  .stButton>button {
166
  width: 100%;
167
  height: 3em;
168
- margin-top: 2em;
 
169
  }
170
- .stProgress .st-bo {
171
- height: 20px;
172
  }
173
  </style>
174
  """, unsafe_allow_html=True)
175
 
176
- # Initialize session state
177
  if 'video_generator' not in st.session_state:
178
- with st.spinner("🚀 Initializing... (just a moment)"):
179
- st.session_state.video_generator = EnhancedVideoGenerator()
180
 
181
- # Sidebar for settings
182
  with st.sidebar:
183
  st.title("🎮 Video Settings")
 
184
  theme = st.selectbox(
185
- "Choose Theme",
186
  ["Professional", "Creative", "Educational"],
187
- help="Select the style for your video"
188
  )
189
 
190
  duration = st.slider(
191
- "Video Duration (seconds)",
192
- min_value=15,
193
- max_value=90,
194
- value=30,
195
- step=15,
196
- help="Choose the length of your video"
 
 
 
 
 
 
 
197
  )
198
 
199
- # Main content
200
- st.title(" Smart Video Generator")
201
- st.markdown("""
202
- Transform your ideas into engaging videos with AI-powered content generation.
203
- Just enter your topic below! 🎥
204
- """)
205
 
206
- # Input section with example
207
  text_input = st.text_area(
208
- "What's your video about?",
209
  height=100,
210
- placeholder="Example: Explain how rainbows form in the sky..."
211
  )
212
 
213
- # Generate button with loading animation
214
  if st.button("🎬 Generate Video", use_container_width=True):
215
  if text_input:
216
  try:
217
  progress_bar = st.progress(0)
218
- status_text = st.empty()
219
 
220
- # Generate script
221
- status_text.text("✍️ Creating engaging script...")
222
- script = st.session_state.video_generator.generate_script(
223
  text_input, theme, duration
224
  )
225
  progress_bar.progress(30)
226
 
227
- # Create video
228
- status_text.text("🎨 Crafting visual elements...")
229
- progress_bar.progress(60)
230
-
231
- video_path = st.session_state.video_generator.create_video(
232
  script, theme, duration
233
  )
234
  progress_bar.progress(100)
235
- status_text.text("✨ Done! Your video is ready!")
236
 
237
- # Display results in tabs
238
  tab1, tab2 = st.tabs(["📽️ Video", "📝 Script"])
239
 
240
  with tab1:
241
  st.video(str(video_path))
242
-
243
- # Download button
244
  with open(str(video_path), 'rb') as f:
245
  st.download_button(
246
  "⬇️ Download Video",
@@ -252,11 +306,12 @@ def main():
252
  with tab2:
253
  st.markdown("### Generated Script")
254
  st.write(script)
255
-
256
  except Exception as e:
257
- st.error(f"💥 Oops! Something went wrong: {str(e)}")
 
258
  else:
259
- st.warning("🎯 Please enter a topic to generate a video!")
260
 
261
  if __name__ == "__main__":
262
  main()
 
9
  import numpy as np
10
  from gtts import gTTS
11
  import textwrap
12
+ from concurrent.futures import ThreadPoolExecutor
13
+ import io
14
+ import unicodedata
15
+ import re
16
 
17
+ class FastVideoGenerator:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  def __init__(self):
 
19
  self.device = "cuda" if torch.cuda.is_available() else "cpu"
20
 
21
+ # Initialize text generation with efficient model
22
  self.text_generator = pipeline(
23
  'text-generation',
24
+ model='distilgpt2',
25
  device=0 if self.device == "cuda" else -1
26
  )
27
 
28
  # Create temp directory
29
  self.temp_dir = Path(tempfile.mkdtemp())
30
 
31
+ # Theme colors with opacity for better text visibility
32
  self.themes = {
33
  'Professional': {
34
  'bg': (245, 245, 245),
35
  'text': (33, 33, 33),
36
+ 'accent': (0, 102, 204),
37
+ 'overlay': (255, 255, 255, 180)
38
  },
39
  'Creative': {
40
  'bg': (255, 240, 245),
41
  'text': (51, 51, 51),
42
+ 'accent': (255, 64, 129),
43
+ 'overlay': (255, 255, 255, 180)
44
  },
45
  'Educational': {
46
  'bg': (240, 249, 255),
47
  'text': (25, 25, 25),
48
+ 'accent': (0, 151, 167),
49
+ 'overlay': (255, 255, 255, 180)
50
  }
51
  }
52
 
53
+ # Pre-load font
54
+ try:
55
+ self.font = ImageFont.truetype("arial.ttf", 40)
56
+ except:
57
+ self.font = ImageFont.load_default()
58
+
59
+ # Add text cleaner
60
+ self.text_cleaner = re.compile(r'[^\x00-\x7F]+')
61
+
62
+ @staticmethod
63
+ def clean_text(text):
64
+ """Clean text to handle encoding issues"""
65
+ # Normalize unicode characters
66
+ text = unicodedata.normalize('NFKD', text)
67
+ # Replace special characters with standard ASCII
68
+ text = text.encode('ascii', 'ignore').decode('ascii')
69
+ # Replace common special characters
70
+ replacements = {
71
+ '–': '-', # en dash
72
+ '—': '-', # em dash
73
+ ''': "'", # curly quote
74
+ ''': "'", # curly quote
75
+ '"': '"', # curly quote
76
+ '"': '"', # curly quote
77
+ '…': '...' # ellipsis
78
+ }
79
+ for old, new in replacements.items():
80
+ text = text.replace(old, new)
81
+ return text
82
+
83
+ @staticmethod
84
+ @st.cache_data
85
+ def generate_script_cached(prompt, style, length, temperature=0.7):
86
+ """Cached script generation with proper text cleaning"""
87
  style_prompts = {
88
+ 'Professional': "Write a clear, professional video script about:",
89
+ 'Creative': "Write an engaging, creative video script about:",
90
+ 'Educational': "Write an informative educational video script about:"
91
  }
92
 
93
+ prompt = FastVideoGenerator.clean_text(prompt)
94
 
95
+ with pipeline('text-generation', model='distilgpt2') as generator:
96
+ output = generator(
97
+ f"{style_prompts[style]} {prompt}. Make it {length} seconds long.",
98
+ max_length=min(length * 3, 1000),
99
+ num_return_sequences=1,
100
+ temperature=temperature
101
+ )
102
 
103
+ script = output[0]['generated_text']
104
+ script = script.replace(style_prompts[style], '').strip()
105
+ return FastVideoGenerator.clean_text(script)
106
 
107
+ def create_frame_fast(self, text, theme, frame_number, total_frames, size=(1280, 720)):
108
+ """Create frame with cleaned text"""
109
+ # Clean text before rendering
110
+ text = self.clean_text(text)
111
+
112
+ # Create frame
113
+ frame = np.full((size[1], size[0], 3), theme['bg'], dtype=np.uint8)
114
+ img = Image.fromarray(frame)
115
  draw = ImageDraw.Draw(img)
116
 
117
  # Wrap text for better presentation
118
  wrapped_text = textwrap.fill(text, width=50)
119
 
120
+ # Calculate text position
121
+ text_bbox = draw.textbbox((0, 0), wrapped_text, font=self.font)
122
+ text_x = (size[0] - (text_bbox[2] - text_bbox[0])) // 2
123
+ text_y = (size[1] - (text_bbox[3] - text_bbox[1])) // 2
 
 
 
 
 
 
 
 
 
124
 
125
+ # Draw text with background for better readability
126
+ text_bg = Image.new('RGBA', size, (0, 0, 0, 0))
127
+ text_draw = ImageDraw.Draw(text_bg)
128
+ text_draw.text((text_x, text_y), wrapped_text, fill=theme['text'], font=self.font)
129
 
130
  # Add progress bar
131
  progress = frame_number / total_frames
 
135
 
136
  return np.array(img)
137
 
138
+ def generate_audio_chunks(self, script, chunk_size=1000):
139
+ """Generate audio with cleaned text"""
140
+ # Clean text before TTS
141
+ script = self.clean_text(script)
142
+ chunks = textwrap.wrap(script, chunk_size)
143
+ audio_paths = []
144
+
145
+ for i, chunk in enumerate(chunks):
146
+ chunk_path = self.temp_dir / f"audio_chunk_{i}.mp3"
147
+ try:
148
+ tts = gTTS(text=chunk, lang='en', slow=False)
149
+ tts.save(str(chunk_path))
150
+ audio_paths.append(chunk_path)
151
+ except Exception as e:
152
+ # If TTS fails, try with further cleaning
153
+ cleaned_chunk = re.sub(r'[^a-zA-Z0-9\s.,!?-]', '', chunk)
154
+ tts = gTTS(text=cleaned_chunk, lang='en', slow=False)
155
+ tts.save(str(chunk_path))
156
+ audio_paths.append(chunk_path)
157
+
158
+ return audio_paths
159
 
160
+ def create_optimized_video(self, script, theme, duration=30):
161
+ """Create video with optimized processing"""
 
162
  fps = 24
163
  total_frames = duration * fps
164
 
165
+ # Create frames efficiently
166
  def make_frame(t):
167
  frame_number = int(t * fps)
168
+ return self.create_frame_fast(
169
+ script,
170
+ self.themes[theme],
171
  frame_number,
172
  total_frames
173
  )
174
 
175
+ # Generate video with reduced memory usage
176
  clip = VideoClip(make_frame, duration=duration)
177
 
178
+ # Generate audio in background while processing video
179
+ with ThreadPoolExecutor() as executor:
180
+ future_audio = executor.submit(self.generate_audio_chunks, script)
181
+
182
+ # Process video
183
+ output_path = self.temp_dir / "output_video.mp4"
184
+ temp_video = self.temp_dir / "temp_video.mp4"
185
+
186
+ # Write video without audio first
187
+ clip.write_videofile(
188
+ str(temp_video),
189
+ fps=fps,
190
+ codec='libx264',
191
+ audio=False,
192
+ preset='ultrafast'
193
+ )
194
+
195
+ # Get audio paths and combine audio
196
+ audio_paths = future_audio.result()
197
+ audio_clips = [AudioFileClip(str(path)) for path in audio_paths]
198
+ final_audio = concatenate_audioclips(audio_clips)
199
+
200
+ # Combine video and audio
201
+ video = VideoFileClip(str(temp_video))
202
+ final_clip = video.set_audio(final_audio)
203
+ final_clip.write_videofile(str(output_path), fps=fps, codec='libx264')
204
+
205
+ # Cleanup
206
+ video.close()
207
+ final_clip.close()
208
+ for clip in audio_clips:
209
+ clip.close()
210
+
211
+ return output_path
212
 
213
  def main():
214
  st.set_page_config(
215
+ page_title=" Fast Video Generator",
216
  layout="wide",
217
  initial_sidebar_state="expanded"
218
  )
219
 
220
+ # Custom CSS
221
  st.markdown("""
222
  <style>
223
  .stButton>button {
224
  width: 100%;
225
  height: 3em;
226
+ background-color: #FF4B4B;
227
+ color: white;
228
  }
229
+ .stProgress > div > div > div > div {
230
+ background-color: #FF4B4B;
231
  }
232
  </style>
233
  """, unsafe_allow_html=True)
234
 
 
235
  if 'video_generator' not in st.session_state:
236
+ st.session_state.video_generator = FastVideoGenerator()
 
237
 
 
238
  with st.sidebar:
239
  st.title("🎮 Video Settings")
240
+
241
  theme = st.selectbox(
242
+ "Theme Style",
243
  ["Professional", "Creative", "Educational"],
244
+ help="Choose the visual style of your video"
245
  )
246
 
247
  duration = st.slider(
248
+ "Duration (seconds)",
249
+ min_value=30,
250
+ max_value=300,
251
+ value=60,
252
+ step=30,
253
+ help="Videos up to 5 minutes supported"
254
+ )
255
+
256
+ quality = st.select_slider(
257
+ "Generation Speed",
258
+ options=["High Quality", "Balanced", "Fast"],
259
+ value="Balanced",
260
+ help="Faster generation may reduce video quality"
261
  )
262
 
263
+ st.title("⚡ Fast Video Generator")
264
+ st.markdown("Create longer videos with optimized performance!")
 
 
 
 
265
 
 
266
  text_input = st.text_area(
267
+ "Video Topic",
268
  height=100,
269
+ placeholder="Enter your topic here..."
270
  )
271
 
 
272
  if st.button("🎬 Generate Video", use_container_width=True):
273
  if text_input:
274
  try:
275
  progress_bar = st.progress(0)
276
+ status = st.empty()
277
 
278
+ # Script generation
279
+ status.text("✍️ Creating script...")
280
+ script = FastVideoGenerator.generate_script_cached(
281
  text_input, theme, duration
282
  )
283
  progress_bar.progress(30)
284
 
285
+ # Video creation
286
+ status.text("🎨 Generating video...")
287
+ video_path = st.session_state.video_generator.create_optimized_video(
 
 
288
  script, theme, duration
289
  )
290
  progress_bar.progress(100)
291
+ status.text("✨ Video ready!")
292
 
293
+ # Display results
294
  tab1, tab2 = st.tabs(["📽️ Video", "📝 Script"])
295
 
296
  with tab1:
297
  st.video(str(video_path))
 
 
298
  with open(str(video_path), 'rb') as f:
299
  st.download_button(
300
  "⬇️ Download Video",
 
306
  with tab2:
307
  st.markdown("### Generated Script")
308
  st.write(script)
309
+
310
  except Exception as e:
311
+ st.error(f"💥 Error: {str(e)}")
312
+ st.error("Please try again with different settings")
313
  else:
314
+ st.warning("⚠️ Please enter a topic first!")
315
 
316
  if __name__ == "__main__":
317
  main()