Распознавание речи Deepgram в реальном времени в PWA

Дата публикации: 2023-03-10

Deepgram предоставляет сервисы распознавания речи и обработки естественного языка. В этом кейсе показано, как использовать его для преобразования живой речи в текст внутри веб-приложения. Демонстрация: deepgram.demo.wiredgeese.com.

SDK и граница безопасности

Для JavaScript доступен SDK Deepgram. Исторический демо-подход подключал его к браузерному приложению:

npm install @deepgram/sdk
cp ./node_modules/@deepgram/sdk/dist/browser/index.js \
  ./js/lib/deepgram.browser.sdk.mjs
import { Deepgram } from './lib/deepgram.browser.sdk.mjs';
const deepgram = new Deepgram(DEEPGRAM_API_KEY);

Для демонстрации это помогает быстро понять интеграцию, но постоянный API-ключ нельзя безопасно помещать в клиентский код. В рабочем продукте сервер выдаёт краткоживущий ограниченный токен либо сам выступает доверенным посредником. Это позволяет контролировать расходы, права и отзыв доступа.

Для заранее записанного аудио API можно вызвать обычным HTTP-запросом: отправить файл или URL и получить текст. Потоковая расшифровка устроена иначе — нужен постоянный сокет.

Потоковая расшифровка

Последовательность проста:

  1. открыть WebSocket с параметрами распознавания, включая язык;
  2. получить доступ к микрофону через браузер;
  3. записывать звук небольшими частями;
  4. отправлять части в сокет и получать результаты по тому же соединению.
const deepgram = new Deepgram(API_KEY);
const socket = deepgram.transcription.live({ language: LANG });
socket.addEventListener('open', onSocketOpen);
socket.addEventListener('message', onSocketMessage);

Запись запускает стандартный MediaRecorder:

const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const recorder = new MediaRecorder(stream, { mimeType: 'audio/webm' });
recorder.start(TIME_SLICE);

TIME_SLICE задаёт интервал события dataavailable. В нём отправляем фрагмент, только если сокет открыт:

recorder.addEventListener('dataavailable', (event) => {
  if (event.data.size > 0 && socket.readyState === 1) {
    socket.send(event.data);
  }
});

Ответ приходит как JSON, а текст лежит в data.channel.alternatives[0].transcript.

Как обработать результат

Сервис возвращает промежуточные и финальные версии фразы. В ответе есть start, duration, флаги is_final/speech_final и уровень уверенности confidence для слов. Поэтому интерфейс не должен просто дописывать каждый ответ: он хранит сегменты по времени и заменяет черновой текст финальным.

function onSocketMessage(message) {
  const data = JSON.parse(message.data);
  const transcript = data.channel.alternatives[0].transcript;
  // Merge transcript by start/duration and final-state flags.
}

Качество зависит от языка, шума, микрофона, модели и словаря предметной области. Перед внедрением нужны тесты на реальных сценариях, явное согласие на доступ к микрофону и понятная политика хранения аудио и транскриптов.

Итог

Deepgram позволяет добавить в PWA расшифровку записей и живой речи: браузер захватывает звук, WebSocket передаёт поток, а приложение собирает текст из ответов. Такой сценарий подходит для заметок, голосовых форм и поддержки, если архитектура защищает учётные данные и уважает приватность говорящих. Wiredgeese может спроектировать и реализовать такую интеграцию под конкретный продукт.

Дополнительные фрагменты исходного кода

mediaRecorder.addEventListener(‘dataavailable’, async (event) => {
if (event.data.size > 0 && deepgramSocket.readyState === 1) {
deepgramSocket.send(event.data);
}
});
function onSocketMessage(message) {
const received = JSON.parse(message.data);
console.log(received);
}
data.channel.alternatives[0].transcript
{
{
{
},
{
},
{
}
]
}
]
},
},
}
}