Nick088 commited on
Commit
809aa1a
1 Parent(s): 02e16ea

added handle invalid api key error + yt-dlp input links

Browse files
Files changed (1) hide show
  1. app.py +96 -35
app.py CHANGED
@@ -4,6 +4,7 @@ import json
4
  from datetime import timedelta
5
  import tempfile
6
  import re
 
7
  import gradio as gr
8
  import groq
9
  from groq import Groq
@@ -25,7 +26,11 @@ def handle_groq_error(e, model_name):
25
  json_str = json_str.replace("'", '"') # Replace single quotes with double quotes
26
  error_data = json.loads(json_str)
27
 
28
- if isinstance(e, groq.RateLimitError):
 
 
 
 
29
  if isinstance(error_data, dict) and 'error' in error_data and 'message' in error_data['error']:
30
  error_message = error_data['error']['message']
31
  raise gr.Error(error_message)
@@ -138,16 +143,42 @@ LANGUAGE_CODES = {
138
  }
139
 
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  # helper functions
142
 
143
- def split_audio(audio_file_path, chunk_size_mb):
144
  chunk_size = chunk_size_mb * 1024 * 1024 # Convert MB to bytes
145
  file_number = 1
146
  chunks = []
147
- with open(audio_file_path, 'rb') as f:
148
  chunk = f.read(chunk_size)
149
  while chunk:
150
- chunk_name = f"{os.path.splitext(audio_file_path)[0]}_part{file_number:03}.mp3" # Pad file number for correct ordering
151
  with open(chunk_name, 'wb') as chunk_file:
152
  chunk_file.write(chunk)
153
  chunks.append(chunk_name)
@@ -188,12 +219,12 @@ ALLOWED_FILE_EXTENSIONS = ["mp3", "mp4", "mpeg", "mpga", "m4a", "wav", "webm"]
188
  MAX_FILE_SIZE_MB = 25
189
  CHUNK_SIZE_MB = 25
190
 
191
- def check_file(audio_file_path):
192
- if not audio_file_path:
193
  raise gr.Error("Please upload an audio/video file.")
194
 
195
- file_size_mb = os.path.getsize(audio_file_path) / (1024 * 1024)
196
- file_extension = audio_file_path.split(".")[-1].lower()
197
 
198
  if file_extension not in ALLOWED_FILE_EXTENSIONS:
199
  raise gr.Error(f"Invalid file type (.{file_extension}). Allowed types: {', '.join(ALLOWED_FILE_EXTENSIONS)}")
@@ -203,13 +234,13 @@ def check_file(audio_file_path):
203
  f"File size too large ({file_size_mb:.2f} MB). Attempting to downsample to 16kHz MP3 128kbps. Maximum size allowed: {MAX_FILE_SIZE_MB} MB"
204
  )
205
 
206
- output_file_path = os.path.splitext(audio_file_path)[0] + "_downsampled.mp3"
207
  try:
208
  subprocess.run(
209
  [
210
  "ffmpeg",
211
  "-i",
212
- audio_file_path,
213
  "-ar",
214
  "16000",
215
  "-ab",
@@ -233,7 +264,7 @@ def check_file(audio_file_path):
233
  return output_file_path, None
234
  except subprocess.CalledProcessError as e:
235
  raise gr.Error(f"Error during downsampling: {e}")
236
- return audio_file_path, None
237
 
238
 
239
  # subtitle maker
@@ -260,8 +291,13 @@ def json_to_srt(transcription_json):
260
  return '\n'.join(srt_lines)
261
 
262
 
263
- def generate_subtitles(audio_file_path, prompt, language, auto_detect_language, model, include_video, font_selection, font_file, font_color, font_size, outline_thickness, outline_color):
264
- processed_path, split_status = check_file(audio_file_path)
 
 
 
 
 
265
  full_srt_content = ""
266
  total_duration = 0
267
  segment_id_offset = 0
@@ -298,7 +334,7 @@ def generate_subtitles(audio_file_path, prompt, language, auto_detect_language,
298
  temp_srt_file.write("\n") # add a new line at the end of the srt chunk file to fix format when merged
299
  srt_chunks.append(temp_srt_path)
300
 
301
- if include_video and audio_file_path.lower().endswith((".mp4", ".webm")):
302
  try:
303
  output_file_path = chunk_path.replace(os.path.splitext(chunk_path)[1], "_with_subs" + os.path.splitext(chunk_path)[1])
304
  # Handle font selection
@@ -330,8 +366,10 @@ def generate_subtitles(audio_file_path, prompt, language, auto_detect_language,
330
  video_chunks.append(output_file_path)
331
  except subprocess.CalledProcessError as e:
332
  raise gr.Error(f"Error during subtitle addition: {e}")
333
- elif include_video and not audio_file_path.lower().endswith((".mp4", ".webm")):
334
- gr.Warning(f"You have checked on the 'Include Video with Subtitles', but the input file {audio_file_path} isn't a video (.mp4 or .webm). Returning only the SRT File.", duration=15)
 
 
335
  except groq.RateLimitError as e:
336
  handle_groq_error(e, model)
337
  gr.Warning(f"API limit reached during chunk {i+1}. Returning processed chunks only.")
@@ -346,7 +384,7 @@ def generate_subtitles(audio_file_path, prompt, language, auto_detect_language,
346
  raise gr.Error("Subtitle generation failed due to API limits.")
347
 
348
  # Merge SRT chunks
349
- final_srt_path = os.path.splitext(audio_file_path)[0] + "_final.srt"
350
  with open(final_srt_path, 'w', encoding="utf-8") as outfile:
351
  for chunk_srt in srt_chunks:
352
  with open(chunk_srt, 'r', encoding="utf-8") as infile:
@@ -373,14 +411,14 @@ def generate_subtitles(audio_file_path, prompt, language, auto_detect_language,
373
  transcription_json = transcription_json_response.segments
374
 
375
  srt_content = json_to_srt(transcription_json)
376
- temp_srt_path = os.path.splitext(audio_file_path)[0] + ".srt"
377
  with open(temp_srt_path, "w", encoding="utf-8") as temp_srt_file:
378
  temp_srt_file.write(srt_content)
379
 
380
- if include_video and audio_file_path.lower().endswith((".mp4", ".webm")):
381
  try:
382
- output_file_path = audio_file_path.replace(
383
- os.path.splitext(audio_file_path)[1], "_with_subs" + os.path.splitext(audio_file_path)[1]
384
  )
385
  # Handle font selection
386
  if font_selection == "Custom Font File" and font_file:
@@ -400,7 +438,7 @@ def generate_subtitles(audio_file_path, prompt, language, auto_detect_language,
400
  "ffmpeg",
401
  "-y",
402
  "-i",
403
- audio_file_path,
404
  "-vf",
405
  f"subtitles={temp_srt_path}:fontsdir={font_dir}:force_style='FontName={font_name},Fontsize={int(font_size)},PrimaryColour=&H{font_color[1:]}&,OutlineColour=&H{outline_color[1:]}&,BorderStyle={int(outline_thickness)},Outline=1'",
406
  "-preset", "fast",
@@ -411,10 +449,12 @@ def generate_subtitles(audio_file_path, prompt, language, auto_detect_language,
411
  return temp_srt_path, output_file_path
412
  except subprocess.CalledProcessError as e:
413
  raise gr.Error(f"Error during subtitle addition: {e}")
414
- elif include_video and not audio_file_path.lower().endswith((".mp4", ".webm")):
415
- gr.Warning(f"You have checked on the 'Include Video with Subtitles', but the input file {audio_file_path} isn't a video (.mp4 or .webm). Returning only the SRT File.", duration=15)
416
 
417
  return temp_srt_path, None
 
 
418
  except groq.RateLimitError as e:
419
  handle_groq_error(e, model)
420
  except ValueError as e:
@@ -452,6 +492,7 @@ h1{text-align:center}
452
  """
453
 
454
 
 
455
  with gr.Blocks(theme=theme, css=css) as interface:
456
  gr.Markdown(
457
  """
@@ -462,16 +503,26 @@ with gr.Blocks(theme=theme, css=css) as interface:
462
  <br> <a href="https://discord.gg/osai"> <img src="https://img.shields.io/discord/1198701940511617164?color=%23738ADB&label=Discord&style=for-the-badge" alt="Discord"> </a>
463
  """
464
  )
465
- with gr.Row():
466
- audio_input_subtitles = gr.File(label="Upload Audio/Video", file_types=[f".{ext}" for ext in ALLOWED_FILE_EXTENSIONS],)
467
- model_choice_subtitles = gr.Dropdown(choices=["whisper-large-v3"], value="whisper-large-v3", label="Audio Speech Recogition (ASR) Model")
468
- with gr.Row():
469
- transcribe_prompt_subtitles = gr.Textbox(label="Prompt (Optional)", info="Specify any context or spelling corrections.")
 
 
 
 
 
 
 
470
  with gr.Row():
471
  language_subtitles = gr.Dropdown(choices=[(lang, code) for lang, code in LANGUAGE_CODES.items()], value="en", label="Language")
472
  auto_detect_language_subtitles = gr.Checkbox(label="Auto Detect Language")
473
- with gr.Row():
474
- transcribe_button_subtitles = gr.Button("Generate Subtitles")
 
 
 
475
  include_video_option = gr.Checkbox(label="Include Video with Subtitles")
476
  gr.Markdown("The SubText Rip (SRT) File, contains the subtitles, you can upload this to any video editing app for adding the subs to your video and also modify/stilyze them")
477
  srt_output = gr.File(label="SRT Output File")
@@ -491,6 +542,15 @@ with gr.Blocks(theme=theme, css=css) as interface:
491
 
492
  # Event bindings
493
 
 
 
 
 
 
 
 
 
 
494
  # show video output
495
  include_video_option.change(lambda include_video: gr.update(visible=include_video), inputs=[include_video_option], outputs=[video_output])
496
  # show video output subs settings checkbox
@@ -501,11 +561,13 @@ with gr.Blocks(theme=theme, css=css) as interface:
501
  show_subtitle_settings.change(lambda show, include_video: gr.update(visible=show and include_video), inputs=[show_subtitle_settings, include_video_option], outputs=[show_subtitle_settings])
502
  # show custom font file selection
503
  font_selection.change(lambda font_selection: gr.update(visible=font_selection == "Custom Font File"), inputs=[font_selection], outputs=[font_file])
504
- # generate subtitles event
505
  transcribe_button_subtitles.click(
506
- generate_subtitles,
507
  inputs=[
508
- audio_input_subtitles,
 
 
509
  transcribe_prompt_subtitles,
510
  language_subtitles,
511
  auto_detect_language_subtitles,
@@ -521,5 +583,4 @@ with gr.Blocks(theme=theme, css=css) as interface:
521
  outputs=[srt_output, video_output],
522
  )
523
 
524
-
525
  interface.launch(share=True)
 
4
  from datetime import timedelta
5
  import tempfile
6
  import re
7
+ import yt_dlp
8
  import gradio as gr
9
  import groq
10
  from groq import Groq
 
26
  json_str = json_str.replace("'", '"') # Replace single quotes with double quotes
27
  error_data = json.loads(json_str)
28
 
29
+ if isinstance(e, groq.AuthenticationError):
30
+ if isinstance(error_data, dict) and 'error' in error_data and 'message' in error_data['error']:
31
+ error_message = error_data['error']['message']
32
+ raise gr.Error(error_message)
33
+ elif isinstance(e, groq.RateLimitError):
34
  if isinstance(error_data, dict) and 'error' in error_data and 'message' in error_data['error']:
35
  error_message = error_data['error']['message']
36
  raise gr.Error(error_message)
 
143
  }
144
 
145
 
146
+ # download link input
147
+ def yt_dlp_download(link):
148
+ try:
149
+ ydl_opts = {
150
+ 'format': 'bestvideo+bestaudio/best', # Download best video and audio or best available
151
+ 'outtmpl': '%(title)s.%(ext)s',
152
+ 'nocheckcertificate': True,
153
+ 'ignoreerrors': False,
154
+ 'no_warnings': True,
155
+ 'quiet': True,
156
+ }
157
+
158
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
159
+ ydl.download([link])
160
+ result = ydl.extract_info(link, download=False)
161
+ download_path = ydl.prepare_filename(result)
162
+
163
+ return download_path
164
+ except yt_dlp.utils.DownloadError as e:
165
+ raise gr.Error(f"Download Error: {e}")
166
+ except ValueError as e:
167
+ raise gr.Error(f"Invalid Link or Format Error: {e}")
168
+ except Exception as e:
169
+ raise gr.Error(f"An unexpected error occurred: {e}")
170
+
171
+
172
  # helper functions
173
 
174
+ def split_audio(input_file_path, chunk_size_mb):
175
  chunk_size = chunk_size_mb * 1024 * 1024 # Convert MB to bytes
176
  file_number = 1
177
  chunks = []
178
+ with open(input_file_path, 'rb') as f:
179
  chunk = f.read(chunk_size)
180
  while chunk:
181
+ chunk_name = f"{os.path.splitext(input_file_path)[0]}_part{file_number:03}.mp3" # Pad file number for correct ordering
182
  with open(chunk_name, 'wb') as chunk_file:
183
  chunk_file.write(chunk)
184
  chunks.append(chunk_name)
 
219
  MAX_FILE_SIZE_MB = 25
220
  CHUNK_SIZE_MB = 25
221
 
222
+ def check_file(input_file_path):
223
+ if not input_file_path:
224
  raise gr.Error("Please upload an audio/video file.")
225
 
226
+ file_size_mb = os.path.getsize(input_file_path) / (1024 * 1024)
227
+ file_extension = input_file_path.split(".")[-1].lower()
228
 
229
  if file_extension not in ALLOWED_FILE_EXTENSIONS:
230
  raise gr.Error(f"Invalid file type (.{file_extension}). Allowed types: {', '.join(ALLOWED_FILE_EXTENSIONS)}")
 
234
  f"File size too large ({file_size_mb:.2f} MB). Attempting to downsample to 16kHz MP3 128kbps. Maximum size allowed: {MAX_FILE_SIZE_MB} MB"
235
  )
236
 
237
+ output_file_path = os.path.splitext(input_file_path)[0] + "_downsampled.mp3"
238
  try:
239
  subprocess.run(
240
  [
241
  "ffmpeg",
242
  "-i",
243
+ input_file_path,
244
  "-ar",
245
  "16000",
246
  "-ab",
 
264
  return output_file_path, None
265
  except subprocess.CalledProcessError as e:
266
  raise gr.Error(f"Error during downsampling: {e}")
267
+ return input_file_path, None
268
 
269
 
270
  # subtitle maker
 
291
  return '\n'.join(srt_lines)
292
 
293
 
294
+ def generate_subtitles(input_mode, input_file, link_input, prompt, language, auto_detect_language, model, include_video, font_selection, font_file, font_color, font_size, outline_thickness, outline_color):
295
+ if input_mode == "Upload Video/Audio File":
296
+ input_file_path = input_file
297
+ elif input_mode == "Link Video/Audio":
298
+ input_file_path = yt_dlp_download(link_input)
299
+
300
+ processed_path, split_status = check_file(input_file_path)
301
  full_srt_content = ""
302
  total_duration = 0
303
  segment_id_offset = 0
 
334
  temp_srt_file.write("\n") # add a new line at the end of the srt chunk file to fix format when merged
335
  srt_chunks.append(temp_srt_path)
336
 
337
+ if include_video and input_file_path.lower().endswith((".mp4", ".webm")):
338
  try:
339
  output_file_path = chunk_path.replace(os.path.splitext(chunk_path)[1], "_with_subs" + os.path.splitext(chunk_path)[1])
340
  # Handle font selection
 
366
  video_chunks.append(output_file_path)
367
  except subprocess.CalledProcessError as e:
368
  raise gr.Error(f"Error during subtitle addition: {e}")
369
+ elif include_video and not input_file_path.lower().endswith((".mp4", ".webm")):
370
+ gr.Warning(f"You have checked on the 'Include Video with Subtitles', but the input file {input_file_path} isn't a video (.mp4 or .webm). Returning only the SRT File.", duration=15)
371
+ except groq.AuthenticationError as e:
372
+ handle_groq_error(e, model)
373
  except groq.RateLimitError as e:
374
  handle_groq_error(e, model)
375
  gr.Warning(f"API limit reached during chunk {i+1}. Returning processed chunks only.")
 
384
  raise gr.Error("Subtitle generation failed due to API limits.")
385
 
386
  # Merge SRT chunks
387
+ final_srt_path = os.path.splitext(input_file_path)[0] + "_final.srt"
388
  with open(final_srt_path, 'w', encoding="utf-8") as outfile:
389
  for chunk_srt in srt_chunks:
390
  with open(chunk_srt, 'r', encoding="utf-8") as infile:
 
411
  transcription_json = transcription_json_response.segments
412
 
413
  srt_content = json_to_srt(transcription_json)
414
+ temp_srt_path = os.path.splitext(input_file_path)[0] + ".srt"
415
  with open(temp_srt_path, "w", encoding="utf-8") as temp_srt_file:
416
  temp_srt_file.write(srt_content)
417
 
418
+ if include_video and input_file_path.lower().endswith((".mp4", ".webm")):
419
  try:
420
+ output_file_path = input_file_path.replace(
421
+ os.path.splitext(input_file_path)[1], "_with_subs" + os.path.splitext(input_file_path)[1]
422
  )
423
  # Handle font selection
424
  if font_selection == "Custom Font File" and font_file:
 
438
  "ffmpeg",
439
  "-y",
440
  "-i",
441
+ input_file_path,
442
  "-vf",
443
  f"subtitles={temp_srt_path}:fontsdir={font_dir}:force_style='FontName={font_name},Fontsize={int(font_size)},PrimaryColour=&H{font_color[1:]}&,OutlineColour=&H{outline_color[1:]}&,BorderStyle={int(outline_thickness)},Outline=1'",
444
  "-preset", "fast",
 
449
  return temp_srt_path, output_file_path
450
  except subprocess.CalledProcessError as e:
451
  raise gr.Error(f"Error during subtitle addition: {e}")
452
+ elif include_video and not input_file_path.lower().endswith((".mp4", ".webm")):
453
+ gr.Warning(f"You have checked on the 'Include Video with Subtitles', but the input file {input_file_path} isn't a video (.mp4 or .webm). Returning only the SRT File.", duration=15)
454
 
455
  return temp_srt_path, None
456
+ except groq.AuthenticationError as e:
457
+ handle_groq_error(e, model)
458
  except groq.RateLimitError as e:
459
  handle_groq_error(e, model)
460
  except ValueError as e:
 
492
  """
493
 
494
 
495
+
496
  with gr.Blocks(theme=theme, css=css) as interface:
497
  gr.Markdown(
498
  """
 
503
  <br> <a href="https://discord.gg/osai"> <img src="https://img.shields.io/discord/1198701940511617164?color=%23738ADB&label=Discord&style=for-the-badge" alt="Discord"> </a>
504
  """
505
  )
506
+
507
+ with gr.Column():
508
+ # Input mode selection
509
+ input_mode = gr.Dropdown(choices=["Upload Video/Audio File", "Link Video/Audio"], value="Upload Video/Audio File", label="Input Mode")
510
+ # Input components
511
+ input_file = gr.File(label="Upload Audio/Video", file_types=[f".{ext}" for ext in ALLOWED_FILE_EXTENSIONS], visible=True)
512
+ link_input_info = gr.Markdown("Using yt-dlp to download Youtube Video Links + other platform's ones. Check [all supported sites](https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md)!", visible=False)
513
+ link_input = gr.Textbox(label="Enter Video/Audio Link", visible=False)
514
+
515
+ # Model and options
516
+ model_choice_subtitles = gr.Dropdown(choices=["whisper-large-v3"], value="whisper-large-v3", label="Audio Speech Recogition (ASR) Model")
517
+ transcribe_prompt_subtitles = gr.Textbox(label="Prompt (Optional)", info="Specify any context or spelling corrections.")
518
  with gr.Row():
519
  language_subtitles = gr.Dropdown(choices=[(lang, code) for lang, code in LANGUAGE_CODES.items()], value="en", label="Language")
520
  auto_detect_language_subtitles = gr.Checkbox(label="Auto Detect Language")
521
+
522
+ # Generate button
523
+ transcribe_button_subtitles = gr.Button("Generate Subtitles")
524
+
525
+ # Output and settings
526
  include_video_option = gr.Checkbox(label="Include Video with Subtitles")
527
  gr.Markdown("The SubText Rip (SRT) File, contains the subtitles, you can upload this to any video editing app for adding the subs to your video and also modify/stilyze them")
528
  srt_output = gr.File(label="SRT Output File")
 
542
 
543
  # Event bindings
544
 
545
+ # input mode
546
+ def toggle_input(mode):
547
+ if mode == "Upload Video/Audio File":
548
+ return gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)
549
+ else:
550
+ return gr.update(visible=False), gr.update(visible=True), gr.update(visible=True)
551
+
552
+ input_mode.change(fn=toggle_input, inputs=[input_mode], outputs=[input_file, link_input_info, link_input])
553
+
554
  # show video output
555
  include_video_option.change(lambda include_video: gr.update(visible=include_video), inputs=[include_video_option], outputs=[video_output])
556
  # show video output subs settings checkbox
 
561
  show_subtitle_settings.change(lambda show, include_video: gr.update(visible=show and include_video), inputs=[show_subtitle_settings, include_video_option], outputs=[show_subtitle_settings])
562
  # show custom font file selection
563
  font_selection.change(lambda font_selection: gr.update(visible=font_selection == "Custom Font File"), inputs=[font_selection], outputs=[font_file])
564
+ # Modified generate subtitles event
565
  transcribe_button_subtitles.click(
566
+ fn=generate_subtitles,
567
  inputs=[
568
+ input_mode,
569
+ input_file,
570
+ link_input,
571
  transcribe_prompt_subtitles,
572
  language_subtitles,
573
  auto_detect_language_subtitles,
 
583
  outputs=[srt_output, video_output],
584
  )
585
 
 
586
  interface.launch(share=True)