AI-система субтитрирования в реальном времени для слабослышащих

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1Все 1566 услуг
AI-система субтитрирования в реальном времени для слабослышащих
Средний
от 1 дня до 3 дней
Часто задаваемые вопросы

Направления AI-разработки

Этапы разработки AI-решения

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1285
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    902
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1122
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    859

Разработка AI-субтитрирования в реальном времени для слабослышащих

Субтитры в реальном времени (live captions) — техническое средство реабилитации по ГОСТ Р 52872-2019 и международному стандарту WCAG 2.1 (критерий 1.2.4). Применяется в трансляциях, конференциях, телевидении, образовательных платформах.

Real-time STT стек

Для субтитров с задержкой < 2 секунд от момента речи:

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 интеграция для браузера

// Клиентская часть: захват аудио и стриминг на сервер
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;
    }
}

Требования к отображению (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": "ru-RU"},
            headers={"Authorization": f"Bearer {ZOOM_JWT_TOKEN}"}
        )

Задержка системы

Компонент Типичная задержка
Аудиобуферизация 2–3 сек
Инференс faster-whisper 0.3–0.8 сек
WebSocket передача < 50 мс
Итого end-to-end 2.5–4 сек

Для снижения задержки до < 1.5 сек — используется streaming transcription с partial results через AssemblyAI или Deepgram Nova-2 (поддерживают incremental transcription). Сроки: веб-компонент субтитрирования — 1–2 недели. Интеграция с Zoom/Teams/вещательной платформой — 2–3 недели.