File size: 9,134 Bytes
9e1fe39
51a3039
 
 
 
 
 
 
 
 
e2f3dc3
51a3039
 
 
 
 
 
 
 
3f7bb48
51a3039
 
 
 
 
 
e2f3dc3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51a3039
9de793a
e2f3dc3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b1cd91
e2f3dc3
39fbfd3
e2f3dc3
 
39fbfd3
 
e2f3dc3
 
cf075ed
 
 
 
e2f3dc3
cf075ed
e2f3dc3
cf075ed
b9fb0d0
cf075ed
 
 
e2f3dc3
cf075ed
 
 
 
 
 
 
e2f3dc3
 
51a3039
e2f3dc3
51a3039
e2f3dc3
 
 
51a3039
e2f3dc3
51a3039
 
 
 
e2f3dc3
 
 
 
 
51a3039
 
 
 
 
 
e2f3dc3
51a3039
e2f3dc3
51a3039
 
 
 
 
 
e2f3dc3
 
 
 
eb43650
cf075ed
eb43650
51a3039
e2f3dc3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51a3039
b8cc811
f5f3ec4
 
e2f3dc3
 
51a3039
 
 
 
e2f3dc3
 
 
 
 
 
 
 
 
51a3039
 
 
 
 
e2f3dc3
51a3039
 
 
 
 
 
 
 
 
 
e2f3dc3
 
51a3039
e2f3dc3
51a3039
e2f3dc3
51a3039
e2f3dc3
 
51a3039
e2f3dc3
 
 
 
 
51a3039
 
 
e2f3dc3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
import spaces
import os
import gc
from functools import partial
import gradio as gr
import torch
from speechbrain.inference.interfaces import Pretrained, foreign_class
from transformers import T5Tokenizer, T5ForConditionalGeneration
import librosa
import whisper_timestamped as whisper
from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor, pipeline, Wav2Vec2ForCTC, AutoProcessor

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
torch.backends.cuda.matmul.allow_tf32 = True

def clean_up_memory():
    gc.collect()
    torch.cuda.empty_cache()

@spaces.GPU(duration=15)
def recap_sentence(string):
    inputs = recap_tokenizer(["restore capitalization and punctuation: " + string], return_tensors="pt", padding=True).to(device)
    outputs = recap_model.generate(**inputs, max_length=768, num_beams=5, early_stopping=True).squeeze(0)
    recap_result = recap_tokenizer.decode(outputs, skip_special_tokens=True)
    return recap_result

@spaces.GPU(duration=30)
def return_prediction_w2v2(mic=None, file=None, device=device):
    if mic is not None:
        waveform, sr = librosa.load(mic, sr=16000)
        waveform = waveform[:60*sr]
        w2v2_result = w2v2_classifier.classify_file_w2v2(waveform, device)
    elif file is not None:
        waveform, sr = librosa.load(file, sr=16000)
        waveform = waveform[:60*sr]
        w2v2_result = w2v2_classifier.classify_file_w2v2(waveform, device)
    else:
        return "You must either provide a mic recording or a file"

    recap_result = recap_sentence(w2v2_result[0])

    for i, letter in enumerate(recap_result):
        if i > 1 and recap_result[i-2] in [".", "!", "?"] and letter.islower():
            recap_result = recap_result[:i] + letter.upper() + recap_result[i+1:]

    clean_up_memory()
    return recap_result

@spaces.GPU(duration=30)
def return_prediction_whisper_mic(mic=None, device=device):
    if mic is not None:
        waveform, sr = librosa.load(mic, sr=16000)
        waveform = waveform[:30*sr]
        whisper_result = whisper_classifier.classify_file_whisper_mkd(waveform, device)
    else:
        return "You must provide a mic recording"
    
    recap_result = recap_sentence(whisper_result[0])

    for i, letter in enumerate(recap_result):
        if i > 1 and recap_result[i-2] in [".", "!", "?"] and letter.islower():
            recap_result = recap_result[:i] + letter.upper() + recap_result[i+1:]

    clean_up_memory()
    return recap_result

@spaces.GPU(duration=60)
def return_prediction_whisper_file(file=None, device=device):
    whisper_result = []
    if file is not None:
        waveform, sr = librosa.load(file, sr=16000)
        waveform = waveform[:3600*sr]
        whisper_result = whisper_classifier.classify_file_whisper_mkd_streaming(waveform, device)
    else:
        yield "You must provide a file"
    
    recap_result = ""
    prev_segment = ""
    prev_segment_len = 0

    segment_counter = 0
    for segment in whisper_result:
        segment_counter += 1
        if prev_segment == "":
            recap_segment = recap_sentence(segment[0])
        else:
            prev_segment_len = len(prev_segment.split())
            recap_segment = recap_sentence(prev_segment + " " + segment[0])
        
        recap_segment = recap_segment.split()
        recap_segment = recap_segment[prev_segment_len:]
        recap_segment = " ".join(recap_segment)
        prev_segment = segment[0]
        recap_result += recap_segment + " "

        for i, letter in enumerate(recap_result):
            if i > 1 and recap_result[i-2] in [".", "!", "?"] and letter.islower():
                recap_result = recap_result[:i] + letter.upper() + recap_result[i+1:]

        yield recap_result

return_prediction_whisper_mic_with_device = partial(return_prediction_whisper_mic, device=device)
return_prediction_whisper_file_with_device = partial(return_prediction_whisper_file, device=device)
return_prediction_w2v2_with_device = partial(return_prediction_w2v2, device=device)

# Load the ASR models
whisper_classifier = foreign_class(source="Macedonian-ASR/whisper-large-v3-macedonian-asr", pymodule_file="custom_interface_app.py", classname="ASR")
whisper_classifier = whisper_classifier.to(device)
whisper_classifier.eval()

w2v2_classifier = foreign_class(source="Macedonian-ASR/wav2vec2-aed-macedonian-asr", pymodule_file="custom_interface_app.py", classname="ASR")
w2v2_classifier = w2v2_classifier.to(device)
w2v2_classifier.eval()

# Load the T5 tokenizer and model
recap_model_name = "Macedonian-ASR/mt5-restore-capitalization-macedonian"
recap_tokenizer = T5Tokenizer.from_pretrained(recap_model_name)
recap_model = T5ForConditionalGeneration.from_pretrained(recap_model_name, torch_dtype=torch.float16)
recap_model.to(device)
recap_model.eval()

# Interface definitions
mic_transcribe_whisper = gr.Interface(
    fn=return_prediction_whisper_mic_with_device,
    inputs=gr.Audio(sources="microphone", type="filepath"),
    outputs=gr.Textbox(),
    allow_flagging="never",
    live=False,
)

file_transcribe_whisper = gr.Interface(
    fn=return_prediction_whisper_file_with_device,
    inputs=gr.Audio(sources="upload", type="filepath"),
    outputs=gr.Textbox(),
    allow_flagging="never",
    live=True
)

mic_transcribe_w2v2 = gr.Interface(
    fn=return_prediction_w2v2_with_device,
    inputs=gr.Audio(sources="microphone", type="filepath"),
    outputs=gr.Textbox(),
    allow_flagging="never",
    live=False,
)

file_transcribe_w2v2 = gr.Interface(
    fn=return_prediction_w2v2_with_device,
    inputs=gr.Audio(sources="upload", type="filepath"),
    outputs=gr.Textbox(),
    allow_flagging="never",
    live=False
)

project_description = '''
<img src="https://i.ibb.co/SKDfwn9/bookie.png"
     alt="Bookie logo"
     style="float: right; width: 130px; height: 110px; margin-left: 10px;" />
     
## Автори:
1. **Дејан Порјазовски**
2. **Илина Јакимовска**
3. **Ордан Чукалиев**
4. **Никола Стиков**
Оваа колаборација е дел од активностите на **Центарот за напредни интердисциплинарни истражувања ([ЦеНИИс](https://ukim.edu.mk/en/centri/centar-za-napredni-interdisciplinarni-istrazhuvanja-ceniis))** при УКИМ.
## Во тренирањето на овој модел се употребени податоци од:
1. Дигитален архив за етнолошки и антрополошки ресурси ([ДАЕАР](https://iea.pmf.ukim.edu.mk/tabs/view/61f236ed7d95176b747c20566ddbda1a)) при Институтот за етнологија и антропологија, Природно-математички факултет при УКИМ.
2. Аудио верзија на меѓународното списание [„ЕтноАнтропоЗум"](https://etno.pmf.ukim.mk/index.php/eaz/issue/archive) на Институтот за етнологија и антропологија, Природно-математички факултет при УКИМ.
3. Аудио подкастот [„Обични луѓе"](https://obicniluge.mk/episodes/) на Илина Јакимовска
4. Научните видеа од серијалот [„Наука за деца"](http://naukazadeca.mk), фондација [КАНТАРОТ](https://qantarot.substack.com/)
5. Македонска верзија на [Mozilla Common Voice](https://commonvoice.mozilla.org/en/datasets) (верзија 18.0)
## Како да придонесете за подобрување на македонските модели за препознавање на говор?
На  следниот [линк](https://drive.google.com/file/d/1YdZJz9o1X8AMc6J4MNPnVZjASyIXnvoZ/view?usp=sharing) ќе најдете инструкции за тоа како да донирате македонски говор преку платформата Mozilla Common Voice.
'''

# Custom CSS
css = """
.gradio-container {
    background-color: #f0f0f0;
}
.custom-markdown p, .custom-markdown li, .custom-markdown h2, .custom-markdown a {
    font-size: 15px !important;
    font-family: Arial, sans-serif !important;
}
.gradio-container {
    background-color: #f3f3f3 !important;
}
"""

transcriber_app = gr.Blocks(css=css, delete_cache=(60, 120))
    
with transcriber_app:
    state = gr.State()
    gr.Markdown(project_description, elem_classes="custom-markdown")

    gr.TabbedInterface(
        [mic_transcribe_whisper, file_transcribe_whisper, mic_transcribe_w2v2, file_transcribe_w2v2],
        ["Буки-Whisper микрофон", "Буки-Whisper датотека", "Буки-Wav2vec2 микрофон", "Буки-Wav2vec2 датотека"],
    )
    state = gr.State(value=[], delete_callback=lambda v: print("STATE DELETED"))

    transcriber_app.unload(return_prediction_whisper_mic)
    transcriber_app.unload(return_prediction_whisper_file)
    transcriber_app.unload(return_prediction_w2v2)

if __name__ == "__main__":
    transcriber_app.queue()
    transcriber_app.launch(share=True)