Реалізація потокового розпізнавання мови в реальному часі (Streaming STT) Streaming STT передає аудіо чанками та повертає часткові результати із затримкою 100–500 мс — на відміну від batch-підходу, де чекає кінця запису. Це ключова вимога для голосових ботів, живих субтитрів та агент-асист систем. ### Архітектура streaming pipeline```
Microphone/WebRTC → WebSocket Server → STT Engine → NLP Processing → Response
16kHz PCM <200ms RTT partial+final intent/NER UI/TTS
Ключові параметри: - **Chunk size**: 100-250 мс (оптимальний баланс затримки та якості) - **VAD**: обов'язковий для визначення паузи в мові - **Endpointing**: детекція кінця висловлювання для надсилання фінального результату ### WebSocket сервер на FastAPIpython
from fastapi import FastAPI, WebSocket
from faster_whisper import WhisperModel
import numpy as np
import asyncio
app = FastAPI() model = WhisperModel("medium", device="cuda", compute_type="float16")
@app.websocket("/stream") async def stream_stt(websocket: WebSocket): await websocket.accept() audio_buffer = bytearray()
try:
while True:
chunk = await websocket.receive_bytes()
audio_buffer.extend(chunk)
# Транскрибируем каждые 2 секунды накопленного аудио
if len(audio_buffer) >= 32000 * 2: # 2 sec @ 16kHz 16-bit
audio_array = np.frombuffer(audio_buffer, dtype=np.int16).astype(np.float32) / 32768.0
segments, _ = model.transcribe(audio_array, language="ru")
partial_text = " ".join([s.text for s in segments])
await websocket.send_json({
"type": "partial",
"text": partial_text
})
audio_buffer = bytearray()
except Exception:
await websocket.close()
### Порівняння двигунів для streaming | Двигун | Затримка Мови | Вартість | |--------|----------|-------|-----------| | Deepgram Nova-2 | 100-200 мс | 30+ | $0.0043/хв | | Google STT Streaming | 150-300 мс | 125+ | $0.006/хв | | Azure Speech | 150-300 мс | 100+ | $0.01/хв | | faster-whisper (self) | 200-500 мс | 99 | ~$0.001/хв | | Vosk (self, CPU) 300-700 мс | 20+ | ~$0/хв | ### VAD для endpointingpython
import webrtcvad
vad = webrtcvad.Vad(2) # aggressiveness 0-3
def is_speech(audio_chunk: bytes, sample_rate: int = 16000) -> bool:
return vad.is_speech(audio_chunk, sample_rate)
WebRTC VAD обробляє чанки строго 10, 20 чи 30 мс. Для визначення кінця фрази: 500-800 мс тиші після останнього мовного кадру. ### Клієнтська частина (браузер)javascript
const socket = new WebSocket('wss://api.example.com/stream');
const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
const recorder = new MediaRecorder(mediaStream, {
mimeType: 'audio/webm;codecs=opus'
});
recorder.ondataavailable = (event) => { if (socket.readyState === WebSocket.OPEN) { socket.send(event.data); } }; recorder.start(250); // chunks each 250ms







