Чому ми Послуги Портфоліо Блог Технології Процес розробки Розпочати проєкт →
UA EN RU
← Всі статті
Інсайт · 20.05.2019 · 7 хв читання

Голосове керування сайтом інтернет-магазину: як це працює

Як зробити пошук голосом на сайті інтернет-магазину: аудіопотік із браузера, передача через WebSocket на сервер і потокове розпізнавання мовлення в Google Speech API.
Голосове керування сайтом інтернет-магазину: як це працює

Завдання звучало просто: дати покупцеві змогу з будь-якого браузера й будь-якого пристрою продиктувати пошуковий запит словами. Голос перетворюється на текст у рядку пошуку, а окремі слова працюють як команди — «шукати», «скасувати» — і запускають відповідні дії на сайті. Нижче розбираємо, як влаштована така система зсередини: від мікрофона в браузері до відповіді служби розпізнавання й назад.

Завдання

Треба розробити функцію розпізнавання мовлення на вебсторінці інтернет-магазину. Покупець натискає кнопку запису, диктує запит — і бачить його текстом у пошуковому рядку. Частина сказаного обробляється як команди: «шукати» запускає пошук, «скасувати» скидає введене.

Ключова вимога — повна сумісність із найпоширенішими браузерами: Chrome, Firefox, Safari, Opera та Edge. Тобто рішення не може спиратися на можливості, які є лише в одному з них.

Що має вміти система

Щоб це запрацювало, потрібні три речі:

  • отримати аудіопотік із браузера;
  • передати аудіодані потоком до служби розпізнавання мовлення;
  • отримувати результати в режимі реального часу — поки користувач ще говорить.
5
браузерів, у яких має працювати: Chrome, Firefox, Safari, Opera, Edge
1
аудіоканал зі стерео — більше службі розпізнавання не потрібно
65 с
ліміт довжини аудіо в одному запиті розпізнавання

Крок 1. Як отримати аудіопотік із браузера

Тут нам допоможе API getUserMedia / Stream, який підтримує більшість популярних браузерів. Через цей браузерний інтерфейс ми отримуємо аудіопотік із мікрофона й надсилаємо його до нашої служби розпізнавання мовлення.

Підтримка API getUserMedia / Stream у популярних браузерах
Підтримка getUserMedia / Stream API браузерами

Далі ініціалізуємо аудіоконтекст і викликаємо getUserMedia. Хоча така конфігурація сумісна з основними браузерами, параметри, які передають у цей API, можуть відрізнятися залежно від потреб — деталі варто звіряти з офіційною документацією.

Налаштування аудіоконтексту

Конфігурація аудіоконтексту та процесора сценаріїв теж залежить від задачі. Складність у тому, що деякі комбінації параметрів наразі не працюють у Safari — це варто перевіряти окремо.

Окрему увагу треба приділити підписці на подію «audioprocess»: для потоку з мікрофона вона фактично виконує роль події «ondata».

Звук реєструється в стерео, тож із мікрофона йдуть два аудіоканали. Насправді ми забираємо лише один із них, бо службі розпізнавання потрібне аудіо з одним каналом. Але залежно від ваших потреб зі звуком можна працювати як завгодно.

Формат має значення. Дані, що надходять з аудіопотоку, — це типізований масив Float32Array. Тобто перед відправкою до служби розпізнавання їх доведеться конвертувати.

Що робити під час зупинки запису

  1. Вимкнути мікрофон. Припинити користування мікрофоном браузера та скинути змінні, якщо такі є.
  2. Відключити слухача події аудіопроцесу. Без цього потік і далі викликатиме подію, навіть коли мікрофон уже деактивовано.

Крок 2. Куди передавати аудіо

Найпростіший шлях — скористатися вбудованим у браузер API розпізнавання мовлення. З ним вебзастосунок розпізнає мовлення потоком просто в браузері, без жодних сторонніх сервісів.

Але, як і в кожному цікавому нововведенні, тут є дрібні проблеми сумісності. І саме вони роблять цей підхід зовсім непридатним для продакшн-застосунків.

Сумісність браузерного API розпізнавання мовлення з різними браузерами
Сумісність вбудованого API розпізнавання мовлення з браузерами

Для доброго користувацького досвіду нам потрібна система розпізнавання в реальному часі, яка повертає результати, поки користувач говорить, а не записує звук повністю й лише потім його транскрибує. Отже, потрібен сторонній сервіс із такими властивостями:

Потокове розпізнавання

Результат має приходити безперервно, у міру того як людина говорить, а не одним шматком після завершення запису.

Сумісність із кожним браузером

Сервіс не повинен залежати від того, що вміє або чого не вміє конкретний браузер користувача.

Чому ми обрали Google Speech API

В інтернеті є багато сервісів, що дають застосункам змогу розпізнавати мовлення через API. Ми зупинилися на Google Speech API: він дає якісний сервіс потокового розпізнавання, справді ефективний, а відповідь у режимі реального часу для нас критично важлива.

SDK-бібліотека надає і службу асинхронного розпізнавання (через gRPC та REST API), і службу розпізнавання в реальному часі — останню тільки через gRPC API.

Наша мета — розпізнавання в режимі реального часу, тож ми обрали саме потокове розпізнавання. Google фактично надає цей API лише через виклик gRPC, використовуючи потокову функцію протоколу gRPC.

Архітектура: браузер, сервер, служба розпізнавання

Саме через це передавати аудіо напряму з браузера через gRPC неможливо. Браузер справді вміє робити gRPC-виклики, але потоково — жодним чином.

Тому ми обрали інший шлях: передавати дані потоком на сервер, а вже звідти — у потокове API розпізнавання Google, і назад, щоб забрати результат розпізнавання.

Варіантів потокової передачі аудіоданих із браузера на сервер небагато. Фактично єдині системи, здатні віддавати дані з браузера потоком, — це протокол webRTC і WebSocket. Для простоти ми обрали WebSocket. Серверну частину має сенс розробляти на nodeJS: там проста обробка потоків і дуже нескладна реалізація вебсокетів.

Схема передачі аудіо з браузера через сервер до служби розпізнавання мовлення
Підсумкова інфраструктура рішення
  1. Підключення. Після натискання кнопки запису підключаємося до WebSocket — ми хочемо уникнути тривалого з'єднання, яке може сповільнити роботу сервера, — і додаємо слухача для даних аудіопотоку.
  2. Прослуховування. Слухаємо події на мікрофоні браузера.
  3. Відправка. Надсилаємо буфер даних на бекенд через WebSocket.
  4. Передача далі. Передаємо дані з бекенда до служби розпізнавання мовлення Google.
  5. Отримання. Забираємо результати розпізнавання.
  6. Повернення у фронтенд. Надсилаємо результати у фронтенд через вебсокет, щоб візуалізувати їх у міру надходження.

Реалізація вебсокета в браузері

Тут важливо пам'ятати, що потік аудіоданих — це масив Float32Array, і його треба перетворити на буфер, а потім знову розгорнути на сервері.

Масив Float32Array конвертуємо в масив Int16Array і вже тоді надсилаємо на сервер. Без цього перетворення сервер не отримає дані в потрібному форматі. Змінна ConversionFactor потрібна виключно для цілей конвертації.

Реалізація вебсокета на сервері

Реалізація на сервері стандартна, болючих точок лише дві:

  • коли саме запускати розпізнавання через Google;
  • як упоратися з різницею між форматом даних потоку, що приходить із вебсокета, і форматом аудіопотоку для потоку розпізнавання мовлення.

Спершу треба створити потік розпізнавання мовлення — деталі є в документації сервісу.

Ліміт 65 секунд. Щойно мовленнєвий потік створено, запит на розпізнавання вже запущено, а Google обмежує довжину аудіо для розпізнавання 65 секундами. Тому розпізнавання треба створювати саме в той момент, коли користувач на вебсторінці натискає кнопку запису, а сервер отримує від браузера запит на підключення до вебсокета.

Далі можна транслювати аудіоблоки, що надходять із браузера, до мовленнєвого API. І ось тут спливає друга болюча точка — формати даних.

ЕтапФормат данихЩо робимо
Мікрофон у браузеріFloat32Array, стереоБеремо лише один канал
Перед відправкою у вебсокетInt16ArrayКонвертуємо з Float32Array
На сервері з вебсокетаСтандартний буфер, цілі по 8 бітПриймаємо як є
Перед записом у потік розпізнаванняInt16Array, кодування «LINEAR16»Конвертуємо буфер

Буфер, що приходить із вебсокета, — це стандартний буфер, масив цілих чисел по 8 біт кожне. А в налаштуваннях розпізнавання мовлення ми вказали, що аудіокодування — «LINEAR16», тобто масив цілих чисел по 16 біт кожне. Тому стандартний буфер треба перетворити на Int16Array, перш ніж записувати його в потік розпізнавання.

Потік розпізнавання, який повертає бібліотека розпізнавання мовлення Google, — це звичайний стандартний потік, і обробляти його можна у звичний спосіб.

Не забудьте закрити потік. Дуже важливо закривати дані потоку розпізнавання, коли закривається вебсокет. Так ми уникаємо помилки розпізнавання мовлення Google через надто довгу потокову передачу звуку.

Результат

У підсумку ми отримуємо кросбраузерну систему розпізнавання мовлення, яка спрощує взаємодію користувача із сайтом. Покупцеві більше не треба набирати назву товару руками — достатньо сказати її вголос.

Якщо плануєте щось подібне у своєму проєкті, починайте з двох перевірок: підтримка getUserMedia / Stream API в потрібних вам браузерах і можливості обраного сервісу speech-to-text. Саме ці дві речі визначають, наскільки складною вийде решта роботи.