shayekh commited on
Commit
dac4f2f
Β·
verified Β·
1 Parent(s): 5e8a8a0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -19
app.py CHANGED
@@ -153,7 +153,7 @@ def extract_youtube_audio(url, max_duration_sec=300, cookiefile=None):
153
 
154
  return wav_path, title
155
 
156
- @spaces.GPU(duration=120)
157
  def transcribe_audio_with_asr(audio_path):
158
  """Transcribe audio file using Cohere ASR model via transformers."""
159
  global asr_model, asr_processor
@@ -168,6 +168,14 @@ def transcribe_audio_with_asr(audio_path):
168
  texts = asr_processor.decode(outputs, skip_special_tokens=True)
169
  # text = texts[0] if isinstance(texts, list) else texts
170
  # join texts
 
 
 
 
 
 
 
 
171
  text = "\n".join(texts) if isinstance(texts, list) else texts
172
 
173
 
@@ -241,7 +249,7 @@ def get_base64_image(image):
241
  img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
242
  return f"data:image/jpeg;base64,{img_str}"
243
 
244
- @spaces.GPU(duration=120)
245
  def extract_vocabulary(pdf_text, images, translit_lang, translit_format, target_lang, max_text_char=1500, repetition_penalty_val=1.1, partial_assistant_text=None, auto_force_chars=1000):
246
  """Use Transformers to extract vocabulary from text and images."""
247
  global model, processor
@@ -249,32 +257,54 @@ def extract_vocabulary(pdf_text, images, translit_lang, translit_format, target_
249
  os.makedirs("log", exist_ok=True)
250
 
251
  if len(pdf_text.strip()) == 0:
252
- pdf_text = '''"No Text available, see provided images only."'''
253
-
 
 
 
254
 
255
  non_english = ""
256
  if translit_lang.upper() != "ENGLISH":
257
  non_english = f" CRITICAL: You MUST use the native alphabet/script of {translit_lang.upper()}, do NOT use English letters unless requested."
258
 
259
- prompt_text = f"""Extract at least 10 key Korean words or phrases from the following text and images.
 
 
 
 
 
 
260
  Focus on meaningful vocabulary that is highly helpful for a new language learner (e.g., common nouns, verbs, adjectives, or useful expressions).
261
  CRITICAL: Do NOT extract website template words, navigation menus, boilerplate text, UI elements, or titles like 'Home page', 'News', 'Menu'.
262
 
263
  Return ONLY a valid JSON list of dictionaries, where each dictionary has four keys:
264
  - 'korean' (the Korean text)
265
  - 'transliteration' (the pronunciation transliterated into {translit_lang.upper()} script/characters, formatted as {translit_format}.{non_english})
266
- - 'translation' (the translation into {target_lang.upper()})
267
  - 'explanation' (a brief grammar or context note in {target_lang.upper()}).
268
 
269
- Just output raw JSON with ```json and ``` markers, as the user will load in python.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
 
271
  CRITICAL: Do NOT overthink. Do NOT deliberate over conditions, edge cases, or reasoning. Keep your thinking extremely brief (a few words at most). Output the JSON array IMMEDIATELY without lengthy analysis.
272
 
273
- Text:
274
 
275
- <scrpated-content>
276
- {pdf_text[:int(max_text_char)]}
277
- </scrpated-content>
278
  """
279
 
280
  # DEBUG: Log prompt text
@@ -375,7 +405,7 @@ Text:
375
  # Check if user clicked "Stop thinking" OR auto-force threshold reached
376
  if (global_stop_thinking[0] or should_auto_force) and not force_triggered:
377
  force_triggered = True
378
- reason = "auto-force (>300 chars)" if should_auto_force else "user clicked stop"
379
  print(f"[STOP-THINK] Force triggered ({reason})! Killing current generation...")
380
 
381
  # 1. Kill the current generation thread
@@ -482,8 +512,13 @@ Text:
482
  # Fallback: find last [ ... ] or { ... } block
483
  json_matches = list(re.finditer(r'(\[[\s\S]*\]|\{[\s\S]*\})', output_text))
484
  clean_text = json_matches[-1].group(1).strip() if json_matches else output_text.strip()
485
-
486
- data = json.loads(clean_text)
 
 
 
 
 
487
  if not isinstance(data, list):
488
  data = [data]
489
  yield output_text, data
@@ -568,7 +603,12 @@ Korean words:
568
  json_matches = list(re.finditer(r'(\[[\s\S]*\]|\{[\s\S]*\})', output_text))
569
  clean_text = json_matches[-1].group(1).strip() if json_matches else output_text.strip()
570
 
571
- data = json.loads(clean_text)
 
 
 
 
 
572
  if not isinstance(data, list):
573
  data = [data]
574
  return data
@@ -590,7 +630,7 @@ def hash_file(filepath):
590
  with open(filepath, 'rb') as f:
591
  return hashlib.md5(f.read(1024*1024)).hexdigest()
592
 
593
- @spaces.GPU(duration=120)
594
  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, auto_force_chars_val, last_source_hash, last_korean_words, active_tab, progress=gr.Progress()):
595
  global tts, voice_style
596
 
@@ -705,7 +745,11 @@ def process_pdf(pdf_file, url_input, audio_file_input, yt_url_input, yt_cookies_
705
  clean_text = json_matches[-1].group(1).strip() if json_matches else ""
706
 
707
  if clean_text:
708
- data = json.loads(clean_text)
 
 
 
 
709
  if not isinstance(data, list):
710
  data = [data]
711
  if data and isinstance(data[0], dict) and 'korean' in data[0]:
@@ -1083,7 +1127,7 @@ def get_example_audio():
1083
  print(f"Failed to download example audio: {e}")
1084
  return file_path if os.path.exists(file_path) else None
1085
 
1086
- @spaces.GPU(duration=120)
1087
  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):
1088
  """Force JSON generation using the current partial stream_box text."""
1089
  is_url = bool(url_input and url_input.strip())
@@ -1309,7 +1353,7 @@ def create_demo():
1309
  gr.Markdown("### βš™οΈ Customization Settings")
1310
  max_text_char_input = gr.Slider(minimum=1000, maximum=30000, step=1000, value=1500, label="Max Input Text Length (Characters)")
1311
  repetition_penalty_input = gr.Slider(minimum=0.1, maximum=2.0, step=0.1, value=1.2, label="Repetition Penalty")
1312
- auto_force_chars_input = gr.Slider(minimum=100, maximum=5000, step=100, value=1000, label="Auto-force JSON after (chars of thinking)")
1313
 
1314
  with gr.Accordion("πŸ”§ Advanced", open=False):
1315
  translit_lang = gr.Dropdown(
 
153
 
154
  return wav_path, title
155
 
156
+ @spaces.GPU(duration=180)
157
  def transcribe_audio_with_asr(audio_path):
158
  """Transcribe audio file using Cohere ASR model via transformers."""
159
  global asr_model, asr_processor
 
168
  texts = asr_processor.decode(outputs, skip_special_tokens=True)
169
  # text = texts[0] if isinstance(texts, list) else texts
170
  # join texts
171
+ # Filter the lines in texts which are english only and no korean
172
+ if isinstance(texts, list):
173
+ # Filter out lines that are purely English/symbols (no Korean characters)
174
+ # Korean Unicode range: AC00-D7A3 (Syllables), 1100-11FF (Jamo), 3130-318F (Compatibility Jamo)
175
+ korean_re = re_module.compile(r'[κ°€-νž£γ„±-γ…Žγ…-γ…£]')
176
+ texts = [line for line in texts if korean_re.search(line)]
177
+
178
+
179
  text = "\n".join(texts) if isinstance(texts, list) else texts
180
 
181
 
 
249
  img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
250
  return f"data:image/jpeg;base64,{img_str}"
251
 
252
+ @spaces.GPU(duration=180)
253
  def extract_vocabulary(pdf_text, images, translit_lang, translit_format, target_lang, max_text_char=1500, repetition_penalty_val=1.1, partial_assistant_text=None, auto_force_chars=1000):
254
  """Use Transformers to extract vocabulary from text and images."""
255
  global model, processor
 
257
  os.makedirs("log", exist_ok=True)
258
 
259
  if len(pdf_text.strip()) == 0:
260
+ pdf_text = '''"No Text available, see provided Images only."'''
261
+
262
+ no_img = ""
263
+ if len(images) == 0:
264
+ no_img = '''\n"No Images available, see provided Text only."'''
265
 
266
  non_english = ""
267
  if translit_lang.upper() != "ENGLISH":
268
  non_english = f" CRITICAL: You MUST use the native alphabet/script of {translit_lang.upper()}, do NOT use English letters unless requested."
269
 
270
+ prompt_text = f"""Text:
271
+
272
+ <scrpated-content>
273
+ {pdf_text[:int(max_text_char)]}
274
+ </scrpated-content>{no_img}
275
+
276
+ Extract at least 10 key Korean words or phrases from the following text and images.
277
  Focus on meaningful vocabulary that is highly helpful for a new language learner (e.g., common nouns, verbs, adjectives, or useful expressions).
278
  CRITICAL: Do NOT extract website template words, navigation menus, boilerplate text, UI elements, or titles like 'Home page', 'News', 'Menu'.
279
 
280
  Return ONLY a valid JSON list of dictionaries, where each dictionary has four keys:
281
  - 'korean' (the Korean text)
282
  - 'transliteration' (the pronunciation transliterated into {translit_lang.upper()} script/characters, formatted as {translit_format}.{non_english})
283
+ - 'translation' (the brief translation into {target_lang.upper()})
284
  - 'explanation' (a brief grammar or context note in {target_lang.upper()}).
285
 
286
+ Just output raw JSON with ```json and ``` markers, as the user will load in python. Example:
287
+
288
+ ```json
289
+ [
290
+ {{
291
+ "korean": "날씨",
292
+ "transliteration": "nal-ssi",
293
+ "translation": "weather",
294
+ "explanation": "Common noun used to describe weather conditions."
295
+ }},
296
+ {{
297
+ "korean": "λ§›μžˆλ‹€",
298
+ "transliteration": "ma-sit-da",
299
+ "translation": "to be delicious",
300
+ "explanation": "Descriptive verb. Polite form: λ§›μžˆμ–΄μš”. Used to compliment food."
301
+ }}
302
+ ]
303
+ ```
304
 
305
  CRITICAL: Do NOT overthink. Do NOT deliberate over conditions, edge cases, or reasoning. Keep your thinking extremely brief (a few words at most). Output the JSON array IMMEDIATELY without lengthy analysis.
306
 
 
307
 
 
 
 
308
  """
309
 
310
  # DEBUG: Log prompt text
 
405
  # Check if user clicked "Stop thinking" OR auto-force threshold reached
406
  if (global_stop_thinking[0] or should_auto_force) and not force_triggered:
407
  force_triggered = True
408
+ reason = f"auto-force (>{AUTO_FORCE_CHARS} chars)" if should_auto_force else "user clicked stop"
409
  print(f"[STOP-THINK] Force triggered ({reason})! Killing current generation...")
410
 
411
  # 1. Kill the current generation thread
 
512
  # Fallback: find last [ ... ] or { ... } block
513
  json_matches = list(re.finditer(r'(\[[\s\S]*\]|\{[\s\S]*\})', output_text))
514
  clean_text = json_matches[-1].group(1).strip() if json_matches else output_text.strip()
515
+ try:
516
+ data = json.loads(clean_text)
517
+ except:
518
+ import jiter
519
+ # Get bytes from string
520
+ data = jiter.from_json(clean_text.encode("utf-8"), partial_mode=True)
521
+
522
  if not isinstance(data, list):
523
  data = [data]
524
  yield output_text, data
 
603
  json_matches = list(re.finditer(r'(\[[\s\S]*\]|\{[\s\S]*\})', output_text))
604
  clean_text = json_matches[-1].group(1).strip() if json_matches else output_text.strip()
605
 
606
+ try:
607
+ data = json.loads(clean_text)
608
+ except:
609
+ import jiter
610
+ data = jiter.from_json(clean_text.encode("utf-8"), partial_mode=True)
611
+
612
  if not isinstance(data, list):
613
  data = [data]
614
  return data
 
630
  with open(filepath, 'rb') as f:
631
  return hashlib.md5(f.read(1024*1024)).hexdigest()
632
 
633
+ @spaces.GPU(duration=180)
634
  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, auto_force_chars_val, last_source_hash, last_korean_words, active_tab, progress=gr.Progress()):
635
  global tts, voice_style
636
 
 
745
  clean_text = json_matches[-1].group(1).strip() if json_matches else ""
746
 
747
  if clean_text:
748
+ try:
749
+ data = json.loads(clean_text)
750
+ except:
751
+ import jiter
752
+ data = jiter.from_json(clean_text.encode("utf-8"), partial_mode=True)
753
  if not isinstance(data, list):
754
  data = [data]
755
  if data and isinstance(data[0], dict) and 'korean' in data[0]:
 
1127
  print(f"Failed to download example audio: {e}")
1128
  return file_path if os.path.exists(file_path) else None
1129
 
1130
+ @spaces.GPU(duration=180)
1131
  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):
1132
  """Force JSON generation using the current partial stream_box text."""
1133
  is_url = bool(url_input and url_input.strip())
 
1353
  gr.Markdown("### βš™οΈ Customization Settings")
1354
  max_text_char_input = gr.Slider(minimum=1000, maximum=30000, step=1000, value=1500, label="Max Input Text Length (Characters)")
1355
  repetition_penalty_input = gr.Slider(minimum=0.1, maximum=2.0, step=0.1, value=1.2, label="Repetition Penalty")
1356
+ auto_force_chars_input = gr.Slider(minimum=1_000, maximum=10_000, step=100, value=4_000, label="Auto-force JSON after (chars of thinking)")
1357
 
1358
  with gr.Accordion("πŸ”§ Advanced", open=False):
1359
  translit_lang = gr.Dropdown(