Files changed (1) hide show
  1. app.py +118 -10
app.py CHANGED
@@ -2,8 +2,88 @@ import gradio as gr
2
  from transformers import pipeline
3
  from librosa import resample
4
  import numpy as np
 
 
 
 
 
 
5
 
6
- def transcribe(input_audio):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  sr, speech = input_audio
8
  # Convert to mono if stereo
9
  if speech.ndim > 1:
@@ -12,23 +92,51 @@ def transcribe(input_audio):
12
  if speech.dtype != "float32":
13
  speech = speech.astype(np.float32)
14
  # Resample if sampling rate is not 16kHz
15
- if sr!=16000:
16
  speech = resample(speech, orig_sr=sr, target_sr=16000)
17
- output = pipe(speech, chunk_length_s=30, stride_length_s=5)['text']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  return output
19
 
20
- pipe = pipeline(
21
- "automatic-speech-recognition",
22
- model="GetmanY1/wav2vec2-large-sami-cont-pt-22k-finetuned",
23
- device="cpu"
24
- )
25
 
 
 
 
 
26
  gradio_app = gr.Interface(
27
  fn=transcribe,
28
- inputs=gr.Audio(sources=["upload","microphone"]),
 
 
 
 
 
 
 
29
  outputs="text",
30
  title="Sámi Automatic Speech Recognition",
 
31
  )
32
-
33
  if __name__ == "__main__":
34
  gradio_app.launch(server_name="0.0.0.0", server_port=7860)
 
2
  from transformers import pipeline
3
  from librosa import resample
4
  import numpy as np
5
+ import os
6
+ import sys
7
+ import glob
8
+ import torch
9
+ from huggingface_hub import snapshot_download
10
+ from fairseq_chunking import infer_fairseq_with_chunking
11
 
12
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
13
+ fairseq_cache = {}
14
+
15
+
16
+ def load_dictionary(dict_path):
17
+ """Load the fairseq dictionary file"""
18
+ dictionary = {}
19
+ special_tokens = ['<s>', '<pad>', '</s>', '<unk>']
20
+ for i, token in enumerate(special_tokens):
21
+ dictionary[i] = token
22
+ with open(dict_path, 'r', encoding='utf-8') as f:
23
+ for line in f:
24
+ parts = line.strip().split()
25
+ if len(parts) >= 1:
26
+ token = parts[0]
27
+ dictionary[len(dictionary)] = token
28
+ return dictionary
29
+
30
+
31
+ def decode_predictions(emissions, dictionary, verbose=False):
32
+ predictions = emissions.argmax(dim=-1)
33
+ vocab_size = emissions.shape[-1]
34
+ blank_idx = 0
35
+
36
+ tokens = []
37
+ prev_token_id = None
38
+
39
+ for pred in predictions[0]:
40
+ token_id = pred.item()
41
+ if token_id == blank_idx:
42
+ prev_token_id = None
43
+ continue
44
+ if token_id == prev_token_id or token_id < 4:
45
+ if token_id != prev_token_id and token_id < 4:
46
+ prev_token_id = None
47
+ continue
48
+ token = dictionary.get(token_id, f'<unk_{token_id}>')
49
+ tokens.append(token)
50
+ prev_token_id = token_id
51
+
52
+ transcription = ''.join(tokens).replace('|', ' ').strip()
53
+ return transcription
54
+
55
+
56
+ def load_fairseq_model(model_id):
57
+ """Download the fairseq model repo, import the encoders, and load the checkpoint"""
58
+ if model_id in fairseq_cache:
59
+ return fairseq_cache[model_id]
60
+
61
+ local_path = snapshot_download(model_id)
62
+ if local_path not in sys.path:
63
+ sys.path.insert(0, local_path)
64
+
65
+ original_load = torch.load
66
+ torch.load = lambda *args, **kwargs: original_load(*args, **{**kwargs, "weights_only": False})
67
+ try:
68
+ import fairseq_extra_encoders
69
+ import fairseq
70
+ checkpoint_path = os.path.join(local_path, "fairseq_checkpoint.pt")
71
+ models, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([checkpoint_path])
72
+ finally:
73
+ torch.load = original_load
74
+
75
+ model = models[0]
76
+ model.eval()
77
+ model = model.to(device)
78
+
79
+ dict_path = os.path.join(local_path, "dict.ltr.txt")
80
+ dictionary = load_dictionary(dict_path)
81
+
82
+ fairseq_cache[model_id] = (model, dictionary, cfg.task.normalize)
83
+ return fairseq_cache[model_id]
84
+
85
+
86
+ def transcribe(input_audio, model_id):
87
  sr, speech = input_audio
88
  # Convert to mono if stereo
89
  if speech.ndim > 1:
 
92
  if speech.dtype != "float32":
93
  speech = speech.astype(np.float32)
94
  # Resample if sampling rate is not 16kHz
95
+ if sr != 16000:
96
  speech = resample(speech, orig_sr=sr, target_sr=16000)
97
+ sr = 16000
98
+
99
+ if "ebranch" in model_id:
100
+ model, dictionary, normalize_audio = load_fairseq_model(model_id)
101
+ output = infer_fairseq_with_chunking(
102
+ audio=speech,
103
+ sampling_rate=sr,
104
+ model=model,
105
+ dictionary=dictionary,
106
+ device=device,
107
+ normalize_audio=normalize_audio,
108
+ chunk_length_s=30.0,
109
+ stride_length_s=(5.0, 5.0),
110
+ model_downsample_ratio=320.0,
111
+ decode_fn=lambda emissions, dict: decode_predictions(emissions, dict, verbose=False)
112
+ )
113
+ else:
114
+ pipe = pipeline(
115
+ "automatic-speech-recognition",
116
+ model=model_id,
117
+ device="cpu"
118
+ )
119
+ output = pipe(speech, chunk_length_s=30, stride_length_s=5)['text']
120
  return output
121
 
 
 
 
 
 
122
 
123
+ model_ids_list = [
124
+ "GetmanY1/wav2vec2-large-sami-cont-pt-22k-finetuned",
125
+ "GetmanY1/wav2vec2-large-ebranch-sami-18k-finetuned-experimental"
126
+ ]
127
  gradio_app = gr.Interface(
128
  fn=transcribe,
129
+ inputs=[
130
+ gr.Audio(sources=["upload","microphone"]),
131
+ gr.Dropdown(
132
+ label="Model",
133
+ value="GetmanY1/wav2vec2-large-sami-cont-pt-22k-finetuned",
134
+ choices=model_ids_list
135
+ )
136
+ ],
137
  outputs="text",
138
  title="Sámi Automatic Speech Recognition",
139
+ description ="Choose a model from the list."
140
  )
 
141
  if __name__ == "__main__":
142
  gradio_app.launch(server_name="0.0.0.0", server_port=7860)