Nishur commited on
Commit
7ddad4d
·
verified ·
1 Parent(s): 100847c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +214 -53
app.py CHANGED
@@ -161,25 +161,70 @@ def generate_translated_audio(srt_path, target_lang):
161
  audio_file = os.path.join(temp_dir, f"chunk_{i:04d}.mp3")
162
 
163
  try:
164
- tts = gTTS(text=text, lang=target_lang, slow=False)
165
- tts.save(audio_file)
166
- audio_files.append(audio_file)
167
- timings.append((start_time, end_time, duration, audio_file))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  except Exception as e:
169
  logger.warning(f"Failed to generate TTS for: {text}. Error: {str(e)}")
170
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  # Create a silent audio track the same length as the original video
172
  silence_file = os.path.join(temp_dir, "silence.wav")
173
- video_duration_cmd = [
174
- 'ffprobe',
175
- '-v', 'error',
176
- '-show_entries', 'format=duration',
177
- '-of', 'default=noprint_wrappers=1:nokey=1',
178
- os.path.join(OUTPUT_DIR, "base_video.mp4")
179
- ]
180
-
181
- duration_result = subprocess.run(video_duration_cmd, capture_output=True, text=True)
182
- video_duration = float(duration_result.stdout.strip())
 
 
 
 
183
 
184
  # Create silent audio track
185
  silent_cmd = [
@@ -229,68 +274,179 @@ def generate_translated_audio(srt_path, target_lang):
229
 
230
  # Run the command
231
  logger.info(f"Combining audio segments: {' '.join(cmd)}")
232
- subprocess.run(cmd, capture_output=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
 
234
  # Clean up temporary files
235
- shutil.rmtree(temp_dir)
 
 
 
236
 
237
  return output_audio
238
  except Exception as e:
239
  logger.error(f"Audio translation failed: {str(e)}", exc_info=True)
240
- raise Exception(f"Audio translation failed: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
 
242
  def combine_video_audio_subtitles(video_path, audio_path, srt_path, output_path):
243
  """Combine video with translated audio and subtitles"""
244
  try:
245
  logger.info(f"Combining video, audio, and subtitles")
246
 
247
- # Escape special characters in paths for ffmpeg filters
248
- escaped_srt_path = srt_path.replace(":", "\\:").replace("'", "\\'").replace(" ", "\\ ")
249
-
250
- # Command to combine video with translated audio and subtitles
251
- cmd = [
252
- 'ffmpeg',
253
- '-i', video_path, # Input video
254
- '-i', audio_path, # Input translated audio
255
- '-map', '0:v', # Use video from first input
256
- '-map', '1:a', # Use audio from second input
257
- '-vf', f"subtitles={escaped_srt_path}:force_style='FontSize=24,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,BorderStyle=3'", # Burn subtitles
258
- '-c:v', 'libx264', # Video codec
259
- '-c:a', 'aac', # Audio codec
260
- '-shortest', # End when shortest input ends
261
- '-y', # Overwrite output file
262
- output_path
263
- ]
264
 
265
- logger.info(f"Running command: {' '.join(cmd)}")
266
- process = subprocess.run(cmd, capture_output=True, text=True)
267
 
268
- if process.returncode != 0:
269
- logger.error(f"Combining failed: {process.stderr}")
270
-
271
- # Try alternative method
272
- logger.info("Trying alternative method")
273
  cmd = [
274
  'ffmpeg',
275
- '-i', video_path,
276
- '-i', audio_path,
277
- '-map', '0:v',
278
- '-map', '1:a',
279
- '-vf', f"subtitles='{srt_path}'",
280
- '-c:v', 'libx264',
281
- '-c:a', 'aac',
282
- '-shortest',
283
- '-y',
284
  output_path
285
  ]
286
 
287
- logger.info(f"Running alternative command: {' '.join(cmd)}")
288
  process = subprocess.run(cmd, capture_output=True, text=True)
289
 
290
  if process.returncode != 0:
291
- logger.error(f"Alternative method failed: {process.stderr}")
292
- raise Exception(f"Failed to combine video, audio, and subtitles: {process.stderr}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
 
 
 
 
 
 
 
 
 
294
  return output_path
295
  except Exception as e:
296
  logger.error(f"Combining failed: {str(e)}", exc_info=True)
@@ -340,6 +496,11 @@ def process_video(video_file, source_lang, target_langs, progress=gr.Progress())
340
  logger.info(f"Generating translated audio for {lang_code}")
341
  translated_audio = generate_translated_audio(sub_path, lang_code)
342
 
 
 
 
 
 
343
  # Combine video, translated audio, and subtitles
344
  output_path = os.path.join(OUTPUT_DIR, f"output_{lang_code}.mp4")
345
  logger.info(f"Creating final video with {lang_code} audio and subtitles")
 
161
  audio_file = os.path.join(temp_dir, f"chunk_{i:04d}.mp3")
162
 
163
  try:
164
+ # Add a retry mechanism for Hindi and other potentially problematic languages
165
+ retry_count = 0
166
+ max_retries = 3
167
+ while retry_count < max_retries:
168
+ try:
169
+ # For Hindi, use slower speed which might improve reliability
170
+ slow_option = target_lang == "hi"
171
+ tts = gTTS(text=text, lang=target_lang, slow=slow_option)
172
+ tts.save(audio_file)
173
+ break
174
+ except Exception as e:
175
+ retry_count += 1
176
+ logger.warning(f"TTS attempt {retry_count} failed for {target_lang}: {str(e)}")
177
+ time.sleep(1) # Wait before retrying
178
+
179
+ # If still failing after retries, try with shorter text
180
+ if retry_count == max_retries and len(text) > 100:
181
+ logger.warning(f"Trying with shortened text for {target_lang}")
182
+ shortened_text = text[:100] + "..."
183
+ tts = gTTS(text=shortened_text, lang=target_lang, slow=True)
184
+ tts.save(audio_file)
185
+
186
+ if os.path.exists(audio_file) and os.path.getsize(audio_file) > 0:
187
+ audio_files.append(audio_file)
188
+ timings.append((start_time, end_time, duration, audio_file))
189
+ else:
190
+ logger.warning(f"Generated audio file is empty or does not exist: {audio_file}")
191
+
192
  except Exception as e:
193
  logger.warning(f"Failed to generate TTS for: {text}. Error: {str(e)}")
194
 
195
+ # Check if we actually generated any audio files
196
+ if not audio_files:
197
+ logger.warning(f"No audio files were generated for {target_lang}")
198
+ # Create a silent audio file as fallback
199
+ silent_audio = os.path.join(OUTPUT_DIR, f"translated_audio_{target_lang}.wav")
200
+ silent_cmd = [
201
+ 'ffmpeg',
202
+ '-f', 'lavfi',
203
+ '-i', f'anullsrc=r=44100:cl=stereo',
204
+ '-t', '180', # 3 minutes default
205
+ '-q:a', '0',
206
+ '-y',
207
+ silent_audio
208
+ ]
209
+ subprocess.run(silent_cmd, capture_output=True)
210
+ return silent_audio
211
+
212
  # Create a silent audio track the same length as the original video
213
  silence_file = os.path.join(temp_dir, "silence.wav")
214
+ try:
215
+ video_duration_cmd = [
216
+ 'ffprobe',
217
+ '-v', 'error',
218
+ '-show_entries', 'format=duration',
219
+ '-of', 'default=noprint_wrappers=1:nokey=1',
220
+ os.path.join(OUTPUT_DIR, "base_video.mp4")
221
+ ]
222
+
223
+ duration_result = subprocess.run(video_duration_cmd, capture_output=True, text=True)
224
+ video_duration = float(duration_result.stdout.strip())
225
+ except Exception as e:
226
+ logger.warning(f"Could not determine video duration: {str(e)}. Using default of 180 seconds.")
227
+ video_duration = 180.0
228
 
229
  # Create silent audio track
230
  silent_cmd = [
 
274
 
275
  # Run the command
276
  logger.info(f"Combining audio segments: {' '.join(cmd)}")
277
+ process = subprocess.run(cmd, capture_output=True)
278
+
279
+ if process.returncode != 0:
280
+ logger.error(f"Audio combination failed: {process.stderr}")
281
+ # Create a fallback silent audio as last resort
282
+ silent_audio = os.path.join(OUTPUT_DIR, f"translated_audio_{target_lang}.wav")
283
+ silent_cmd = [
284
+ 'ffmpeg',
285
+ '-f', 'lavfi',
286
+ '-i', f'anullsrc=r=44100:cl=stereo',
287
+ '-t', str(video_duration),
288
+ '-q:a', '0',
289
+ '-y',
290
+ silent_audio
291
+ ]
292
+ subprocess.run(silent_cmd, capture_output=True)
293
+ output_audio = silent_audio
294
+
295
+ # Verify the output file exists
296
+ if not os.path.exists(output_audio):
297
+ logger.error(f"Output audio file does not exist: {output_audio}")
298
+ # Create emergency fallback
299
+ silent_audio = os.path.join(OUTPUT_DIR, f"translated_audio_{target_lang}.wav")
300
+ silent_cmd = [
301
+ 'ffmpeg',
302
+ '-f', 'lavfi',
303
+ '-i', f'anullsrc=r=44100:cl=stereo',
304
+ '-t', '180',
305
+ '-q:a', '0',
306
+ '-y',
307
+ silent_audio
308
+ ]
309
+ subprocess.run(silent_cmd, capture_output=True)
310
+ output_audio = silent_audio
311
 
312
  # Clean up temporary files
313
+ try:
314
+ shutil.rmtree(temp_dir)
315
+ except Exception as e:
316
+ logger.warning(f"Failed to clean up temp directory: {str(e)}")
317
 
318
  return output_audio
319
  except Exception as e:
320
  logger.error(f"Audio translation failed: {str(e)}", exc_info=True)
321
+ # Create an emergency fallback silent audio
322
+ try:
323
+ silent_audio = os.path.join(OUTPUT_DIR, f"translated_audio_{target_lang}.wav")
324
+ silent_cmd = [
325
+ 'ffmpeg',
326
+ '-f', 'lavfi',
327
+ '-i', f'anullsrc=r=44100:cl=stereo',
328
+ '-t', '180',
329
+ '-q:a', '0',
330
+ '-y',
331
+ silent_audio
332
+ ]
333
+ subprocess.run(silent_cmd, capture_output=True)
334
+ return silent_audio
335
+ except:
336
+ raise Exception(f"Audio translation failed: {str(e)}")
337
 
338
  def combine_video_audio_subtitles(video_path, audio_path, srt_path, output_path):
339
  """Combine video with translated audio and subtitles"""
340
  try:
341
  logger.info(f"Combining video, audio, and subtitles")
342
 
343
+ # Verify that all input files exist
344
+ if not os.path.exists(video_path):
345
+ raise Exception(f"Video file does not exist: {video_path}")
346
+ if not os.path.exists(audio_path):
347
+ raise Exception(f"Audio file does not exist: {audio_path}")
348
+ if not os.path.exists(srt_path):
349
+ raise Exception(f"Subtitle file does not exist: {srt_path}")
350
+
351
+ logger.info(f"Input files verified: Video: {os.path.getsize(video_path)} bytes, Audio: {os.path.getsize(audio_path)} bytes, Subtitles: {os.path.getsize(srt_path)} bytes")
 
 
 
 
 
 
 
 
352
 
353
+ # Create a safe version of the subtitle path
354
+ safe_srt_path = srt_path.replace(" ", "\\ ").replace(":", "\\:")
355
 
356
+ # Command to combine video with translated audio and subtitles
357
+ try:
358
+ # Attempt method 1: Using subtitles filter
 
 
359
  cmd = [
360
  'ffmpeg',
361
+ '-i', video_path, # Input video
362
+ '-i', audio_path, # Input translated audio
363
+ '-map', '0:v', # Use video from first input
364
+ '-map', '1:a', # Use audio from second input
365
+ '-vf', f"subtitles={safe_srt_path}:force_style='FontSize=24,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,BorderStyle=3'", # Burn subtitles
366
+ '-c:v', 'libx264', # Video codec
367
+ '-c:a', 'aac', # Audio codec
368
+ '-shortest', # End when shortest input ends
369
+ '-y', # Overwrite output file
370
  output_path
371
  ]
372
 
373
+ logger.info(f"Running command: {' '.join(cmd)}")
374
  process = subprocess.run(cmd, capture_output=True, text=True)
375
 
376
  if process.returncode != 0:
377
+ logger.warning(f"First method failed: {process.stderr}")
378
+ raise Exception("First method failed")
379
+
380
+ except Exception as e:
381
+ logger.warning(f"First method failed: {str(e)}")
382
+
383
+ try:
384
+ # Attempt method 2: Using hardcoded subtitles approach
385
+ temp_srt_dir = os.path.join(OUTPUT_DIR, "temp_srt")
386
+ os.makedirs(temp_srt_dir, exist_ok=True)
387
+
388
+ # Copy the SRT file to the temp directory
389
+ temp_srt_path = os.path.join(temp_srt_dir, "temp.srt")
390
+ shutil.copy(srt_path, temp_srt_path)
391
+
392
+ cmd = [
393
+ 'ffmpeg',
394
+ '-i', video_path,
395
+ '-i', audio_path,
396
+ '-map', '0:v',
397
+ '-map', '1:a',
398
+ '-vf', f"subtitles={temp_srt_path}",
399
+ '-c:v', 'libx264',
400
+ '-c:a', 'aac',
401
+ '-shortest',
402
+ '-y',
403
+ output_path
404
+ ]
405
+
406
+ logger.info(f"Running second method: {' '.join(cmd)}")
407
+ process = subprocess.run(cmd, capture_output=True, text=True)
408
+
409
+ if process.returncode != 0:
410
+ logger.warning(f"Second method failed: {process.stderr}")
411
+ raise Exception("Second method failed")
412
+
413
+ # Clean up temp directory
414
+ shutil.rmtree(temp_srt_dir)
415
+
416
+ except Exception as e:
417
+ logger.warning(f"Second method failed: {str(e)}")
418
+
419
+ # Attempt method 3: No subtitles as last resort
420
+ cmd = [
421
+ 'ffmpeg',
422
+ '-i', video_path,
423
+ '-i', audio_path,
424
+ '-map', '0:v',
425
+ '-map', '1:a',
426
+ '-c:v', 'libx264',
427
+ '-c:a', 'aac',
428
+ '-shortest',
429
+ '-y',
430
+ output_path
431
+ ]
432
+
433
+ logger.info(f"Running fallback method (no subtitles): {' '.join(cmd)}")
434
+ process = subprocess.run(cmd, capture_output=True, text=True)
435
+
436
+ if process.returncode != 0:
437
+ logger.error(f"All methods failed: {process.stderr}")
438
+ raise Exception(f"Failed to combine video and audio: {process.stderr}")
439
+ else:
440
+ logger.warning("Created video without subtitles as fallback")
441
 
442
+ # Verify the output file exists and has a reasonable size
443
+ if not os.path.exists(output_path):
444
+ raise Exception(f"Output file does not exist: {output_path}")
445
+
446
+ if os.path.getsize(output_path) < 1000:
447
+ raise Exception(f"Output file is too small: {os.path.getsize(output_path)} bytes")
448
+
449
+ logger.info(f"Successfully created output file: {output_path} ({os.path.getsize(output_path)} bytes)")
450
  return output_path
451
  except Exception as e:
452
  logger.error(f"Combining failed: {str(e)}", exc_info=True)
 
496
  logger.info(f"Generating translated audio for {lang_code}")
497
  translated_audio = generate_translated_audio(sub_path, lang_code)
498
 
499
+ # Verify audio file exists
500
+ if not os.path.exists(translated_audio):
501
+ logger.error(f"Translated audio file does not exist: {translated_audio}")
502
+ continue
503
+
504
  # Combine video, translated audio, and subtitles
505
  output_path = os.path.join(OUTPUT_DIR, f"output_{lang_code}.mp4")
506
  logger.info(f"Creating final video with {lang_code} audio and subtitles")