Использование Google Cloud Speech API v2 в Asterisk для распознавания русской речи

в 14:04, , рубрики: api, asterisk, Google API, Google Speech api, voice recognition, Яндекс API

Добрый вечер, коллеги. Недавно возникла необходимость добавить систему голосовых заявок в нашу ticket-систему. Но не всегда удобно каждый раз прослушивать голосовой файл, поэтому возникла идея добавить к этому систему автоматического распознавания голоса, к тому же в будущем она бы пригодилась в других проектах. В ходе этой работы были испробованы два варианта API наиболее популярных систем распознавания речи от google и yandex. В конечном итоге выбор пал на первый вариант. К сожалению, не нашел подробной информации об этом в интернете, поэтому решил поделиться полученным опытом. Если интересно, что из этого получилось добро пожаловать под кат.

Выбор API для распознавания речи

Я рассматривал только вариант api, коробочные решения были не нужны, поскольку требовали ресурсы, данные для распознания не критичны для бизнеса, да и использование их существенно сложнее и требует больше человеко-часов.

Первым был Yandex SpeechKit Cloud. Мне он сразу понравился простотой использования:

curl -X POST -H "Content-Type: audio/x-wav" --data-binary "@speech.wav" "https://asr.yandex.net/asr_xml?uuid=<идентификатор пользователя>&key=<API-ключ>&topic=queries"

Ценовая политика 400 рублей за 1000 запросов. Первый месяц бесплатно. Но после этого пошли только разочарования:

— На передачу большого предложения, приходил ответ из 2-3 слов
— Распознавались эти слова в странной последовательности
— Попытки изменения топика положительных результатов не принесли

Возможно это было связано со средним качеством записи, мы все тестировали через голосовые шлюзы и древние телефоны panasonic. Пока планирую его в дальнейшем использовать для построения IVR.

Следующим стал сервис от Google. Интернет пестрит статьями, в которых предлагается использовать API для разработчиков Chromium. Сейчас ключей для этого API уже так просто получить нельзя. Поэтому мы будем использовать коммерческую платформу.

Ценовая политика — 0-60 минут в месяц бесплатно. Далее 0,006 $ за 15 секунд речи. Каждый запрос округляется к цифре кратной 15. Первые два месяца бесплатно, для создания проекта нужна кредитная карта. Варианты использования API в базовой документации разнообразны. Мы будем использовать скрипт на Python:

Скрипт из документации
"""Google Cloud Speech API sample application using the REST API for batch
processing."""

import argparse
import base64
import json

from googleapiclient import discovery
import httplib2
from oauth2client.client import GoogleCredentials


DISCOVERY_URL = ('https://{api}.googleapis.com/$discovery/rest?'
                 'version={apiVersion}')


def get_speech_service():
    credentials = GoogleCredentials.get_application_default().create_scoped(
        ['https://www.googleapis.com/auth/cloud-platform'])
    http = httplib2.Http()
    credentials.authorize(http)

    return discovery.build(
        'speech', 'v1beta1', http=http, discoveryServiceUrl=DISCOVERY_URL)


def main(speech_file):
    """Transcribe the given audio file.

    Args:
        speech_file: the name of the audio file.
    """
    with open(speech_file, 'rb') as speech:
        speech_content = base64.b64encode(speech.read())

    service = get_speech_service()
    service_request = service.speech().syncrecognize(
        body={
            'config': {
                'encoding': 'LINEAR16',  # raw 16-bit signed LE samples
                'sampleRate': 16000,  # 16 khz
                'languageCode': 'en-US',  # a BCP-47 language tag
            },
            'audio': {
                'content': speech_content.decode('UTF-8')
                }
            })
    response = service_request.execute()
    print(json.dumps(response))

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'speech_file', help='Full path of audio file to be recognized')
    args = parser.parse_args()
    main(args.speech_file)

Подготовка к использованию Google Cloud Speech API

Нам необходимо будет зарегистрировать проект и создать ключ сервисного аккаунта для авторизации. Вот ссылка для получения триала, необходим гугл-аккаунт. После регистрации необходимо активировать API и создать ключ для авторизации. После необходимо скопировать ключ на сервер.

Перейдем к настройке самого сервера, нам необходимы будут:

— python
— python-pip
— python google api client

sudo apt-get install -y python python-pip
pip install  --upgrade google-api-python-client

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

export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service_account_file.json
export GCLOUD_PROJECT=your-project-id

Скачаем тестовый аудио файл и попытаемся запустить скрипт:

wget https://cloud.google.com/speech/docs/samples/audio.raw
 python voice.py audio.raw
{"results": [{"alternatives": [{"confidence": 0.98267895, "transcript": "how old is the Brooklyn Bridge"}]}]}

Отлично! Первый тест успешен. Теперь изменим в скрипте язык распознавания текста и попробуем распознать его:

nano voice.py
   service_request = service.speech().syncrecognize(
        body={
            'config': {
                'encoding': 'LINEAR16',  # raw 16-bit signed LE samples
                'sampleRate': 16000,  # 16 khz
                'languageCode': 'ru-RU',  # a BCP-47 language tag

Нам необходим .raw аудио файл. Используем для этого sox

apt-get install -y sox
sox test.wav -r 16000 -b 16 -c 1 test.raw
python voice.py test.raw
{"results": [{"alternatives": [{"confidence": 0.96161985, "transcript": "u0417u0434u0440u0430u0432u0441u0442u0432u0443u0439u0442u0435 u0412u0430u0441 u043fu0440u0438u0432u0435u0442u0441u0442u0432u0443u0435u0442 u043au043eu043cu043fu0430u043du0438u044f"}]}]}

Гугл возвращает нам ответ в юникоде. Но мы хотим видеть нормальные буквы. Поменяем немного наш voice.py:

Вместо

print(json.dumps(response))

Мы будем использовать

s = simplejson.dumps({'var': response}, ensure_ascii=False)
    print s

Добавим import simplejson. Итоговый скрипт под катом:

Voice.py

"""Google Cloud Speech API sample application using the REST API for batch
processing."""

import argparse
import base64
import json
import simplejson

from googleapiclient import discovery
import httplib2
from oauth2client.client import GoogleCredentials


DISCOVERY_URL = ('https://{api}.googleapis.com/$discovery/rest?'
                 'version={apiVersion}')


def get_speech_service():
    credentials = GoogleCredentials.get_application_default().create_scoped(
        ['https://www.googleapis.com/auth/cloud-platform'])
    http = httplib2.Http()
    credentials.authorize(http)

    return discovery.build(
        'speech', 'v1beta1', http=http, discoveryServiceUrl=DISCOVERY_URL)


def main(speech_file):
    """Transcribe the given audio file.

    Args:
        speech_file: the name of the audio file.
    """
    with open(speech_file, 'rb') as speech:
        speech_content = base64.b64encode(speech.read())

    service = get_speech_service()
    service_request = service.speech().syncrecognize(
        body={
            'config': {
                'encoding': 'LINEAR16',  # raw 16-bit signed LE samples
                'sampleRate': 16000,  # 16 khz
                'languageCode': 'en-US',  # a BCP-47 language tag
            },
            'audio': {
                'content': speech_content.decode('UTF-8')
                }
            })
    response = service_request.execute()
     s = simplejson.dumps({'var': response}, ensure_ascii=False)
    print s

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'speech_file', help='Full path of audio file to be recognized')
    args = parser.parse_args()
    main(args.speech_file)

Но перед его запуском нужно будет экспортировать ещё одну переменную окружения export PYTHONIOENCODING=UTF-8. Без неё у меня возникли проблемы с stdout при вызове в скриптах.

export PYTHONIOENCODING=UTF-8
python voice.py test.raw
{"var": {"results": [{"alternatives": [{"confidence": 0.96161985, "transcript": "Здравствуйте Вас приветствует компания"}]}]}}

Отлично. Теперь мы можем вызывать этот скрипт в диалплане.

Пример Asterisk dialplan

Для вызова скрипта я буду использовать простенький диалплан:

exten => 1234,1,Answer
exten => 1234,n,wait(1)
exten => 1234,n,Playback(howtomaketicket)
exten => 1234,n,Playback(beep)
exten => 1234,n,Set(FILE=${CALLERID(num)}--${EXTEN}--${STRFTIME(${EPOCH},,%d-%m-%Y--%H-%M-%S)}.wav)
exten => 1234,n,MixMonitor(${FILE},,/opt/test/send.sh support@test.net "${CDR(src)}" "${CALLERID(name)}" "${FILE}")
exten => 1234,n,wait(28)
exten => 1234,n,Playback(beep)
exten => 1234,n,Playback(Thankyou!)
exten => 1234,n,Hangup()

Я использую для записи mixmonitor и после окончания запускаю скрипт. Можно использовать record и это, пожалуй, будет лучше. Пример send.sh для отправки — он предполагает, что у вас уже настроен mutt:

#!/bin/bash
#скрипт для отправки уведомлений

# экспортируем необходимые переменные окружения
# файл лицензии гугла
export GOOGLE_APPLICATION_CREDENTIALS=/opt/test/project.json
# название проекта
export GCLOUD_PROJECT=project-id
# кодировка для питона
export PYTHONIOENCODING=UTF-8
#список переменных на входе
EMAIL=$1
CALLERIDNUM=$2
CALLERIDNAME=$3
FILE=$4

# перекодируем звуковой файл в raw для того, чтобы отдать его гугл апи

sox /var/spool/asterisk/monitor/$FILE -r 16000 -b 16 -c 1 /var/spool/asterisk/monitor/$FILE.raw

# присваиваем переменной значение выполненного скрипта по конвертации звука в текст и обрезаем не нужное

TEXT=`python /opt/test/voice.py /var/spool/asterisk/monitor/$FILE.raw  | sed -e 's/.*transcript"://' -e 's/}]}]}}//'`

# отправляем письмо, включаем в письмо распознанный текст

echo "новое уведомление от номера: $CALLERIDNUM  $CALLERIDNAME
 $TEXT " | mutt -s "Это заголовок письма" -e 'set from=test@test.net realname="я присылаю оповещения"' -a "/var/spool/asterisk/monitor/$FILE" -- $EMAIL

Заключение

Таким образом мы решили поставленную задачу. Надеюсь кому-то пригодится мой опыт. Буду рад комментариям (пожалуй только ради этого и стоит читать Хабр!). В будущем планирую реализовать на основе этого IVR с элементами голосового управления.

Автор: Faight

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js