Spaces:
Sleeping
Sleeping
File size: 5,139 Bytes
28bcfea c99e36c 28bcfea 280abdf 28bcfea 8825934 28bcfea d765cf3 28bcfea d765cf3 28bcfea d765cf3 28bcfea d765cf3 28bcfea 244af9f 28bcfea 280abdf 28bcfea ee7d7fc | 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 | import os
import gradio as gr
import numpy as np
import sherpa_onnx
from huggingface_hub import hf_hub_download
# ── 1. Загрузка приватных моделей ────────────────────────────
HF_TOKEN = os.environ.get("HF_TOKEN")
REPO_ID = "exboogiman/streamingASR"
print("Скачивание моделей...")
encoder_path = hf_hub_download(repo_id=REPO_ID, filename="encoder-uzbek_fc.onnx", token=HF_TOKEN)
decoder_path = hf_hub_download(repo_id=REPO_ID, filename="decoder-uzbek_fc.onnx", token=HF_TOKEN)
joiner_path = hf_hub_download(repo_id=REPO_ID, filename="joiner-uzbek_fc.onnx", token=HF_TOKEN)
tokens_path = hf_hub_download(repo_id=REPO_ID, filename="tokens.txt", token=HF_TOKEN)
vad_path = hf_hub_download(repo_id=REPO_ID, filename="silero_vad.onnx", token=HF_TOKEN)
# ── 2. Инициализация компонентов ────────────────────────────
recognizer = sherpa_onnx.OfflineRecognizer.from_transducer(
encoder=encoder_path,
decoder=decoder_path,
joiner=joiner_path,
tokens=tokens_path,
model_type="nemo_transducer",
num_threads=2,
sample_rate=16000,
feature_dim=80,
decoding_method="greedy_search",
)
# Настройки VAD
vad_config = sherpa_onnx.VadModelConfig()
vad_config.silero_vad.model = vad_path
vad_config.silero_vad.min_silence_duration = 0.3 # пауза 300мс = конец фразы
vad_config.silero_vad.threshold = 0.5
vad_config.sample_rate = 16000
# ── 3. Логика стриминга ──────────────────────────────────────
def initialize_state():
return {
"vad": sherpa_onnx.VoiceActivityDetector(vad_config, buffer_size_in_seconds=30),
"buffer": np.array([], dtype=np.float32),
"transcript": "",
}
def transcribe_stream(audio, state):
if state is None:
state = initialize_state()
if audio is None:
return state["transcript"], state
sr, y = audio
# Приводим к моно
if y.ndim > 1:
y = y.mean(axis=-1)
# Приводим к float32 и нормализуем
samples = y.astype(np.float32)
if np.max(np.abs(samples)) > 1.0:
samples = samples / 32768.0
# Добавляем новые семплы в буфер
state["buffer"] = np.concatenate([state["buffer"], samples])
vad = state["vad"]
window_size = vad_config.silero_vad.window_size
# Передаем в VAD фиксированными окнами
while len(state["buffer"]) >= window_size:
vad.accept_waveform(state["buffer"][:window_size])
state["buffer"] = state["buffer"][window_size:]
# Если VAD вырезал законченную фразу — распознаем её офлайн-моделью
new_text_segments = []
while not vad.empty():
stream = recognizer.create_stream()
stream.accept_waveform(16000, vad.front.samples)
vad.pop()
recognizer.decode_stream(stream)
text = stream.result.text.strip()
if text:
new_text_segments.append(text)
# Если есть новые распознанные слова, добавляем их к общей истории
if new_text_segments:
added_text = " ".join(new_text_segments)
if state["transcript"]:
state["transcript"] += " " + added_text
else:
state["transcript"] = added_text
return state["transcript"], state
# ── 4. Описание интерфейса Gradio Blocks ─────────────────────
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# STT Real-time Streaming Demo (Uzbek)")
# Состояние для сохранения VAD буфера между вызовами
state = gr.State()
with gr.Row():
# Вход звука с микрофона с флагом streaming=True
input_audio = gr.Audio(
sources=["microphone"],
type="numpy",
streaming=True,
label="Говорите в микрофон"
)
# Поле вывода текста
output_text = gr.Textbox(
label="Распознанный текст",
interactive=False,
placeholder="Ваша речь отобразится здесь..."
)
# Событие .stream срабатывает каждые ~0.5 сек по мере записи звука
input_audio.stream(
fn=transcribe_stream,
inputs=[input_audio, state],
outputs=[output_text, state],
show_progress="hidden"
)
# Сброс состояния при очистке аудио
input_audio.clear(
fn=initialize_state,
inputs=[],
outputs=[state]
)
if __name__ == "__main__":
demo.launch() |