Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -60,7 +60,8 @@ def process_video(video_file, language="hindi", progress=gr.Progress()):
|
|
| 60 |
print(f"Extracting audio from: {video_file}")
|
| 61 |
video = VideoFileClip(video_file)
|
| 62 |
if not video.audio:
|
| 63 |
-
shutil.rmtree(
|
|
|
|
| 64 |
return None, None, "Video has no audio track"
|
| 65 |
|
| 66 |
video.audio.write_audiofile(
|
|
@@ -78,7 +79,7 @@ def process_video(video_file, language="hindi", progress=gr.Progress()):
|
|
| 78 |
progress(0.4, desc="Transcribing with Whisper Turbo...")
|
| 79 |
print(f"Starting transcription (language: {language})...")
|
| 80 |
|
| 81 |
-
|
| 82 |
audio_path,
|
| 83 |
return_timestamps=True,
|
| 84 |
generate_kwargs={
|
|
@@ -87,67 +88,48 @@ def process_video(video_file, language="hindi", progress=gr.Progress()):
|
|
| 87 |
}
|
| 88 |
)
|
| 89 |
|
| 90 |
-
print(f"Transcription result keys: {
|
| 91 |
|
| 92 |
# Verify we have chunks
|
| 93 |
-
if not
|
| 94 |
-
error_msg = f"Transcription returned no segments. Full result: {
|
| 95 |
print(error_msg)
|
| 96 |
-
shutil.rmtree(
|
|
|
|
| 97 |
return None, None, error_msg
|
| 98 |
|
| 99 |
-
print(f"Transcription complete: {len(
|
| 100 |
|
| 101 |
# Create SRT in output directory (persistent)
|
| 102 |
progress(0.6, desc="Creating SRT...")
|
| 103 |
srt_path = os.path.join(output_dir, "subtitles.srt")
|
| 104 |
|
| 105 |
print(f"Creating SRT at: {srt_path}")
|
| 106 |
-
print(f"Output directory exists: {os.path.exists(output_dir)}")
|
| 107 |
-
print(f"Output directory contents before SRT: {os.listdir(output_dir)}")
|
| 108 |
-
|
| 109 |
-
try:
|
| 110 |
-
with open(srt_path, 'w', encoding='utf-8-sig') as f:
|
| 111 |
-
for i, chunk in enumerate(result['chunks'], 1):
|
| 112 |
-
start, end = chunk['timestamp']
|
| 113 |
-
text = chunk['text'].strip()
|
| 114 |
-
|
| 115 |
-
if text:
|
| 116 |
-
f.write(f"{i}\n")
|
| 117 |
-
f.write(f"{format_srt_time(start)} --> {format_srt_time(end)}\n")
|
| 118 |
-
f.write(f"{text}\n\n")
|
| 119 |
-
|
| 120 |
-
print(f"SRT file write completed")
|
| 121 |
-
except Exception as e:
|
| 122 |
-
print(f"Error writing SRT file: {e}")
|
| 123 |
-
import traceback
|
| 124 |
-
print(traceback.format_exc())
|
| 125 |
-
shutil.rmtree(output_dir)
|
| 126 |
-
raise
|
| 127 |
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
|
|
|
|
| 132 |
if not os.path.exists(srt_path):
|
| 133 |
-
shutil.rmtree(
|
| 134 |
-
|
|
|
|
| 135 |
|
| 136 |
srt_size = os.path.getsize(srt_path)
|
| 137 |
if srt_size == 0:
|
| 138 |
-
shutil.rmtree(
|
|
|
|
| 139 |
return None, None, f"SRT file is empty at: {srt_path}"
|
| 140 |
|
| 141 |
print(f"SRT created successfully: {srt_path} ({srt_size} bytes)")
|
| 142 |
|
| 143 |
-
# Read SRT content for debugging
|
| 144 |
-
try:
|
| 145 |
-
with open(srt_path, 'r', encoding='utf-8-sig') as f:
|
| 146 |
-
srt_preview = f.read()[:500]
|
| 147 |
-
print(f"SRT preview:\n{srt_preview}")
|
| 148 |
-
except Exception as e:
|
| 149 |
-
print(f"Error reading SRT file: {e}")
|
| 150 |
-
|
| 151 |
# Burn subtitles
|
| 152 |
progress(0.85, desc="Burning subtitles...")
|
| 153 |
output_path = os.path.join(output_dir, "final.mp4")
|
|
@@ -158,193 +140,20 @@ def process_video(video_file, language="hindi", progress=gr.Progress()):
|
|
| 158 |
ass_path = os.path.join(output_dir, "subtitles.ass")
|
| 159 |
|
| 160 |
print(f"Converting SRT to ASS for better compatibility...")
|
| 161 |
-
|
| 162 |
-
subprocess.run([
|
| 163 |
-
'ffmpeg', '-y',
|
| 164 |
-
'-i', srt_path,
|
| 165 |
-
ass_path
|
| 166 |
-
], check=True, capture_output=True, text=True)
|
| 167 |
-
|
| 168 |
-
if not os.path.exists(ass_path):
|
| 169 |
-
raise Exception(f"Failed to create ASS file at {ass_path}")
|
| 170 |
-
|
| 171 |
-
print(f"ASS file created: {ass_path} ({os.path.getsize(ass_path)} bytes)")
|
| 172 |
-
except subprocess.CalledProcessError as e:
|
| 173 |
-
print(f"SRT to ASS conversion failed: {e.stderr}")
|
| 174 |
-
shutil.rmtree(output_dir)
|
| 175 |
-
raise
|
| 176 |
-
|
| 177 |
-
# Use ASS filter which is more reliable than subtitles filter
|
| 178 |
-
# For ass filter, we need to escape special characters differently
|
| 179 |
-
ass_path_escaped = ass_path.replace('\\', '\\\\').replace(':', '\\:')
|
| 180 |
-
|
| 181 |
-
ffmpeg_cmd = [
|
| 182 |
'ffmpeg', '-y',
|
| 183 |
-
'-i',
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
'-c:v', 'libx264',
|
| 187 |
-
'-preset', 'medium',
|
| 188 |
-
'-crf', '23',
|
| 189 |
-
output_path
|
| 190 |
-
]
|
| 191 |
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
try:
|
| 195 |
-
ffmpeg_result = subprocess.run(
|
| 196 |
-
ffmpeg_cmd,
|
| 197 |
-
check=True,
|
| 198 |
-
capture_output=True,
|
| 199 |
-
text=True,
|
| 200 |
-
timeout=600
|
| 201 |
-
)
|
| 202 |
-
print(f"FFmpeg stdout: {ffmpeg_result.stdout}")
|
| 203 |
-
print(f"FFmpeg stderr: {ffmpeg_result.stderr}")
|
| 204 |
-
except subprocess.CalledProcessError as e:
|
| 205 |
-
print(f"FFmpeg failed!")
|
| 206 |
-
print(f"Return code: {e.returncode}")
|
| 207 |
-
print(f"Stdout: {e.stdout}")
|
| 208 |
-
print(f"Stderr: {e.stderr}")
|
| 209 |
-
shutil.rmtree(output_dir)
|
| 210 |
-
raise
|
| 211 |
-
|
| 212 |
-
if not os.path.exists(output_path):
|
| 213 |
-
shutil.rmtree(output_dir)
|
| 214 |
-
return None, None, f"Output video was not created at: {output_path}"
|
| 215 |
-
|
| 216 |
-
print(f"Video created: {output_path} ({os.path.getsize(output_path)} bytes)")
|
| 217 |
-
|
| 218 |
-
progress(1.0, desc="Complete!")
|
| 219 |
-
|
| 220 |
-
# Create status with preview
|
| 221 |
-
preview_lines = []
|
| 222 |
-
for i, chunk in enumerate(result['chunks'][:10], 1):
|
| 223 |
-
text = chunk['text'].strip()
|
| 224 |
-
start_time = chunk['timestamp'][0]
|
| 225 |
-
preview_lines.append(f"{i}. [{start_time:.1f}s] {text}")
|
| 226 |
-
|
| 227 |
-
preview_text = "\n".join(preview_lines)
|
| 228 |
-
full_text = " ".join([c['text'].strip() for c in result['chunks']])
|
| 229 |
-
|
| 230 |
-
status = f"""Processing Complete!
|
| 231 |
-
Statistics:
|
| 232 |
-
- Model: Whisper Large V3 Turbo
|
| 233 |
-
- Device: {device}
|
| 234 |
-
- Segments: {len(result['chunks'])}
|
| 235 |
-
- Duration: {result['chunks'][-1]['timestamp'][1]:.1f}s
|
| 236 |
-
- Language: {language}
|
| 237 |
-
|
| 238 |
-
Preview (first 10 segments):
|
| 239 |
-
{preview_text}
|
| 240 |
-
|
| 241 |
-
Full Transcription:
|
| 242 |
-
{full_text[:500]}{"..." if len(full_text) > 500 else ""}
|
| 243 |
-
|
| 244 |
-
Files created successfully!
|
| 245 |
-
"""
|
| 246 |
-
|
| 247 |
-
# Don't cleanup output_dir - Gradio needs these files
|
| 248 |
-
return srt_path, output_path, status
|
| 249 |
-
|
| 250 |
-
except subprocess.TimeoutExpired:
|
| 251 |
-
try:
|
| 252 |
shutil.rmtree(temp_dir, ignore_errors=True)
|
| 253 |
shutil.rmtree(output_dir, ignore_errors=True)
|
| 254 |
-
|
| 255 |
-
pass
|
| 256 |
-
return None, None, "Processing timeout. Try a shorter video."
|
| 257 |
-
except subprocess.CalledProcessError as e:
|
| 258 |
-
try:
|
| 259 |
-
shutil.rmtree(temp_dir, ignore_errors=True)
|
| 260 |
-
shutil.rmtree(output_dir, ignore_errors=True)
|
| 261 |
-
except:
|
| 262 |
-
pass
|
| 263 |
-
error_detail = e.stderr.decode() if hasattr(e.stderr, 'decode') else str(e.stderr) if e.stderr else str(e)
|
| 264 |
-
return None, None, f"FFmpeg error: {error_detail}"
|
| 265 |
-
except Exception as e:
|
| 266 |
-
try:
|
| 267 |
-
shutil.rmtree(temp_dir, ignore_errors=True)
|
| 268 |
-
shutil.rmtree(output_dir, ignore_errors=True)
|
| 269 |
-
except:
|
| 270 |
-
pass
|
| 271 |
-
import traceback
|
| 272 |
-
error_trace = traceback.format_exc()
|
| 273 |
-
print(f"Error: {error_trace}")
|
| 274 |
-
return None, None, f"Error: {str(e)}\n\nDetails:\n{error_trace}"
|
| 275 |
-
finally:
|
| 276 |
-
# Only cleanup temp_dir (audio processing), keep output_dir for Gradio
|
| 277 |
-
try:
|
| 278 |
-
shutil.rmtree(temp_dir)
|
| 279 |
-
print(f"Cleaned up temp directory: {temp_dir}")
|
| 280 |
-
except Exception as e:
|
| 281 |
-
print(f"Cleanup warning: {e}")
|
| 282 |
-
# Note: output_dir is NOT cleaned up here - Gradio needs access to the files
|
| 283 |
-
# The files will be cleaned up by the OS eventually from /tmp/, 'w', encoding='utf-8-sig') as f:
|
| 284 |
-
for i, chunk in enumerate(result['chunks'], 1):
|
| 285 |
-
start, end = chunk['timestamp']
|
| 286 |
-
text = chunk['text'].strip()
|
| 287 |
-
|
| 288 |
-
if text:
|
| 289 |
-
f.write(f"{i}\n")
|
| 290 |
-
f.write(f"{format_srt_time(start)} --> {format_srt_time(end)}\n")
|
| 291 |
-
f.write(f"{text}\n\n")
|
| 292 |
-
|
| 293 |
-
print(f"SRT file write completed")
|
| 294 |
-
except Exception as e:
|
| 295 |
-
print(f"Error writing SRT file: {e}")
|
| 296 |
-
import traceback
|
| 297 |
-
print(traceback.format_exc())
|
| 298 |
-
raise
|
| 299 |
-
|
| 300 |
-
# Verify SRT was created
|
| 301 |
-
print(f"Checking if SRT exists: {os.path.exists(srt_path)}")
|
| 302 |
-
print(f"Temp directory contents after SRT: {os.listdir(temp_dir)}")
|
| 303 |
|
| 304 |
-
|
| 305 |
-
return None, None, f"SRT file was not created at: {srt_path}\nDirectory contents: {os.listdir(temp_dir)}"
|
| 306 |
|
| 307 |
-
|
| 308 |
-
if srt_size == 0:
|
| 309 |
-
return None, None, f"SRT file is empty at: {srt_path}"
|
| 310 |
-
|
| 311 |
-
print(f"SRT created successfully: {srt_path} ({srt_size} bytes)")
|
| 312 |
-
|
| 313 |
-
# Read SRT content for debugging
|
| 314 |
-
try:
|
| 315 |
-
with open(srt_path, 'r', encoding='utf-8-sig') as f:
|
| 316 |
-
srt_preview = f.read()[:500]
|
| 317 |
-
print(f"SRT preview:\n{srt_preview}")
|
| 318 |
-
except Exception as e:
|
| 319 |
-
print(f"Error reading SRT file: {e}")
|
| 320 |
-
|
| 321 |
-
# Burn subtitles
|
| 322 |
-
progress(0.85, desc="Burning subtitles...")
|
| 323 |
-
output_path = os.path.join(temp_dir, "final.mp4")
|
| 324 |
-
|
| 325 |
-
print("Burning subtitles with FFmpeg...")
|
| 326 |
-
|
| 327 |
-
# Convert SRT to ASS first (more reliable with FFmpeg)
|
| 328 |
-
ass_path = os.path.join(temp_dir, "subtitles.ass")
|
| 329 |
-
|
| 330 |
-
print(f"Converting SRT to ASS for better compatibility...")
|
| 331 |
-
try:
|
| 332 |
-
subprocess.run([
|
| 333 |
-
'ffmpeg', '-y',
|
| 334 |
-
'-i', srt_path,
|
| 335 |
-
ass_path
|
| 336 |
-
], check=True, capture_output=True, text=True)
|
| 337 |
-
|
| 338 |
-
if not os.path.exists(ass_path):
|
| 339 |
-
raise Exception(f"Failed to create ASS file at {ass_path}")
|
| 340 |
-
|
| 341 |
-
print(f"ASS file created: {ass_path} ({os.path.getsize(ass_path)} bytes)")
|
| 342 |
-
except subprocess.CalledProcessError as e:
|
| 343 |
-
print(f"SRT to ASS conversion failed: {e.stderr}")
|
| 344 |
-
raise
|
| 345 |
-
|
| 346 |
-
# Use ASS filter which is more reliable than subtitles filter
|
| 347 |
-
# For ass filter, we need to escape special characters differently
|
| 348 |
ass_path_escaped = ass_path.replace('\\', '\\\\').replace(':', '\\:')
|
| 349 |
|
| 350 |
ffmpeg_cmd = [
|
|
@@ -360,24 +169,17 @@ Files created successfully!
|
|
| 360 |
|
| 361 |
print(f"FFmpeg command: {' '.join(ffmpeg_cmd)}")
|
| 362 |
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
)
|
| 371 |
-
print(f"FFmpeg stdout: {ffmpeg_result.stdout}")
|
| 372 |
-
print(f"FFmpeg stderr: {ffmpeg_result.stderr}")
|
| 373 |
-
except subprocess.CalledProcessError as e:
|
| 374 |
-
print(f"FFmpeg failed!")
|
| 375 |
-
print(f"Return code: {e.returncode}")
|
| 376 |
-
print(f"Stdout: {e.stdout}")
|
| 377 |
-
print(f"Stderr: {e.stderr}")
|
| 378 |
-
raise
|
| 379 |
|
| 380 |
if not os.path.exists(output_path):
|
|
|
|
|
|
|
| 381 |
return None, None, f"Output video was not created at: {output_path}"
|
| 382 |
|
| 383 |
print(f"Video created: {output_path} ({os.path.getsize(output_path)} bytes)")
|
|
@@ -386,20 +188,20 @@ Files created successfully!
|
|
| 386 |
|
| 387 |
# Create status with preview
|
| 388 |
preview_lines = []
|
| 389 |
-
for i, chunk in enumerate(
|
| 390 |
text = chunk['text'].strip()
|
| 391 |
start_time = chunk['timestamp'][0]
|
| 392 |
preview_lines.append(f"{i}. [{start_time:.1f}s] {text}")
|
| 393 |
|
| 394 |
preview_text = "\n".join(preview_lines)
|
| 395 |
-
full_text = " ".join([c['text'].strip() for c in
|
| 396 |
|
| 397 |
status = f"""Processing Complete!
|
| 398 |
Statistics:
|
| 399 |
- Model: Whisper Large V3 Turbo
|
| 400 |
- Device: {device}
|
| 401 |
-
- Segments: {len(
|
| 402 |
-
- Duration: {
|
| 403 |
- Language: {language}
|
| 404 |
|
| 405 |
Preview (first 10 segments):
|
|
@@ -411,25 +213,29 @@ Full Transcription:
|
|
| 411 |
Files created successfully!
|
| 412 |
"""
|
| 413 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 414 |
return srt_path, output_path, status
|
| 415 |
|
| 416 |
except subprocess.TimeoutExpired:
|
|
|
|
|
|
|
| 417 |
return None, None, "Processing timeout. Try a shorter video."
|
| 418 |
except subprocess.CalledProcessError as e:
|
| 419 |
-
|
|
|
|
|
|
|
| 420 |
return None, None, f"FFmpeg error: {error_detail}"
|
| 421 |
except Exception as e:
|
|
|
|
|
|
|
| 422 |
import traceback
|
| 423 |
error_trace = traceback.format_exc()
|
| 424 |
print(f"Error: {error_trace}")
|
| 425 |
return None, None, f"Error: {str(e)}\n\nDetails:\n{error_trace}"
|
| 426 |
-
finally:
|
| 427 |
-
# Cleanup
|
| 428 |
-
try:
|
| 429 |
-
shutil.rmtree(temp_dir)
|
| 430 |
-
print(f"Cleaned up temp directory: {temp_dir}")
|
| 431 |
-
except Exception as e:
|
| 432 |
-
print(f"Cleanup warning: {e}")
|
| 433 |
|
| 434 |
# Gradio UI
|
| 435 |
with gr.Blocks(theme=gr.themes.Soft(), title="Hindi Subtitle Generator") as demo:
|
|
|
|
| 60 |
print(f"Extracting audio from: {video_file}")
|
| 61 |
video = VideoFileClip(video_file)
|
| 62 |
if not video.audio:
|
| 63 |
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
| 64 |
+
shutil.rmtree(output_dir, ignore_errors=True)
|
| 65 |
return None, None, "Video has no audio track"
|
| 66 |
|
| 67 |
video.audio.write_audiofile(
|
|
|
|
| 79 |
progress(0.4, desc="Transcribing with Whisper Turbo...")
|
| 80 |
print(f"Starting transcription (language: {language})...")
|
| 81 |
|
| 82 |
+
transcription_result = pipe(
|
| 83 |
audio_path,
|
| 84 |
return_timestamps=True,
|
| 85 |
generate_kwargs={
|
|
|
|
| 88 |
}
|
| 89 |
)
|
| 90 |
|
| 91 |
+
print(f"Transcription result keys: {transcription_result.keys()}")
|
| 92 |
|
| 93 |
# Verify we have chunks
|
| 94 |
+
if not transcription_result.get('chunks') or len(transcription_result['chunks']) == 0:
|
| 95 |
+
error_msg = f"Transcription returned no segments. Full result: {transcription_result}"
|
| 96 |
print(error_msg)
|
| 97 |
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
| 98 |
+
shutil.rmtree(output_dir, ignore_errors=True)
|
| 99 |
return None, None, error_msg
|
| 100 |
|
| 101 |
+
print(f"Transcription complete: {len(transcription_result['chunks'])} segments")
|
| 102 |
|
| 103 |
# Create SRT in output directory (persistent)
|
| 104 |
progress(0.6, desc="Creating SRT...")
|
| 105 |
srt_path = os.path.join(output_dir, "subtitles.srt")
|
| 106 |
|
| 107 |
print(f"Creating SRT at: {srt_path}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
|
| 109 |
+
with open(srt_path, 'w', encoding='utf-8-sig') as f:
|
| 110 |
+
for i, chunk in enumerate(transcription_result['chunks'], 1):
|
| 111 |
+
start, end = chunk['timestamp']
|
| 112 |
+
text = chunk['text'].strip()
|
| 113 |
+
|
| 114 |
+
if text:
|
| 115 |
+
f.write(f"{i}\n")
|
| 116 |
+
f.write(f"{format_srt_time(start)} --> {format_srt_time(end)}\n")
|
| 117 |
+
f.write(f"{text}\n\n")
|
| 118 |
|
| 119 |
+
# Verify SRT was created
|
| 120 |
if not os.path.exists(srt_path):
|
| 121 |
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
| 122 |
+
shutil.rmtree(output_dir, ignore_errors=True)
|
| 123 |
+
return None, None, f"SRT file was not created at: {srt_path}"
|
| 124 |
|
| 125 |
srt_size = os.path.getsize(srt_path)
|
| 126 |
if srt_size == 0:
|
| 127 |
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
| 128 |
+
shutil.rmtree(output_dir, ignore_errors=True)
|
| 129 |
return None, None, f"SRT file is empty at: {srt_path}"
|
| 130 |
|
| 131 |
print(f"SRT created successfully: {srt_path} ({srt_size} bytes)")
|
| 132 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
# Burn subtitles
|
| 134 |
progress(0.85, desc="Burning subtitles...")
|
| 135 |
output_path = os.path.join(output_dir, "final.mp4")
|
|
|
|
| 140 |
ass_path = os.path.join(output_dir, "subtitles.ass")
|
| 141 |
|
| 142 |
print(f"Converting SRT to ASS for better compatibility...")
|
| 143 |
+
subprocess.run([
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
'ffmpeg', '-y',
|
| 145 |
+
'-i', srt_path,
|
| 146 |
+
ass_path
|
| 147 |
+
], check=True, capture_output=True, text=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
|
| 149 |
+
if not os.path.exists(ass_path):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
shutil.rmtree(temp_dir, ignore_errors=True)
|
| 151 |
shutil.rmtree(output_dir, ignore_errors=True)
|
| 152 |
+
raise Exception(f"Failed to create ASS file at {ass_path}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
|
| 154 |
+
print(f"ASS file created: {ass_path} ({os.path.getsize(ass_path)} bytes)")
|
|
|
|
| 155 |
|
| 156 |
+
# Use ASS filter - escape path for FFmpeg
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
ass_path_escaped = ass_path.replace('\\', '\\\\').replace(':', '\\:')
|
| 158 |
|
| 159 |
ffmpeg_cmd = [
|
|
|
|
| 169 |
|
| 170 |
print(f"FFmpeg command: {' '.join(ffmpeg_cmd)}")
|
| 171 |
|
| 172 |
+
subprocess.run(
|
| 173 |
+
ffmpeg_cmd,
|
| 174 |
+
check=True,
|
| 175 |
+
capture_output=True,
|
| 176 |
+
text=True,
|
| 177 |
+
timeout=600
|
| 178 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
|
| 180 |
if not os.path.exists(output_path):
|
| 181 |
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
| 182 |
+
shutil.rmtree(output_dir, ignore_errors=True)
|
| 183 |
return None, None, f"Output video was not created at: {output_path}"
|
| 184 |
|
| 185 |
print(f"Video created: {output_path} ({os.path.getsize(output_path)} bytes)")
|
|
|
|
| 188 |
|
| 189 |
# Create status with preview
|
| 190 |
preview_lines = []
|
| 191 |
+
for i, chunk in enumerate(transcription_result['chunks'][:10], 1):
|
| 192 |
text = chunk['text'].strip()
|
| 193 |
start_time = chunk['timestamp'][0]
|
| 194 |
preview_lines.append(f"{i}. [{start_time:.1f}s] {text}")
|
| 195 |
|
| 196 |
preview_text = "\n".join(preview_lines)
|
| 197 |
+
full_text = " ".join([c['text'].strip() for c in transcription_result['chunks']])
|
| 198 |
|
| 199 |
status = f"""Processing Complete!
|
| 200 |
Statistics:
|
| 201 |
- Model: Whisper Large V3 Turbo
|
| 202 |
- Device: {device}
|
| 203 |
+
- Segments: {len(transcription_result['chunks'])}
|
| 204 |
+
- Duration: {transcription_result['chunks'][-1]['timestamp'][1]:.1f}s
|
| 205 |
- Language: {language}
|
| 206 |
|
| 207 |
Preview (first 10 segments):
|
|
|
|
| 213 |
Files created successfully!
|
| 214 |
"""
|
| 215 |
|
| 216 |
+
# Cleanup only temp_dir, keep output_dir for Gradio
|
| 217 |
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
| 218 |
+
print(f"Cleaned up temp directory: {temp_dir}")
|
| 219 |
+
|
| 220 |
+
# Return paths - Gradio needs these files to exist
|
| 221 |
return srt_path, output_path, status
|
| 222 |
|
| 223 |
except subprocess.TimeoutExpired:
|
| 224 |
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
| 225 |
+
shutil.rmtree(output_dir, ignore_errors=True)
|
| 226 |
return None, None, "Processing timeout. Try a shorter video."
|
| 227 |
except subprocess.CalledProcessError as e:
|
| 228 |
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
| 229 |
+
shutil.rmtree(output_dir, ignore_errors=True)
|
| 230 |
+
error_detail = e.stderr if hasattr(e, 'stderr') else str(e)
|
| 231 |
return None, None, f"FFmpeg error: {error_detail}"
|
| 232 |
except Exception as e:
|
| 233 |
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
| 234 |
+
shutil.rmtree(output_dir, ignore_errors=True)
|
| 235 |
import traceback
|
| 236 |
error_trace = traceback.format_exc()
|
| 237 |
print(f"Error: {error_trace}")
|
| 238 |
return None, None, f"Error: {str(e)}\n\nDetails:\n{error_trace}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 239 |
|
| 240 |
# Gradio UI
|
| 241 |
with gr.Blocks(theme=gr.themes.Soft(), title="Hindi Subtitle Generator") as demo:
|