Spaces:
Sleeping
Sleeping
File size: 9,243 Bytes
d5a7304 40e6055 d5a7304 dab09e6 d5a7304 bf4454f d5a7304 bc54321 a5c9298 bc54321 a5c9298 bc54321 a5c9298 bc54321 d5a7304 0e2929c d5a7304 a694d9e d5a7304 a694d9e d5a7304 a694d9e d5a7304 e94a807 d5a7304 910aade d5a7304 945f327 d5a7304 bc54321 d5a7304 |
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 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
import gradio as gr
from transformers import pipeline, Wav2Vec2ProcessorWithLM, Wav2Vec2ForCTC
import os
import soundfile as sf
import torch
import numpy as np
HF_TOKEN = os.environ.get("HF_TOKEN")
model_name = "bond005/wav2vec2-large-ru-golos-with-lm"
processor = Wav2Vec2ProcessorWithLM.from_pretrained(model_name)
model = Wav2Vec2ForCTC.from_pretrained(model_name)
pipe = pipeline("automatic-speech-recognition", model=model, tokenizer=processor, feature_extractor=processor.feature_extractor, decoder=processor.decoder)
detokenize_dict = {value: key for key, value in processor.tokenizer.get_vocab().items()}
dict_v = ["а", "у" "о" "и" "э" "ы" "я" "ю" "е" "ё"]
def count_char_borders(predicted_ids, input_values, processor, sample_rate=16000):
predicted_ids_l = predicted_ids[0].tolist()
duration_sec = input_values.shape[1] / sample_rate
ids_c_time = [(i / len(predicted_ids_l) * duration_sec, _id) for i, _id in enumerate(predicted_ids_l)]
t_chars_list = [[i[0], detokenize_dict[i[1]]] for i in ids_c_time if i[1] != processor.tokenizer.pad_token_id]
t_chars_list_cl = []
cur = None
for i, item in enumerate(t_chars_list[:-1]):
if i == 0 or cur == None:
cur = item
if item[1] != t_chars_list[i + 1][1]:
cur.append(t_chars_list[i + 1][0])
t_chars_list_cl.append(cur)
cur = t_chars_list[i + 1]
t_chars_list_cl = [i if i[1] != "|" else [i[0], "", i[2]] for i in t_chars_list_cl]
chars, char_start_times, char_end_times = [], [], []
for c in t_chars_list_cl:
if c[1].lower() in dict_v and c[1] != "":
chars.append("v")
elif c[1] != "":
chars.append("c")
else:
chars.append("")
char_start_times.append(c[0])
char_end_times.append(c[2])
return chars, char_start_times, char_end_times
# обработка seg-файла, получение информации для расчётов
# предполагается, что на вход получаем seg либо 'corpres' - с разметкой по корпресу, либо упрощённая разметка 'cv' - с разметкой на согласные и гласные
def preprocess(chars, starts, labelled='cv'):
start_and_sound = []
# берём из seg-файла метки звуков, отсчёты переводим в секунды, получаем общую длительность
for i, item in enumerate(chars):
start_time = float(starts[i])
label = item
start_and_sound.append([start_time, label])
# заводим переменные, необходимые для расчётов
clusters_and_duration = []
pauses = 0
sum_dur_vowels = 0
# флаг для определения границ кластеров. важно, если до и после паузы звуки одного класса
postpause_flag = 0
# обработка файлов с гласно-согласной разметкой
if labelled == 'cv':
total_duration = 0
# определяем к какому классу относится каждый звук и считаем длительность (отдельных гласных и согласных кластеров)
for n, i in enumerate(start_and_sound):
sound = i[1]
# определяем не является ли звук конечным
if n != len(start_and_sound) - 1:
duration = start_and_sound[n+1][0] - i[0]
# выделяем гласные
if sound == 'V' or sound == 'v':
total_duration += duration
# записываем отдельно звук в нулевой позиции в обход ошибки индекса
if n == 0:
clusters_and_duration.append(['V', duration])
# объединяем длительности, если предыдущий звук тоже был гласным
elif clusters_and_duration[-1][0] == 'V' and postpause_flag == 0:
clusters_and_duration[-1][1] += duration
# фиксируем длительность отдельного гласного звука
else:
clusters_and_duration.append(['V', duration])
# считаем длителность всех гласных интервалов в записи
sum_dur_vowels += duration
# снимаем флаг
postpause_flag = 0
# выделяем паузы
elif sound == '':
pauses += duration
total_duration += duration
# ставим флаг для следующего звука
postpause_flag = 1
# выделяем согласные
else:
total_duration += duration
# записываем отдельно звук в нулевой позиции в обход ошибки
if n == 0:
clusters_and_duration.append(['C', duration])
# объединяем длительности, если предыдущий звук тоже был согласным
elif clusters_and_duration[-1][0] == 'C' and postpause_flag == 0:
clusters_and_duration[-1][1] += duration
# фиксируем длительность отдельного согласного звука
else:
clusters_and_duration.append(['C', duration])
# снимаем флаг
postpause_flag = 0
# функция возвращает метки кластеров и их длительность и общую длительность всех гласных интервалов
return clusters_and_duration, sum_dur_vowels, total_duration, pauses
def delta_C(cons_clusters):
# применяем функцию numpy среднеквадратического отклонения
dC = np.std(cons_clusters)
return dC
def percent_V(vowels, total_wo_pauses):
pV = vowels / total_wo_pauses
return pV
# point_1 = np.array((0, 0, 0))
# point_2 = np.array((3, 3, 3))
def count_eucl(point_1, point_2):
# Initializing the points
# Get the square of the difference of the 2 vectors
square = np.square(point_1 - point_2)
# Get the sum of the square
sum_square = np.sum(square)
# The last step is to get the square root and print the Euclidean distance
distance = np.sqrt(sum_square)
return distance
ex_dict = {"eng": np.array((0.0535, 0.401)), "kat": np.array((0.0452, 0.456)), "jap": np.array((0.0356, 0.531))}
def classify_rhytm(dC, pV):
our = np.array((dC, pV))
res = {}
if (dC > 0.08 and pV > 0.45) or (dC < 0.03 and pV < 0.04):
text = "Вы не укладываетесь ни в какие рамки и прекрасны в этом!"
else:
for k, v in ex_dict.items():
res[k] = count_eucl(our, v)
sorted_tuples = sorted(res.items(), key=lambda item: item[1])
sorted_res = {k: v for k, v in sorted_tuples}
if [i for i in sorted_res.keys()][0] == "eng":
text = "По типу ритма ваша речь близка к тактосчитающим языкам (английский)."
if [i for i in sorted_res.keys()][0] == "kat":
text = "По типу ритма ваша речь близка к слогосчитающим языкам (испанский)."
if [i for i in sorted_res.keys()][0] == "jap":
text = "По типу ритма ваша речь близка к моросчитающим языкам (японский)."
return text
def transcribe(audio):
y, sr = sf.read(audio, samplerate=16000)
input_values = processor(y, sampling_rate=sr, return_tensors="pt").input_values
logits = model(input_values).logits
predicted_ids = torch.argmax(logits, dim=-1)
chars, char_start_times, char_end_times = count_char_borders(predicted_ids, input_values, processor)
clusters_and_duration, sum_dur_vowels, total_duration, pauses = preprocess(chars, char_start_times)
cons_clusters = []
# параметры для ΔC
for x in clusters_and_duration:
if x[0] == 'C':
cons_clusters.append(x[1])
# параметры для %V
vowels_duration = sum_dur_vowels
duration_without_pauses = total_duration - pauses
# расчёт метрик
dC = delta_C(cons_clusters) / 5
pV = percent_V(vowels_duration, duration_without_pauses) * 5
transcription = processor.batch_decode(logits.detach().numpy()).text[0]
text = {"transcription": transcription}
text['dC'] = dC
text['pV'] = pV
cl = classify_rhytm(dC, pV)
text['result'] = cl
return text
iface = gr.Interface(
fn=transcribe,
inputs=gr.Audio(type="filepath"),
outputs="text",
title="Mihaj/Wav2Vec2RhytmAnalyzer",
description="Демо анализатор ритма на основе модели Wav2Vec large от bond005.",
)
iface.launch() |