Система live captions реального часу: архітектура, затримка, інтеграція
Субтитри в реальному часі (live captions) — технічний засіб реабілітації за ГОСТ Р 52872-2019 та міжнародним стандартом WCAG 2.1 (критерій 1.2.4). Ми розробляємо системи субтитрування, які працюють із затримкою менше 2 секунд. Це критично для трансляцій, конференцій, телебачення та освітніх платформ. Наша команда — 12 інженерів із сумарним досвідом понад 25 років у галузі STT та NLP. Ми реалізували 10+ інсталяцій для подій із аудиторією до 5000 осіб та забезпечили доступ до інформації для тисяч людей із порушеннями слуху. Впровадження AI-субтитрів дозволяє заощадити до 40% бюджету порівняно з ручним субтитруванням, а окупність настає протягом 2–3 місяців при регулярних трансляціях. Для оцінки вашого проєкту зв'яжіться з нами — ми запропонуємо рішення під ключ.
Проблеми, які вирішуємо
Стандартні субтитри часто відстають від мовлення на 5–10 секунд — це неприйнятно для людей із порушеннями слуху. Типові складнощі:
- Синхронізація тексту та звуку страждає при використанні batch-обробки аудіо.
- Хмарні STT-сервіси не завжди справляються з доменною лексикою (медична, юридична термінологія).
- Інтеграція з платформами на кшталт Zoom та Teams потребує окремого бота та налаштування API.
Ми вирішуємо ці проблеми через вибір streaming-моделі, оптимізацію буферизації та кастомізацію словника. Наприклад, в одному проєкті для конференції з телемедицини ми донавчили Whisper на корпусі медичних термінів — точність розпізнавання зросла з 82% до 95%.
Як забезпечити затримку менше 2 секунд?
Ключ — вибір streaming-моделі та архітектура передачі аудіо. Deepgram Nova-2 видає partial results кожні 200 мс, що дає затримку end-to-end близько 1 секунди — в 2–3 рази швидше, ніж faster-whisper large-v3 у batch-режимі. Для локальних сценаріїв ми використовуємо faster-whisper з VAD-фільтром та буфером 3 секунди, що дає 2.5–4 секунди. Але якщо потрібно < 2 сек — лише хмарний streaming.
Real-time STT стек
Для субтитрів із затримкою < 2 секунд від моменту мовлення використовуємо локальний faster-whisper або хмарний Deepgram Nova-2. Приклад ядра на Python:
import asyncio
import websockets
from faster_whisper import WhisperModel
import numpy as np
import sounddevice as sd
class RealTimeCaptioner:
def __init__(self):
self.model = WhisperModel(
"large-v3",
device="cuda",
compute_type="float16"
)
self.buffer = []
self.chunk_duration = 3.0 # секунды буферизации
self.sample_rate = 16000
async def stream_captions(self, websocket, audio_queue: asyncio.Queue):
"""Стриминг субтитров через WebSocket"""
while True:
chunk = await audio_queue.get()
self.buffer.append(chunk)
buffer_duration = len(self.buffer) * len(chunk) / self.sample_rate
if buffer_duration >= self.chunk_duration:
audio_data = np.concatenate(self.buffer)
self.buffer = []
segments, _ = self.model.transcribe(
audio_data,
language="ru",
vad_filter=True,
vad_parameters={"min_silence_duration_ms": 500}
)
for segment in segments:
caption = {
"text": segment.text.strip(),
"start": segment.start,
"end": segment.end,
"confidence": segment.avg_logprob
}
await websocket.send(json.dumps(caption, ensure_ascii=False))
WebRTC інтеграція для браузера
Клієнтська частина на JavaScript захоплює аудіо з мікрофона та передає на сервер через WebSocket. Сервер повертає субтитри, які відображаються з rolling-вікном.
// Клиентская часть: захват аудио и стриминг на сервер
class LiveCaptionClient {
constructor(wsUrl) {
this.ws = new WebSocket(wsUrl);
this.captionDiv = document.getElementById('captions');
}
async startCapturing() {
const stream = await navigator.mediaDevices.getUserMedia({
audio: { sampleRate: 16000, channelCount: 1, echoCancellation: true }
});
const audioContext = new AudioContext({ sampleRate: 16000 });
const processor = audioContext.createScriptProcessor(4096, 1, 1);
processor.onaudioprocess = (event) => {
const pcmData = event.inputBuffer.getChannelData(0);
const int16Array = new Int16Array(pcmData.length);
for (let i = 0; i < pcmData.length; i++) {
int16Array[i] = Math.max(-32768, Math.min(32767, pcmData[i] * 32768));
}
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(int16Array.buffer);
}
};
this.ws.onmessage = (event) => {
const caption = JSON.parse(event.data);
this.displayCaption(caption.text);
};
const source = audioContext.createMediaStreamSource(stream);
source.connect(processor);
processor.connect(audioContext.destination);
}
displayCaption(text) {
// Отображение с rolling-window (последние 2-3 строки)
const line = document.createElement('p');
line.textContent = text;
line.className = 'caption-line';
this.captionDiv.appendChild(line);
// Убираем старые строки
while (this.captionDiv.children.length > 3) {
this.captionDiv.removeChild(this.captionDiv.firstChild);
}
// Auto-scroll
this.captionDiv.scrollTop = this.captionDiv.scrollHeight;
}
}
Як вибрати STT-модель для субтитрів?
Вибір між локальним та хмарним рішенням:
| Параметр | faster-whisper (локально) | Deepgram Nova-2 (хмара) |
|---|---|---|
| Затримка | 0.3–0.8 сек (інференс) | 0.1–0.3 сек (streaming) |
| Якість | висока (large-v3) | висока (спеціалізована) |
| Конфіденційність | повна | дані йдуть у хмару |
| Вартість | один GPU (~$0.5/год) | $0.004/хв аудіо |
| Підтримка мов | 99+ | 30+ |
Для завдань, де потрібна повна ізоляція даних (медичні, державні) — локальний faster-whisper із Triton Inference Server. Для типових трансляцій — хмарний Deepgram або AssemblyAI. Ми оцінимо проєкт та запропонуємо оптимальний варіант. Замовте попередній аудит — він безкоштовний та займе 30 хвилин.
Вимоги до відображення (WCAG 2.1)
/* Субтитри для людей із порушеннями слуху — WCAG 2.1 критерій 1.4.3 */
.caption-container {
background-color: rgba(0, 0, 0, 0.85);
color: #FFFFFF;
font-size: 1.5rem; /* мінімум 24px */
line-height: 1.6;
padding: 12px 20px;
border-radius: 4px;
max-width: 80%;
font-family: Arial, sans-serif; /* висока розбірливість */
}
/* Високий контраст (коефіцієнт 7:1 для AA+) */
.caption-line {
color: #FFFFFF;
text-shadow: 1px 1px 2px #000;
}
Інтеграція з Zoom/Teams через Bot
# Zoom використовує RTMP для стрімінгу субтитрів
import httpx
async def push_zoom_captions(meeting_id: str, caption_text: str, seq: int):
"""Відправляємо субтитри в Zoom через Closed Caption API"""
async with httpx.AsyncClient() as client:
await client.post(
f"https://api.zoom.us/v2/meetings/{meeting_id}/live_streaming/captions",
json={"text": caption_text, "seq": seq, "lang": "uk-UA"},
headers={"Authorization": f"Bearer {ZOOM_JWT_TOKEN}"}
)
Що таке streaming transcription?
Streaming transcription — це технологія, при якій модель розпізнає мовлення в міру надходження аудіофрагментів, видаючи проміжні результати (partial results) кожні 100-200 мс. Це дозволяє оновлювати субтитри плавно, без пауз на очікування повної фрази. Використовуємо WebSocket для передачі аудіофрагментів та отримання тексту з часовими мітками.
Чек-лист для впровадження
- [ ] Аудит поточних каналів звуку та платформи
- [ ] Вибір STT-моделі (локальна/хмарна)
- [ ] Калібрування під доменну лексику
- [ ] Розробка WebRTC/WebSocket-сервера
- [ ] Інтеграція з Zoom, Teams, YouTube Live, RTMP
- [ ] Інтерфейс керування та ручної корекції
- [ ] Документація та навчання операторів
- [ ] Гарантія 6 місяців
Орієнтовні терміни
Веб-компонент субтитрування — 1–2 тижні. Повна інтеграція з платформами — 2–3 тижні. Для оцінки вашого проєкту зв'яжіться з нами — опишіть сценарій, і ми розрахуємо рішення. Економія бюджету може досягати 40% порівняно з ручним субтитруванням, а окупність — за 2–3 місяці. Отримайте консультацію прямо зараз!







