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 секунд від моменту мови:```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 // Клиентская часть: захват аудио и стриминг на сервер 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)css /* Субтитры для слабослышащих — 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 через Botpython

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}"} )