offiongbassey commited on
Commit
39af064
·
verified ·
1 Parent(s): a37473a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +51 -114
app.py CHANGED
@@ -7,37 +7,29 @@ import ctranslate2
7
  from transformers import (
8
  AutoProcessor,
9
  AutoModelForSpeechSeq2Seq,
10
- AutoTokenizer,
11
- VitsModel,
12
  )
13
 
14
-
15
- ASR_MODEL = "offiongbassey/efik_whisper_asr"
16
- MT_MODEL = "offiongbassey/efik-mt"
17
- CT2_DIR = "./ct2_mt"
18
- TTS_EFIK = "offiongbassey/efik-mms-tts"
19
- TTS_ENG = "facebook/mms-tts-eng"
20
-
21
  device = "cuda" if torch.cuda.is_available() else "cpu"
22
- dtype = torch.float16 if device == "cuda" else torch.float32
23
-
24
 
25
  print("Loading ASR...")
26
  processor = AutoProcessor.from_pretrained(ASR_MODEL)
27
  asr_model = AutoModelForSpeechSeq2Seq.from_pretrained(
28
  ASR_MODEL,
29
  torch_dtype=dtype,
30
- low_cpu_mem_usage=True,
31
  ).to(device)
32
  asr_model.eval()
33
  print("ASR Loaded")
34
 
35
-
36
  print("Loading MT tokenizer...")
37
  mt_tokenizer = AutoTokenizer.from_pretrained(MT_MODEL)
38
  print("MT tokenizer loaded")
39
 
40
-
41
  if not os.path.exists(CT2_DIR):
42
  print("Converting MT model to CTranslate2 format...")
43
  os.system(
@@ -47,26 +39,14 @@ if not os.path.exists(CT2_DIR):
47
  f"--quantization int8"
48
  )
49
  print("Conversion done")
50
-
51
  print("Loading CTranslate2 translator...")
52
- translator = ctranslate2.Translator(CT2_DIR, device=device, compute_type="int8")
 
 
 
 
53
  print("Translator loaded")
54
 
55
-
56
- _tts_cache = {}
57
-
58
- def get_tts(model_id: str):
59
- """Load and cache a VITS/MMS-TTS model + tokenizer."""
60
- if model_id not in _tts_cache:
61
- print(f"Loading TTS model: {model_id} ...")
62
- tok = AutoTokenizer.from_pretrained(model_id)
63
- model = VitsModel.from_pretrained(model_id).to(device)
64
- model.eval()
65
- _tts_cache[model_id] = (tok, model)
66
- print(f"TTS model loaded: {model_id}")
67
- return _tts_cache[model_id]
68
-
69
-
70
  def fix_audio(audio):
71
  sr, wav = audio
72
  if len(wav.shape) > 1:
@@ -79,112 +59,69 @@ def fix_audio(audio):
79
  wav = wav / mx
80
  return wav
81
 
82
-
83
  def transcribe(audio):
84
  if audio is None:
85
  return ""
86
  wav = fix_audio(audio)
87
- inputs = processor(wav, sampling_rate=16000, return_tensors="pt")
 
 
 
 
88
  inputs = {k: v.to(device) for k, v in inputs.items()}
89
  with torch.no_grad():
90
- ids = asr_model.generate(**inputs, max_new_tokens=128, num_beams=1)
91
- return processor.batch_decode(ids, skip_special_tokens=True)[0]
92
-
93
-
94
- def translate(text: str, src_lang: str, tgt_lang: str) -> str:
95
- """
96
- src_lang / tgt_lang are NLLB language codes, e.g. "ibo_Latn", "eng_Latn".
97
- The MT model was trained on Efik; we reuse the same CTranslate2 translator
98
- for both directions.
99
- """
 
 
100
  if not text:
101
  return ""
102
- input_text = f"{src_lang} {text}"
103
- ids = mt_tokenizer.encode(input_text)
 
 
104
  tokens = mt_tokenizer.convert_ids_to_tokens(ids)
 
105
  results = translator.translate_batch(
106
  [tokens],
107
- target_prefix=[[tgt_lang]],
108
- beam_size=4,
109
  )
110
  out = results[0].hypotheses[0]
111
- if out and out[0] == tgt_lang:
 
112
  out = out[1:]
113
  ids = mt_tokenizer.convert_tokens_to_ids(out)
114
  return mt_tokenizer.decode(ids, skip_special_tokens=True)
115
 
116
-
117
- def synthesise(text: str, tts_model_id: str):
118
- """Return (sample_rate, waveform_np) tuple for Gradio Audio output."""
119
- if not text:
120
- return None
121
- tok, model = get_tts(tts_model_id)
122
- inputs = tok(text, return_tensors="pt").to(device)
123
- with torch.no_grad():
124
- output = model(**inputs)
125
- # VitsModel returns waveform in output.waveform shape: (batch, channels, time)
126
- wav = output.waveform[0].squeeze().cpu().float().numpy()
127
- sr = model.config.sampling_rate
128
- return (sr, wav)
129
-
130
-
131
- DIRECTIONS = {
132
- "Efik → English": {
133
- "src_lang" : "ibo_Latn", # token used in the Efik-MT model
134
- "tgt_lang" : "eng_Latn",
135
- "src_label" : "Efik Text",
136
- "tgt_label" : "English Translation",
137
- "tts_model" : TTS_ENG,
138
- },
139
- "English → Efik": {
140
- "src_lang" : "eng_Latn",
141
- "tgt_lang" : "ibo_Latn",
142
- "src_label" : "English Text",
143
- "tgt_label" : "Efik Translation",
144
- "tts_model" : TTS_EFIK,
145
- },
146
- }
147
-
148
-
149
- def pipeline(audio, direction: str):
150
  try:
151
- cfg = DIRECTIONS[direction]
152
- transcribed = transcribe(audio)
153
- translated = translate(transcribed, cfg["src_lang"], cfg["tgt_lang"])
154
- speech = synthesise(translated, cfg["tts_model"])
155
- return transcribed, translated, speech
156
  except Exception as e:
157
- import traceback
158
- traceback.print_exc()
159
- return f"ERROR: {str(e)}", "", None
160
 
161
- with gr.Blocks(title="Efik Speech Translator") as demo:
162
  gr.Markdown("# 🎤 Efik Speech Translator")
163
- gr.Markdown(
164
- "Record or upload audio → transcribe → translate → hear the result.\n\n"
165
- "Use the toggle below to switch translation direction."
166
  )
167
-
168
- direction = gr.Radio(
169
- choices=list(DIRECTIONS.keys()),
170
- value="Efik → English",
171
- label="Translation Direction",
172
- interactive=True,
173
- )
174
-
175
- mic = gr.Audio(sources=["microphone", "upload"], type="numpy", label="Input Audio")
176
-
177
- btn = gr.Button("🚀 Translate", variant="primary")
178
-
179
- with gr.Column():
180
- out_transcribed = gr.Textbox(label="Transcribed Text", interactive=False)
181
- out_translated = gr.Textbox(label="Translated Text", interactive=False)
182
- out_audio = gr.Audio(label="Generated Speech", interactive=False, autoplay=True)
183
-
184
  btn.click(
185
  fn=pipeline,
186
- inputs=[mic, direction],
187
- outputs=[out_transcribed, out_translated, out_audio],
188
  )
189
-
190
  demo.launch()
 
7
  from transformers import (
8
  AutoProcessor,
9
  AutoModelForSpeechSeq2Seq,
10
+ AutoTokenizer
 
11
  )
12
 
13
+ ASR_MODEL = "offiongbassey/efik_whisper_asr"
14
+ MT_MODEL = "offiongbassey/efik-mt"
15
+ CT2_DIR = "./ct2_mt"
 
 
 
 
16
  device = "cuda" if torch.cuda.is_available() else "cpu"
17
+ dtype = torch.float16 if device == "cuda" else torch.float32
 
18
 
19
  print("Loading ASR...")
20
  processor = AutoProcessor.from_pretrained(ASR_MODEL)
21
  asr_model = AutoModelForSpeechSeq2Seq.from_pretrained(
22
  ASR_MODEL,
23
  torch_dtype=dtype,
24
+ low_cpu_mem_usage=True
25
  ).to(device)
26
  asr_model.eval()
27
  print("ASR Loaded")
28
 
 
29
  print("Loading MT tokenizer...")
30
  mt_tokenizer = AutoTokenizer.from_pretrained(MT_MODEL)
31
  print("MT tokenizer loaded")
32
 
 
33
  if not os.path.exists(CT2_DIR):
34
  print("Converting MT model to CTranslate2 format...")
35
  os.system(
 
39
  f"--quantization int8"
40
  )
41
  print("Conversion done")
 
42
  print("Loading CTranslate2 translator...")
43
+ translator = ctranslate2.Translator(
44
+ CT2_DIR,
45
+ device=device,
46
+ compute_type="int8"
47
+ )
48
  print("Translator loaded")
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  def fix_audio(audio):
51
  sr, wav = audio
52
  if len(wav.shape) > 1:
 
59
  wav = wav / mx
60
  return wav
61
 
 
62
  def transcribe(audio):
63
  if audio is None:
64
  return ""
65
  wav = fix_audio(audio)
66
+ inputs = processor(
67
+ wav,
68
+ sampling_rate=16000,
69
+ return_tensors="pt"
70
+ )
71
  inputs = {k: v.to(device) for k, v in inputs.items()}
72
  with torch.no_grad():
73
+ ids = asr_model.generate(
74
+ **inputs,
75
+ max_new_tokens=128,
76
+ num_beams=1
77
+ )
78
+ text = processor.batch_decode(
79
+ ids,
80
+ skip_special_tokens=True
81
+ )[0]
82
+ return text
83
+
84
+ def translate(text):
85
  if not text:
86
  return ""
87
+
88
+ input_text = f"ibo_Latn {text}"
89
+ # Tokenize
90
+ ids = mt_tokenizer.encode(input_text)
91
  tokens = mt_tokenizer.convert_ids_to_tokens(ids)
92
+ # Translate with CTranslate2
93
  results = translator.translate_batch(
94
  [tokens],
95
+ target_prefix=[["eng_Latn"]],
96
+ beam_size=4
97
  )
98
  out = results[0].hypotheses[0]
99
+ # Strip target prefix token if present
100
+ if out[0] == "eng_Latn":
101
  out = out[1:]
102
  ids = mt_tokenizer.convert_tokens_to_ids(out)
103
  return mt_tokenizer.decode(ids, skip_special_tokens=True)
104
 
105
+ def pipeline(audio):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  try:
107
+ efik = transcribe(audio)
108
+ eng = translate(efik)
109
+ return efik, eng
 
 
110
  except Exception as e:
111
+ return f"ERROR: {str(e)}", ""
 
 
112
 
113
+ with gr.Blocks() as demo:
114
  gr.Markdown("# 🎤 Efik Speech Translator")
115
+ mic = gr.Audio(
116
+ sources=["microphone"],
117
+ type="numpy"
118
  )
119
+ btn = gr.Button("Translate")
120
+ out1 = gr.Textbox(label="Efik Text")
121
+ out2 = gr.Textbox(label="English")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  btn.click(
123
  fn=pipeline,
124
+ inputs=mic,
125
+ outputs=[out1, out2]
126
  )
 
127
  demo.launch()