shayekh commited on
Commit
55a83fe
Β·
verified Β·
1 Parent(s): 610b224

Add tabs for input, audio input

Browse files
Files changed (1) hide show
  1. app.py +65 -34
app.py CHANGED
@@ -537,7 +537,7 @@ def hash_file(filepath):
537
  return hashlib.md5(f.read(1024*1024)).hexdigest()
538
 
539
  @spaces.GPU(duration=120)
540
- def process_pdf(pdf_file, url_input, yt_url_input, yt_cookies_file, translit_lang, translit_format, target_lang, max_text_char, repetition_penalty_val, last_source_hash, last_korean_words, progress=gr.Progress()):
541
  global tts, voice_style
542
 
543
  # Clean language choices from "Family - Language" to just "Language"
@@ -548,14 +548,20 @@ def process_pdf(pdf_file, url_input, yt_url_input, yt_cookies_file, translit_lan
548
 
549
  os.makedirs("log", exist_ok=True)
550
 
551
- is_url = bool(url_input and url_input.strip())
552
- is_youtube = bool(yt_url_input and yt_url_input.strip() and is_youtube_url(yt_url_input.strip()))
553
- if pdf_file is None and not is_url and not is_youtube:
554
- yield "<p>Please upload a PDF, enter a URL, or provide a YouTube link.</p>", None, None, "", "", [], None
 
 
 
 
555
  return
556
 
557
  if is_youtube:
558
  current_source_hash = hashlib.md5(yt_url_input.strip().encode()).hexdigest()
 
 
559
  elif is_url:
560
  current_source_hash = hashlib.md5(url_input.strip().encode()).hexdigest()
561
  else:
@@ -564,16 +570,6 @@ def process_pdf(pdf_file, url_input, yt_url_input, yt_cookies_file, translit_lan
564
  vocab_list = []
565
  extracted_audio_path = None
566
 
567
- # if last_source_hash == current_source_hash and last_korean_words:
568
- # # Just run text-to-text LLM
569
- # progress(0.2, desc="Translating previously extracted vocabulary...")
570
- # korean_words = [item.get("korean") for item in last_korean_words if item.get("korean")]
571
- # for attempt in range(1, 4):
572
- # vocab_list = translate_vocabulary(korean_words, translit_lang, translit_format, target_lang, repetition_penalty_val)
573
- # if vocab_list:
574
- # break
575
- # else:
576
-
577
  try:
578
  if is_youtube:
579
  progress(0, desc="Downloading YouTube audio (first 5 min)...")
@@ -592,6 +588,18 @@ def process_pdf(pdf_file, url_input, yt_url_input, yt_cookies_file, translit_lan
592
  # Log the transcription
593
  with open("log/debug_yt_transcription.txt", "w", encoding="utf-8") as f:
594
  f.write(f"Title: {yt_title}\n\n{content_text}")
 
 
 
 
 
 
 
 
 
 
 
 
595
  elif is_url:
596
  progress(0, desc="Fetching Website...")
597
  content_text, images = extract_website_content(url_input.strip())
@@ -980,6 +988,16 @@ def get_example_pdf():
980
  print(f"Failed to download example PDF: {e}")
981
  return file_path if os.path.exists(file_path) else None
982
 
 
 
 
 
 
 
 
 
 
 
983
  @spaces.GPU(duration=120)
984
  def process_pdf_force(partial_text, pdf_file, url_input, translit_lang, translit_format, target_lang, max_text_char, repetition_penalty_val, last_source_state, last_korean_words_state):
985
  """Force JSON generation using the current partial stream_box text."""
@@ -1062,6 +1080,7 @@ def process_pdf_force(partial_text, pdf_file, url_input, translit_lang, translit
1062
 
1063
  def create_demo():
1064
  example_pdf = get_example_pdf()
 
1065
 
1066
  custom_theme = gr.themes.Soft(
1067
  primary_hue="violet",
@@ -1168,27 +1187,39 @@ def create_demo():
1168
 
1169
  with gr.Blocks(title="LocalDuo", theme=custom_theme, css=css) as demo:
1170
  gr.Markdown("# πŸ‡°πŸ‡·βœ¨ LocalDuo - Learn Korean from PDFs, Websites & YouTube")
1171
- gr.Markdown("Enter a website URL 🌐, a YouTube link 🎬, or upload a Korean book PDF πŸ“„. The app uses a **Vision-Language Model (VLM)** 🧠 to extract vocabulary from text and images, **ASR** 🎀 to transcribe YouTube audio, and a **Text-to-Speech (TTS)** engine πŸ—£οΈ to generate pronunciation audio.")
 
 
1172
 
1173
  with gr.Row():
1174
  with gr.Column(scale=1):
1175
- # url_input = gr.Textbox(label="Enter a Website URL 🌐", placeholder=r"e.g. https://storykorean.com/stories?level=beginner&story=tiger", value=r"https://storykorean.com/stories?level=beginner&story=tiger")
1176
- # https://www.bbc.com/korean/articles/c5yz89k5dw0o
1177
- # https://www.bbc.com/korean/articles/cn0p7rkvxdgo
1178
- # https://www.koreanstudyjunkie.com/post/korean-reading-exercise-for-all-levels-beginner-intermediate-advanced
1179
- url_input = gr.Textbox(label="Enter a Website URL 🌐",
1180
- placeholder=r"e.g. # https://www.bbc.com/korean/articles/cn0p7rkvxdgo",
1181
- value=r"https://www.bbc.com/korean/articles/cn0p7rkvxdgo")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1182
 
1183
- yt_url_input = gr.Textbox(label="Or Enter a YouTube Link 🎬",
1184
- placeholder=r"e.g. https://www.youtube.com/watch?v=...",
1185
- value="https://www.youtube.com/watch?v=9Nj7l73PBWE",
1186
- info="Audio from the first 5 minutes will be transcribed using Cohere ASR")
1187
- yt_cookies_input = gr.File(label="YouTube Cookies (cookies.txt)", file_types=[".txt"], value=None,
1188
- type="filepath")
1189
- gr.Markdown("*Optional. Helps bypass YouTube bot detection. Install the [cookies.txt](https://addons.mozilla.org/firefox/addon/cookies-txt/) extension, go to youtube.com while logged in, click the extension β†’ 'Current Site' to export.*", elem_classes=["hint-text"])
1190
-
1191
- pdf_input = gr.File(label="Or Upload Book PDF πŸ“š", file_types=[".pdf"], value=example_pdf)
1192
 
1193
  gr.Markdown("### βš™οΈ Customization Settings")
1194
  translit_lang = gr.Dropdown(
@@ -1217,7 +1248,7 @@ def create_demo():
1217
  with gr.Accordion("πŸ“„ Extracted Source Content", open=True):
1218
  extracted_text_box = gr.Textbox(label="Extracted Text", lines=10, max_lines=15, interactive=False)
1219
  extracted_images_gallery = gr.Gallery(label="Extracted Images", columns=4, height="auto", object_fit="contain")
1220
- extracted_audio_player = gr.Audio(label="Extracted Audio (YouTube)", type="filepath", interactive=False)
1221
 
1222
  last_source_state = gr.State(None)
1223
  last_korean_words_state = gr.State(None)
@@ -1229,7 +1260,7 @@ def create_demo():
1229
 
1230
  generate_event = submit_btn.click(
1231
  fn=process_pdf,
1232
- inputs=[pdf_input, url_input, yt_url_input, yt_cookies_input, translit_lang, translit_format, target_lang, max_text_char_input, repetition_penalty_input, last_source_state, last_korean_words_state],
1233
  outputs=[output_html, last_source_state, last_korean_words_state, stream_box, extracted_text_box, extracted_images_gallery, extracted_audio_player]
1234
  )
1235
 
 
537
  return hashlib.md5(f.read(1024*1024)).hexdigest()
538
 
539
  @spaces.GPU(duration=120)
540
+ def process_pdf(pdf_file, url_input, audio_file_input, yt_url_input, yt_cookies_file, translit_lang, translit_format, target_lang, max_text_char, repetition_penalty_val, last_source_hash, last_korean_words, active_tab, progress=gr.Progress()):
541
  global tts, voice_style
542
 
543
  # Clean language choices from "Family - Language" to just "Language"
 
548
 
549
  os.makedirs("log", exist_ok=True)
550
 
551
+ # Determine input source based on active tab
552
+ is_url = (active_tab == "Website URL") and bool(url_input and url_input.strip())
553
+ is_youtube = (active_tab == "YouTube Link") and bool(yt_url_input and yt_url_input.strip() and is_youtube_url(yt_url_input.strip()))
554
+ is_audio_upload = (active_tab == "Upload Audio") and (audio_file_input is not None)
555
+ is_pdf = (active_tab == "Upload PDF") and (pdf_file is not None)
556
+
557
+ if not is_url and not is_youtube and not is_audio_upload and not is_pdf:
558
+ yield "<p>Please provide input in the active tab.</p>", None, None, "", "", [], None
559
  return
560
 
561
  if is_youtube:
562
  current_source_hash = hashlib.md5(yt_url_input.strip().encode()).hexdigest()
563
+ elif is_audio_upload:
564
+ current_source_hash = hash_file(audio_file_input)
565
  elif is_url:
566
  current_source_hash = hashlib.md5(url_input.strip().encode()).hexdigest()
567
  else:
 
570
  vocab_list = []
571
  extracted_audio_path = None
572
 
 
 
 
 
 
 
 
 
 
 
573
  try:
574
  if is_youtube:
575
  progress(0, desc="Downloading YouTube audio (first 5 min)...")
 
588
  # Log the transcription
589
  with open("log/debug_yt_transcription.txt", "w", encoding="utf-8") as f:
590
  f.write(f"Title: {yt_title}\n\n{content_text}")
591
+ elif is_audio_upload:
592
+ progress(0, desc="Transcribing uploaded audio with Cohere ASR...")
593
+ content_text = transcribe_audio_with_asr(audio_file_input)
594
+ images = []
595
+ extracted_audio_path = audio_file_input
596
+
597
+ if not content_text.strip():
598
+ yield "<p>Could not transcribe any text from the uploaded audio.</p>", current_source_hash, None, "", "", [], extracted_audio_path
599
+ return
600
+
601
+ with open("log/debug_audio_transcription.txt", "w", encoding="utf-8") as f:
602
+ f.write(content_text)
603
  elif is_url:
604
  progress(0, desc="Fetching Website...")
605
  content_text, images = extract_website_content(url_input.strip())
 
988
  print(f"Failed to download example PDF: {e}")
989
  return file_path if os.path.exists(file_path) else None
990
 
991
+ def get_example_audio():
992
+ url = "https://raw.githubusercontent.com/ShayekhBinIslam/file-host/main/new_1min.wav"
993
+ file_path = "new_1min.wav"
994
+ if not os.path.exists(file_path):
995
+ try:
996
+ urllib.request.urlretrieve(url, file_path)
997
+ except Exception as e:
998
+ print(f"Failed to download example audio: {e}")
999
+ return file_path if os.path.exists(file_path) else None
1000
+
1001
  @spaces.GPU(duration=120)
1002
  def process_pdf_force(partial_text, pdf_file, url_input, translit_lang, translit_format, target_lang, max_text_char, repetition_penalty_val, last_source_state, last_korean_words_state):
1003
  """Force JSON generation using the current partial stream_box text."""
 
1080
 
1081
  def create_demo():
1082
  example_pdf = get_example_pdf()
1083
+ example_audio = get_example_audio()
1084
 
1085
  custom_theme = gr.themes.Soft(
1086
  primary_hue="violet",
 
1187
 
1188
  with gr.Blocks(title="LocalDuo", theme=custom_theme, css=css) as demo:
1189
  gr.Markdown("# πŸ‡°πŸ‡·βœ¨ LocalDuo - Learn Korean from PDFs, Websites & YouTube")
1190
+ gr.Markdown("Enter a website URL 🌐, upload a PDF πŸ“„, upload an audio file 🎡, or paste a YouTube link 🎬. The app uses a **Vision-Language Model (VLM)** 🧠, **ASR** 🎀, and **TTS** πŸ—£οΈ to generate vocabulary flashcards.")
1191
+
1192
+ active_tab = gr.State("Website URL")
1193
 
1194
  with gr.Row():
1195
  with gr.Column(scale=1):
1196
+ with gr.Tabs() as input_tabs:
1197
+ with gr.Tab("Website URL", id="tab_url") as tab_url:
1198
+ url_input = gr.Textbox(label="Enter a Website URL 🌐",
1199
+ placeholder=r"e.g. https://www.bbc.com/korean/articles/cn0p7rkvxdgo",
1200
+ value=r"https://www.bbc.com/korean/articles/cn0p7rkvxdgo")
1201
+
1202
+ with gr.Tab("Upload PDF", id="tab_pdf") as tab_pdf:
1203
+ pdf_input = gr.File(label="Upload Book PDF πŸ“š", file_types=[".pdf"], value=example_pdf)
1204
+
1205
+ with gr.Tab("Upload Audio", id="tab_audio") as tab_audio:
1206
+ audio_file_input = gr.File(label="Upload Audio File 🎡", file_types=[".wav", ".mp3", ".m4a", ".ogg", ".flac", ".opus", ".webm"], value=example_audio)
1207
+ gr.Markdown("*Upload a Korean audio file. It will be transcribed using Cohere ASR and vocabulary will be extracted from the transcript.*", elem_classes=["hint-text"])
1208
+
1209
+ with gr.Tab("YouTube Link", id="tab_yt") as tab_yt:
1210
+ yt_url_input = gr.Textbox(label="Enter a YouTube Link 🎬",
1211
+ placeholder=r"e.g. https://www.youtube.com/watch?v=...",
1212
+ value="https://www.youtube.com/watch?v=9Nj7l73PBWE",
1213
+ info="Audio from the first 5 minutes will be transcribed using Cohere ASR")
1214
+ yt_cookies_input = gr.File(label="YouTube Cookies (cookies.txt)", file_types=[".txt"], value=None,
1215
+ type="filepath")
1216
+ gr.Markdown("*Optional. Helps bypass YouTube bot detection. Install the [cookies.txt](https://addons.mozilla.org/firefox/addon/cookies-txt/) extension, go to youtube.com while logged in, click the extension β†’ 'Current Site' to export.*", elem_classes=["hint-text"])
1217
 
1218
+ # Track active tab
1219
+ tab_url.select(fn=lambda: "Website URL", inputs=None, outputs=active_tab)
1220
+ tab_pdf.select(fn=lambda: "Upload PDF", inputs=None, outputs=active_tab)
1221
+ tab_audio.select(fn=lambda: "Upload Audio", inputs=None, outputs=active_tab)
1222
+ tab_yt.select(fn=lambda: "YouTube Link", inputs=None, outputs=active_tab)
 
 
 
 
1223
 
1224
  gr.Markdown("### βš™οΈ Customization Settings")
1225
  translit_lang = gr.Dropdown(
 
1248
  with gr.Accordion("πŸ“„ Extracted Source Content", open=True):
1249
  extracted_text_box = gr.Textbox(label="Extracted Text", lines=10, max_lines=15, interactive=False)
1250
  extracted_images_gallery = gr.Gallery(label="Extracted Images", columns=4, height="auto", object_fit="contain")
1251
+ extracted_audio_player = gr.Audio(label="Extracted Audio (YouTube / Uploaded)", type="filepath", interactive=False)
1252
 
1253
  last_source_state = gr.State(None)
1254
  last_korean_words_state = gr.State(None)
 
1260
 
1261
  generate_event = submit_btn.click(
1262
  fn=process_pdf,
1263
+ inputs=[pdf_input, url_input, audio_file_input, yt_url_input, yt_cookies_input, translit_lang, translit_format, target_lang, max_text_char_input, repetition_penalty_input, last_source_state, last_korean_words_state, active_tab],
1264
  outputs=[output_html, last_source_state, last_korean_words_state, stream_box, extracted_text_box, extracted_images_gallery, extracted_audio_player]
1265
  )
1266