shaheerawan3 commited on
Commit
ee4b9c0
·
verified ·
1 Parent(s): e575ced

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +170 -175
app.py CHANGED
@@ -62,55 +62,47 @@ class FastVideoGenerator:
62
  @staticmethod
63
  def clean_text(text):
64
  """Clean text to handle encoding issues"""
65
- if not isinstance(text, str):
66
- text = str(text)
67
-
68
- # Remove non-ASCII characters
69
  text = text.encode('ascii', 'ignore').decode('ascii')
70
-
71
- # Replace common problematic characters
72
- text = text.replace('–', '-') # en dash
73
- text = text.replace('—', '-') # em dash
74
- text = text.replace('"', '"') # smart quotes
75
- text = text.replace('"', '"') # smart quotes
76
- text = text.replace(''', "'") # smart apostrophe
77
- text = text.replace(''', "'") # smart apostrophe
78
- text = text.replace('…', '...') # ellipsis
79
-
80
- # Remove any remaining non-standard characters
81
- text = re.sub(r'[^\x00-\x7F]+', '', text)
82
-
83
- return text.strip()
84
 
85
  @staticmethod
86
  @st.cache_data
87
  def generate_script_cached(prompt, style, length, temperature=0.7):
88
  """Cached script generation with proper text cleaning"""
89
- try:
90
- style_prompts = {
91
- 'Professional': "Write a clear, professional video script about:",
92
- 'Creative': "Write an engaging, creative video script about:",
93
- 'Educational': "Write an informative educational video script about:"
94
- }
95
-
96
- # Clean prompt before processing
97
- prompt = FastVideoGenerator.clean_text(prompt)
98
-
99
- generator = pipeline('text-generation', model='distilgpt2')
100
  output = generator(
101
  f"{style_prompts[style]} {prompt}. Make it {length} seconds long.",
102
  max_length=min(length * 3, 1000),
103
  num_return_sequences=1,
104
  temperature=temperature
105
  )
106
-
107
- script = output[0]['generated_text']
108
- script = script.replace(style_prompts[style], '').strip()
109
- return FastVideoGenerator.clean_text(script)
110
-
111
- except Exception as e:
112
- st.error(f"Script generation failed: {str(e)}")
113
- raise
114
 
115
  def create_frame_fast(self, text, theme, frame_number, total_frames, size=(1280, 720)):
116
  """Create frame with cleaned text"""
@@ -153,170 +145,173 @@ class FastVideoGenerator:
153
  for i, chunk in enumerate(chunks):
154
  chunk_path = self.temp_dir / f"audio_chunk_{i}.mp3"
155
  try:
156
- # Additional cleaning for gTTS
157
- chunk = re.sub(r'[^\x00-\x7F]+', '', chunk)
158
  tts = gTTS(text=chunk, lang='en', slow=False)
159
  tts.save(str(chunk_path))
160
  audio_paths.append(chunk_path)
161
  except Exception as e:
162
- st.error(f"Audio generation failed for chunk {i}: {str(e)}")
163
- raise
164
-
 
 
 
165
  return audio_paths
166
 
167
- class VideoGenerator:
168
- def __init__(self):
169
- self.device = "cuda" if torch.cuda.is_available() else "cpu"
170
- self.temp_dir = Path(tempfile.mkdtemp())
171
-
172
- # Load text generator
173
- self.text_generator = pipeline(
174
- 'text-generation',
175
- model='distilgpt2',
176
- device=0 if self.device == "cuda" else -1
177
- )
178
-
179
- # Define themes
180
- self.themes = {
181
- 'Professional': {'bg': (245, 245, 245), 'text': (33, 33, 33)},
182
- 'Creative': {'bg': (255, 240, 245), 'text': (51, 51, 51)},
183
- 'Educational': {'bg': (240, 249, 255), 'text': (25, 25, 25)}
184
- }
185
-
186
- # Load font
187
- try:
188
- self.font = ImageFont.truetype("arial.ttf", 40)
189
- except:
190
- self.font = ImageFont.load_default()
191
-
192
- def generate_script(self, prompt, style, length):
193
- """Generate video script based on prompt"""
194
- style_prompts = {
195
- 'Professional': "Write a professional video script about:",
196
- 'Creative': "Write a creative video script about:",
197
- 'Educational': "Write an educational video script about:"
198
- }
199
-
200
- output = self.text_generator(
201
- f"{style_prompts[style]} {prompt}. Length: {length} seconds.",
202
- max_length=min(length * 3, 1000),
203
- num_return_sequences=1,
204
- temperature=0.7
205
- )
206
-
207
- return output[0]['generated_text'].replace(style_prompts[style], '').strip()
208
-
209
- def create_frame(self, text, theme, frame_num, total_frames, size=(1280, 720)):
210
- """Create a single video frame"""
211
- # Create base frame
212
- frame = np.full((size[1], size[0], 3), theme['bg'], dtype=np.uint8)
213
- img = Image.fromarray(frame)
214
- draw = ImageDraw.Draw(img)
215
-
216
- # Add text
217
- wrapped_text = textwrap.fill(text, width=50)
218
- text_bbox = draw.textbbox((0, 0), wrapped_text, font=self.font)
219
- text_x = (size[0] - (text_bbox[2] - text_bbox[0])) // 2
220
- text_y = (size[1] - (text_bbox[3] - text_bbox[1])) // 2
221
- draw.text((text_x, text_y), wrapped_text, fill=theme['text'], font=self.font)
222
-
223
- # Add progress bar
224
- progress = frame_num / total_frames
225
- bar_width = int(1000 * progress)
226
- draw.rectangle([140, 650, 140+bar_width, 660], fill=(100, 100, 100))
227
-
228
- return np.array(img)
229
-
230
- def generate_video(self, script, theme, duration=30):
231
- """Generate complete video with audio"""
232
  fps = 24
233
  total_frames = duration * fps
234
 
235
- # Create video frames
236
  def make_frame(t):
237
- frame_num = int(t * fps)
238
- return self.create_frame(script, self.themes[theme], frame_num, total_frames)
 
 
 
 
 
239
 
240
- # Generate video
241
- video_path = self.temp_dir / "output.mp4"
242
  clip = VideoClip(make_frame, duration=duration)
243
 
244
- # Generate audio
245
- audio_path = self.temp_dir / "audio.mp3"
246
- tts = gTTS(text=script, lang='en')
247
- tts.save(str(audio_path))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
 
249
- # Combine video and audio
250
- audio = AudioFileClip(str(audio_path))
251
- final_clip = clip.set_audio(audio)
252
- final_clip.write_videofile(
253
- str(video_path),
254
- fps=fps,
255
- codec='libx264',
256
- audio_codec='aac'
257
  )
258
 
259
- # Cleanup
260
- audio.close()
261
- final_clip.close()
 
 
 
 
 
262
 
263
- return video_path
 
 
 
 
 
264
 
265
- def main():
266
- st.set_page_config(page_title="Video Generator", layout="wide")
267
-
268
- # Initialize generator
269
- if 'generator' not in st.session_state:
270
- st.session_state.generator = VideoGenerator()
271
-
272
- # UI Elements
273
- st.title("🎥 Quick Video Generator")
274
-
275
- with st.sidebar:
276
- theme = st.selectbox("Theme", ["Professional", "Creative", "Educational"])
277
- duration = st.slider("Duration (seconds)", 30, 120, 60, 30)
278
-
279
- # Main input
280
- prompt = st.text_area("What's your video about?", height=100)
281
-
282
- if st.button("Generate Video"):
283
- if prompt:
284
  try:
285
- # Show progress
286
- progress = st.progress(0)
287
  status = st.empty()
288
 
289
- # Generate script
290
- status.text("Creating script...")
291
- script = st.session_state.generator.generate_script(prompt, theme, duration)
292
- progress.progress(33)
 
 
293
 
294
- # Create video
295
- status.text("Generating video...")
296
- video_path = st.session_state.generator.generate_video(script, theme, duration)
297
- progress.progress(100)
298
- status.text("Done!")
 
 
299
 
300
- # Show results
301
- col1, col2 = st.columns(2)
302
- with col1:
 
303
  st.video(str(video_path))
304
- with col2:
305
- st.text_area("Generated Script", script, height=200)
 
 
 
 
 
 
 
 
 
306
 
307
- # Download button
308
- with open(str(video_path), 'rb') as f:
309
- st.download_button(
310
- "Download Video",
311
- f,
312
- file_name="generated_video.mp4",
313
- mime="video/mp4"
314
- )
315
-
316
  except Exception as e:
317
- st.error(f"Error: {str(e)}")
 
318
  else:
319
- st.warning("Please enter a topic first!")
320
 
321
  if __name__ == "__main__":
322
- main()
 
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"""
 
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",
301
+ f,
302
+ file_name="generated_video.mp4",
303
+ mime="video/mp4"
304
+ )
305
+
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()