Использование Wit.ai в качестве S2T решения бесплатно даже для коммерческого пользования, однако его разработчики просят выполнять 2 условия - не более 1 запроса к серверам Wit.ai в секунду и условие «честного использования» [8][9] - запросы к Wit.ai должны быть изначально происходить от человека. В то время как второе условие напрямую выполняется, первое условие обязывает алгоритм не делать более 1 запроса к Wit.ai в секунду.
Рис. 2. Диаграмма процесса распознавания речи по сегментам
В результате при тестировании алгоритма оказалось, что скорость распознавания зависит от качества аудиозаписи. Если речь слабо различима от фонового шума, есть большое количество эха или голоса перебивают друг друга - время распознавания будет больше из-за повторной попытки распознавания “плохих” участков с помощью Google Speech API.
В ходе тестирования открылась главная проблема данного решения - при наличии в аудиозаписи пустых отрезков длиной более 45 секунд Wit.ai не возвращал результатов, и отрезок автоматически посылался на распознавание с помощью платного Google Speech API. Для решения этой проблемы было решено использовать технологию VAD (англ. Voice Activity Detection - обнаружение голосовой активности).
Примером такой технологии является часть кода проекта с открытым исходным кодом под названием WebRTC [10], предназначенным для организации передачи потоковых данных между браузерами или другими поддерживающими его приложениями по технологии точка-точка.
Для языка Python 3 есть несколько классов оберток и интерфейсов с открытым кодом, позволяющих использовать данную технологию. Одним из примеров такой обертки стал python-vad [11], который и было решено использовать для решения выше обозначенной проблемы.
Рис. 3. Пример работы технологии обнаружения голосовой активности
Данное решение позволило получать временные метки, позволяющие различить периоды аудиозаписи в которых есть речь, а в которых нет. При условии игнорирования очень коротких сегментов аудио длиной до одной секунды, в которых чаще всего нет речи (ошибки работы алгоритма) и делении больших по длине сегментов речи (более 45 секунд) на более короткие получилось достичь решения проблемы перепосылки аудио сегментов без речи на платный сервис распознавания Google Speech API.
3.3.4 Разработка HTTP Request API
Flask - веб фреймворк [12], был использован для реализации обмена данными между частями сервиса. Было создано HTTP Request API [13] для взаимодействия между воркером - сервером что распознает файлы от пользователей и сервером, обслуживающим сайт для пользователей.
Так как архитектура сервиса подразумевает возможность быстрого расширения вычислительной мощности сервер, обслуживающий сайт хранит в своей базе данных очередь задач с их статусами и при обращении любого воркера по заданному адресу выдает ему информацию о том, по какой ссылке скачать файл для распознавания, идентификационный номер задачи, язык речи в файле и статус «бесплатности» распознавания. В случае если флаг бесплатного распознавания True - перед разделением исходного файла на части подлежащие распознавания файл не будет распознаваться больше, чем на 10 минут аудио дорожки.
GET http://127.0.0.1:5100/api/tasks
Типичный ответ (JSON):
{
"status": "ok",
"id": <id>,
"uri": <uri>,
"language": <language>,
"trial": <trial>,
"trial_length": <trial_length>
}
Во время распознавания воркер посылает серверу сайта обновления статуса задачи с помощью POST запроса и query string в адресе запроса. Поле статуса данного запроса может принимать значения "creating", "in_progress", "failed", "complete". Данный запрос позволяет серверу сайта сбросить статус задачи при произошедшей ошибке во время распознавания воркером.
POST http://127.0.0.1:5100/api/tasks/<id>/
set_status?status=<status>
Типичный ответ: 200
Рис. 4. Внешний вид тестовой страницы
программный распознавание речь аудио текст
В момент, когда воркер завершает распознавание задачи, он отправляет multipart POST запрос, содержащий в своем теле два файла результатов - результат с текстом, разделенным на строки с временными метками и без них.
POST http://127.0.0.1:5100/api/tasks/<id>/result
Типичный ответ: 200
Также с помощью Flask была реализована тестовая страница, позволяющая отслеживать процесс выполнения задач распознавания, создавать новые или останавливать текущие задачи, а так же отключать периодические запросы воркера к серверу с очередью задач.
3.4 Описание структуры и рабочего процесса программного обеспечения
Исходный код разработанного программного обеспечения содержится в двух файлах - app_namespace.py (512 строк) и recognition_wit.py (687 строк).
3.4.1 Работа app_recognition.py
Первый файл содержит исходный код, отвечающий за получение задач, обновление их статуса на сервере очереди задач с помощью HTTP запросов, отправку результатов распознавания. Еще одна задача кода, содержащегося в app_namespace.py - обслуживание тестовой страницы и запросов, приходящих с нее.
При запуске данный скрипт запускает две главных параллельных фоновых функции:
? task_request_loop() отвечающую за запрос задач от сервера с очередью задач. Период цикла данной функции - 5 секунд в режиме дебата и 20 секунд в обычном режиме работы.
? task_send_status_loop() отвечающую за запросы обновления статуса задач на сервере очереди и отправку результатов, полученных по окончанию задач распознавания. Период цикла данной функции - 1 секунда.
При получении задачи task_request_loop() создает новый объект класса Task(), который при инициализации парсит json, полученный от сервера очереди задач и создает класс WitRecognition, импортированный из файла recognition_wit.py, а также содержит главные параметры задачи и очереди для обмена данных с дочерним классом WitRecognition. Важно заметить, что класс WitRecognition наследует стандартный класс языка Python 3 Threading.thread() и поэтому работает в отдельном потоке. Это необходимо для параллельного распознавания нескольких задач одновременно и одновременного функционирования тестовой страницы и поддержки HTTP API.
3.4.2 Работа wit_recognition.py
Основными классом в файле wit_recognition.py является класс WitRecognition. В его задачи входит:
1. конвертирование исходного аудиофайла в формат, поддерживаемый главным сервисом распознавания Wit.ai
2. анализирование полученного аудиофайла с помощью VAD, «нарезание» аудиофайла на куски с речью и фильтрация ошибок VAD
3. распознавание полученных сегментов аудио с речью с помощью пула потоков
4. анализирование, склейка, и сохранение полученных результатов и логов работы в текстовые файлы
Рис. 5. Диаграмма работы задачи распознавания
Сначала полученный файл конвертируется в MP3 128 Кбит/с. В ходе тестирования оказалось, что Wit.ai поддерживает MP3 файлы и больших битрейтов, например 320 Кбит/с, однако ограничение накладывается на размер файла (до 5.5 Мб или до 55 секунд), то есть на длину распознанного аудио за один запрос. Битрейт 128 Кбит/с был выбран так как он не сильно отличается по качеству и точности передачи речи от 320 Кбит/с, но дает преимущество в длине распознанного аудио за один запрос к Wit.ai.
После конвертирования файл «отправляется» на анализ с помощью Voice Activity Detection. Для этого файл делится на куски по 10 минут и результаты анализов собираются воедино после полной обработки всего файла. Это сделано для того, чтобы избежать переполнения памяти, так как процесс анализирования на нахождение речи в файле переполнял 2Гб оперативной памяти удаленного виртуального сервера при анализе аудиозаписей длиной более 50-60 минут.
После получения временных меток начала и конца фрагментов, содержащих речь, аудиозапись «нарезается» на фрагменты с длиной каждого фрагмента +30% относительно результатов VAD. Это сделано для того, чтобы распознанный из фрагментов текст можно было склеить воедино, найдя максимальное совпадение. Фрагменты длиной более 45 секунд разрезаются пополам (см. выше - ограничения Wit.ai)
Конвертирование и нарезка аудиофайла выполняется с помощью создания подпроцесса FFmpeg с помощью стандартного модуля Python - subprocess [14].
Так как обнаружение голосовой активности часто дает временные метки, в аудиосегментах которых могут содержаться случайные вздохи, фоновые тихие голоса и другой «мусор» данные сегменты надо отсеивать. Для этого используется оценка среднего уровня громкости длинных фрагментов аудио, и все сегменты аудио, где средний уровень громкости на 20 децибел ниже, чем средний уровень громкости самого длинного фрагмента отсеиваются.
Следующим шагом работы программы является непосредственно распознавание полученных фрагментов аудио. Для этого используется пул потоков [15], в аргументы которым передаются фрагменты для распознавания. В один и тот же момент может работать только 12 потоков. Это связано с тем, что длина самого большого фрагмента равна 45 секундам, а среднее скорость распознавания такого фрагмента с помощью Wit.ai и Google Speech API - около 12 секунд. Таким образом, при условии того, что Wit.ai просит не делать более одного запроса к их серверам в секунду получается полная «загруженность канала».
Распознавание с помощью Wit.ai может быть нестабильно. Во время тестирования оказалось, что при посылке аудио с плохим качеством в первую попытку Wit.ai может не возвратить результатов, но при попытке отправить повторно ту же самую аудиозапись на распознавание сервис может вдруг вернуть результаты, чаще всего во время третьей попытки, поэтому, прежде чем любая аудиозапись будет отправлена на распознавание платным сервисом Google Speech API будет 3 раза отправлена на сервис распознавания речи Wit.ai.
После получения результатов распознавания производится попытка «склеивания» их в читаемый текст. Так как сегменты аудио нарезаются с 30% запасом по длине, часто результаты соседних фрагментов содержат одинаковые куски текста. Процедура «склеивания» пытается найти максимальный одинаковый фрагмент текста в обеих строках результата, и обрезать их таким образом, чтобы текст конца первой строки логично продолжался в начале второй строки.
Последним шагом в работе класса WitRecognition является сохранение результатов и логов работы в соответствующие файлы на диске.
3.5 Описание алгоритма работы разрабатываемого сервиса
При разработке программного обеспечения задумывался следующий алгоритм работы сервиса в целом:
1. Пользователь заходит на сайт, вводит свой электронный адрес и выбирает язык из выпадающего списка.
2. С помощью диалога выбора файла или используя drag-n-drop загружает файл на сервис.
3. Сервер, обслуживаемый веб интерфейс и очередь задач вносит новую задачу с ее параметрами в базу данных.
4. При запросе воркером новой задачи сервер очереди задач помечает ее флагом «в работе»
5. По ходу распознавания воркер отправляет новые статусы задачи серверу очереди задач, таким образом обеспечивается контроль за возможными ошибками на стороне воркера.
6. Как только распознавание заканчивается, воркер делает HTTP запрос, содержащий файлы результатов в своем теле, сервер очереди задач сохраняет результаты и отправляет письмо пользователю о том, что распознавание завершено с ссылками на скачивание результатов.
Рис. 6. Диаграмма обмена информацией между частями сервиса
3.6 ТЗ на создание сервера веб интерфейса и очереди задач
Описание сервиса:
Сервис Transcript предназначен для преобразования загружаемых в него медиафайлов (видео, звук в любых доступных форматах любой длины) в текст при помощи Google Speech API и Wit.ai
На первом этапе требуется сделать минимальный рабочий продукт со следующими возможностями:
? Стартовая страница с полем загрузки файла, индикатором процесса загрузки (расчет прогресс бара на стороне клиента) и полем ввода электронной почты. На странице, помимо названия должно быть поле выбора языка речи в входном файле, и текстовое поле для краткого вводного текста, рекомендациям по форматам файлов, качеству аудиозаписи и т.д.
? После обработки и расчета стоимости обработки файла на стороне сервера пользователю показывается страница платежной системы, где ему предлагается заплатить рассчитанную из длины файла сумму.
? Важный момент: если файл занимает меньше 10 (+1 на нечеткую обрезку) минут и за текущие сутки не было загрузок с указанной электронной почты (возможна проверка по email / browser user agent + IP, простой фильтр типичных временных email/алиасов email), то вместо платежки показывается уведомление, что результаты распознавания скоро придут на почту. Если лимит превышен или это уже не первый файл, то показывается окно платежной системы с предложением оплатить заказ, а после принятия платежа показывается то же сообщение о том, что результат скоро придет на электронную почту. Подтвердив это сообщение, пользователь попадает на стартовую страницу сервиса.
? Сохранение истории задач распознавания (email - id задачи - количество минут - путь к исходному файлу - пути к результатам - загружены ли файлы на gdrive)