shayekh commited on
Commit
727b491
·
verified ·
1 Parent(s): b0055d7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -44
app.py CHANGED
@@ -1,5 +1,17 @@
1
  # Copyright: Shayekh Bin Islam. KAIST, South Korea. 2026.
2
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  import gradio as gr
4
  import fitz # PyMuPDF
5
  from PIL import Image
@@ -8,13 +20,12 @@ import json
8
  import base64
9
  import soundfile as sf
10
  import torch
11
- import spaces
12
 
13
  from supertonic import TTS
14
- from vllm import LLM, SamplingParams
15
 
16
- llm = None
17
- sampling_params = None
18
  tts = None
19
  voice_style = None
20
 
@@ -41,18 +52,26 @@ def get_base64_image(image):
41
 
42
  @spaces.GPU
43
  def extract_vocabulary(pdf_text, images, translit_lang, translit_format, target_lang):
44
- """Use vLLM to extract vocabulary from text and images."""
45
- global llm, sampling_params
46
 
47
  os.makedirs("log", exist_ok=True)
48
 
 
 
 
 
 
 
 
 
49
  prompt_text = f"""Extract 3 to 5 key Korean words or phrases from the following text and images.
50
  Return ONLY a valid JSON list of dictionaries, where each dictionary has four keys:
51
  - 'korean' (the Korean text)
52
- - 'transliteration' (the pronunciation transliterated into {translit_lang.upper()} script/characters, formatted as {translit_format}. CRITICAL: You MUST use the native alphabet/script of {translit_lang.upper()}, do NOT use English letters unless requested.)
53
  - 'translation' (the translation into {target_lang.upper()})
54
  - 'explanation' (a brief grammar or context note in {target_lang.upper()}).
55
- No markdown formatting, just raw JSON.
56
 
57
  Text:
58
  {pdf_text[:1500]}
@@ -62,16 +81,19 @@ Text:
62
  with open("log/debug_vlm_prompt.txt", "w", encoding="utf-8") as f:
63
  f.write(prompt_text)
64
 
65
- content = [{"type": "text", "text": prompt_text}]
 
66
 
67
  for i, img in enumerate(images):
68
  # DEBUG: Log images
69
  img.save(f"log/debug_image_{i}.png", format="PNG")
 
70
 
71
  content.append({
72
- "type": "image_url",
73
- "image_url": {"url": get_base64_image(img)}
74
  })
 
 
75
 
76
  messages = [
77
  {
@@ -81,26 +103,46 @@ Text:
81
  ]
82
 
83
  try:
84
- outputs = llm.chat(messages=messages, sampling_params=sampling_params)
85
- output_text = outputs[0].outputs[0].text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
  # DEBUG: Log raw output text
88
  with open("log/debug_vlm_output.txt", "w", encoding="utf-8") as f:
89
  f.write(output_text)
90
 
91
  except Exception as e:
92
- print(f"Error during vLLM inference: {e}")
93
  return []
94
 
95
  try:
96
- clean_text = output_text.strip()
97
- if clean_text.startswith("```json"):
98
- clean_text = clean_text[7:]
99
- if clean_text.startswith("```"):
100
- clean_text = clean_text[3:]
101
- if clean_text.endswith("```"):
102
- clean_text = clean_text[:-3]
103
- clean_text = clean_text.strip()
 
104
 
105
  data = json.loads(clean_text)
106
  if not isinstance(data, list):
@@ -458,26 +500,27 @@ def create_demo():
458
 
459
  @spaces.GPU
460
  def main():
461
- print("Loading Qwen3.5-2B model via vLLM...")
462
- llm = LLM(
463
- model="Qwen/Qwen3.5-2B",
464
- # model="Qwen/Qwen3.5-9B",
465
- max_model_len=65536, # Reduced from 262144 to fit on single GPU
466
- tensor_parallel_size=1, # Kept at 1 since CUDA_VISIBLE_DEVICES=1
467
- gpu_memory_utilization=0.5,
468
- enable_prefix_caching=True,
469
- trust_remote_code=True,
470
- limit_mm_per_prompt={"image": 10} # Added image limits
471
- )
472
-
473
- sampling_params = SamplingParams(
474
- temperature=1.0,
475
- top_p=0.95,
476
- top_k=20,
477
- min_p=0.0,
478
- presence_penalty=0.0,
479
- repetition_penalty=1.0,
480
- max_tokens=2048,
 
481
  )
482
 
483
  print("Loading Supertonic TTS...")
@@ -488,8 +531,8 @@ def main():
488
  voice_style = tts.get_voice_style(tts.voice_style_names[0])
489
 
490
  demo = create_demo()
491
- demo.launch(server_name="0.0.0.0", server_port=7861)
492
-
493
 
494
  if __name__ == "__main__":
495
  main()
 
1
  # Copyright: Shayekh Bin Islam. KAIST, South Korea. 2026.
2
 
3
+ try:
4
+ import spaces
5
+ except ImportError:
6
+ class spaces:
7
+ @staticmethod
8
+ def GPU(*args, **kwargs):
9
+ def decorator(func):
10
+ return func
11
+ if len(args) == 1 and callable(args[0]) and not kwargs:
12
+ return args[0]
13
+ return decorator
14
+
15
  import gradio as gr
16
  import fitz # PyMuPDF
17
  from PIL import Image
 
20
  import base64
21
  import soundfile as sf
22
  import torch
 
23
 
24
  from supertonic import TTS
25
+ from transformers import AutoProcessor, AutoModelForImageTextToText
26
 
27
+ model = None
28
+ processor = None
29
  tts = None
30
  voice_style = None
31
 
 
52
 
53
  @spaces.GPU
54
  def extract_vocabulary(pdf_text, images, translit_lang, translit_format, target_lang):
55
+ """Use Transformers to extract vocabulary from text and images."""
56
+ global model, processor
57
 
58
  os.makedirs("log", exist_ok=True)
59
 
60
+ if pdf_text.strip() == "":
61
+ pdf_text = '''"No Text available, see provided images only."'''
62
+
63
+
64
+ non_english = ""
65
+ if translit_lang.upper() != "ENGLISH":
66
+ non_english = f" CRITICAL: You MUST use the native alphabet/script of {translit_lang.upper()}, do NOT use English letters unless requested."
67
+
68
  prompt_text = f"""Extract 3 to 5 key Korean words or phrases from the following text and images.
69
  Return ONLY a valid JSON list of dictionaries, where each dictionary has four keys:
70
  - 'korean' (the Korean text)
71
+ - 'transliteration' (the pronunciation transliterated into {translit_lang.upper()} script/characters, formatted as {translit_format}.{non_english})
72
  - 'translation' (the translation into {target_lang.upper()})
73
  - 'explanation' (a brief grammar or context note in {target_lang.upper()}).
74
+ No markdown formatting, just raw JSON with ```json and ``` markers.
75
 
76
  Text:
77
  {pdf_text[:1500]}
 
81
  with open("log/debug_vlm_prompt.txt", "w", encoding="utf-8") as f:
82
  f.write(prompt_text)
83
 
84
+ content = []
85
+ pil_images = []
86
 
87
  for i, img in enumerate(images):
88
  # DEBUG: Log images
89
  img.save(f"log/debug_image_{i}.png", format="PNG")
90
+ pil_images.append(img)
91
 
92
  content.append({
93
+ "type": "image",
 
94
  })
95
+
96
+ content += [{"type": "text", "text": prompt_text}]
97
 
98
  messages = [
99
  {
 
103
  ]
104
 
105
  try:
106
+ model.to("cuda")
107
+ text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
108
+ inputs = processor(
109
+ text=[text],
110
+ images=pil_images if pil_images else None,
111
+ return_tensors="pt",
112
+ padding=True
113
+ ).to("cuda")
114
+
115
+ generated_ids = model.generate(
116
+ **inputs,
117
+ max_new_tokens=2048*4,
118
+ temperature=1.0,
119
+ top_p=0.95,
120
+ do_sample=True
121
+ )
122
+
123
+ generated_ids = [
124
+ output_ids[len(input_ids):] for input_ids, output_ids in zip(inputs.input_ids, generated_ids)
125
+ ]
126
+ output_text = processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
127
 
128
  # DEBUG: Log raw output text
129
  with open("log/debug_vlm_output.txt", "w", encoding="utf-8") as f:
130
  f.write(output_text)
131
 
132
  except Exception as e:
133
+ print(f"Error during Transformers inference: {e}")
134
  return []
135
 
136
  try:
137
+ import re
138
+ # Extract JSON from markdown code fences or raw output
139
+ json_match = re.search(r'```(?:json)?\s*([\s\S]*?)```', output_text)
140
+ if json_match:
141
+ clean_text = json_match.group(1).strip()
142
+ else:
143
+ # Fallback: find first [ ... ] or { ... } block
144
+ json_match = re.search(r'(\[[\s\S]*\]|\{[\s\S]*\})', output_text)
145
+ clean_text = json_match.group(1).strip() if json_match else output_text.strip()
146
 
147
  data = json.loads(clean_text)
148
  if not isinstance(data, list):
 
500
 
501
  @spaces.GPU
502
  def main():
503
+ global model, processor, tts, voice_style
504
+
505
+
506
+ # model_id = "Qwen/Qwen3.5-9B"
507
+ model_id = "Qwen/Qwen3.5-2B"
508
+
509
+ print(f"Loading {model_id} model via Transformers...")
510
+
511
+ processor = AutoProcessor.from_pretrained(model_id, trust_remote_code=True)
512
+
513
+ try:
514
+ with open("chat_template.jinja", "r", encoding="utf-8") as f:
515
+ processor.chat_template = f.read()
516
+ except Exception as e:
517
+ print("Could not load custom chat template:", e)
518
+
519
+ model = AutoModelForImageTextToText.from_pretrained(
520
+ model_id,
521
+ torch_dtype=torch.bfloat16,
522
+ device_map="cpu",
523
+ trust_remote_code=True
524
  )
525
 
526
  print("Loading Supertonic TTS...")
 
531
  voice_style = tts.get_voice_style(tts.voice_style_names[0])
532
 
533
  demo = create_demo()
534
+ demo.launch(server_name="0.0.0.0", server_port=7865)
535
+
536
 
537
  if __name__ == "__main__":
538
  main()