Asetrisk, распознавание и генерации речи с помощью yandex speechkit

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

Итак, настройка Asterisk, для простоты настраивать будем через ael:

На Астериске организован цикл while

1234567 => {
Answer;
Set(audio=/var/lib/asterisk/sounds/custom/enteraccount);
flag=1;
label=1;
while (${flag} = 1){
Background(${audio});
Record(/tmp/${UNIQUEID}label${label}.wav,3,20);
Agi(yandex.agi,/tmp/${UNIQUEID}, ${label});
label=${label}+1;

                  };

    };

В начале позвонившему проигрывается фудио файл «enteraccount» с просьбой назвать лицевой счет
На каждом шаге цикла, позвонившему человеку проигрывается аудио файл «audio», путь к которому получен из agi скрипта, далее записывается ответ, и путь к полученному записанному файлу отправляется agi скрипту, также в скрипт отправляется текущий шаг «label», после чего шаг увеличивается на 1, и цикл повторяется. Из agi скрипта астерис получает 2 параметра, это обязательный параметр «audio», путь к аудиофайлу который нужно проиграть, и не обязательный «label», метка с помощью которой происходит синхронизация астериска и agi. Выход из цикла происходит если человек положил трубку, а также если из agi прийдет параметр «flag» не равный 1.
Еще неплохо бы после завершения вызова удалить все временные файлы, для этого в макросе который срабатывает после завершения вызова пропишем

[macro-hangupcall]
exten => s,1,System(find /tmp/ -name "${UNIQUEID}*" | xargs rm);

На этом настройка астериска завершена.

Далее сам скрипт yandex.agi, написанный на python, для работы необходимо установить pyst

# wget http://heanet.dl.sourceforge.net/project/pyst/pyst/0.6.50/pyst-0.6.50.zip
# unzip pyst-0.6.50.zip
# cd pyst-0.6.50
# python setup.py install

Сам agi:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import urllib2
import urllib
import sys
import random
from xml.dom.minidom import *
import os
import asterisk.agi

agi=asterisk.agi.AGI()
uuid=''
key='28b22b47-a7b0-40d2-892d-ad79bbdbc304'
def yadexASR(uuid, key, topic, callid):
# Функция для преобразования аудио файла в текст
# Генерим уникальный код id для запроса
    while (len(uuid)<32):
        uuid=uuid+random.choice('1234567890abcdef')
    #Ссылка для пост запроса 
    url = 'https://asr.yandex.net/asr_xml?uuid=%s&key=%s&topic=%s&lang=ru-RU' % (uuid, key, topic)
    filename = callid+'.wav'
    #Считываем файл в двоичном режиме
    audio = open(filename,'rb').read()
    #Указываем тип аудиофайла для заголовка в POST запрос
    headers={'Content-Type': 'audio/x-pcm;bit=16;rate=8000'}
    #Отправляем запрос
    request = urllib2.Request(url, data=audio, headers=headers)
    response = urllib2.urlopen(request)
    #Считываем ответ
    answer=response.read()
    # Создаем xml файл для полученного ответа
    f_answer=('%s.xml' % callid)
    f=open(f_answer, 'w')
    # записываем в файл ответ полученный на POST запрос (ответ получен в xml формате)
    f.write(answer)
    f.close()
    # Парсим xml файл
    xml = parse(f_answer)
    # Выбираем из файла значение между тегами variant
    var = xml.getElementsByTagName('variant')
    # Выбираем первое значение из xml файла, оно же наиболее точное в распознании
    result=var[0].childNodes[0].nodeValue
    return result

def generate(key,text, file):
# Функция для преобразования текста в аудио формат
    #Форматируем текс для GET запрса (нужен для корректной обработки кирилици)
    text_f=urllib.quote_plus(text.encode('utf-8'))
    #отправляем запрос на яндекс
    url='http://tts.voicetech.yandex.net/generate?text=%s&format=mp3&lang=ru-RU&speaker=jane&key=%s' % (text_f, key)
    # Сохраняем айдио файл в file
    urllib.urlretrieve(url, file)

if sys.argv[2].replace(' ','')=="1":
    agi.verbose('label='+sys.argv[2].replace(' ',''))
    try:
        # Распознаем полученный файл
        result=yadexASR(uuid, key, 'notes', sys.argv[1]+'label'+sys.argv[2].replace(' ',''))
        # Формируем ответ
        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')
        generate(key, u'Вы сказали '+result+u'Скажите да или Нет', file+'.mp3')
        agi.set_variable('audio', file)
    except:
        agi.set_variable('audio', '/var/lib/asterisk/sounds/custom/enteraccount')
        agi.set_variable('label', '0')
        agi.verbose('label=0')

elif sys.argv[2].replace(' ','')=="2":
    agi.verbose('label='+sys.argv[2].replace(' ',''))
    try:
        result=yadexASR(uuid, key, 'notes', sys.argv[1]+'label'+sys.argv[2].replace(' ',''))
    except:
        agi.set_variable('label', '1')
    if 'Да' in str(result.encode('utf-8')):
        agi.verbose('Yes')
        #///////////////////////////////
        # Здест должна быть проверка на существование абонента в базе данных
        #/////////////////////////////
    
        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')
        generate(key, u'Показания какого счетчика вы хотите сообщить горячего или холодного?', file+'.mp3')
        agi.set_variable('audio', file)
    elif 'Нет' in str(result.encode('utf-8')):
        agi.verbose('No')
        # Ставим метку в 0 что бы вернуться к шагй 1 и проигрываем файл
        agi.set_variable('label', '0')
        agi.set_variable('audio', '/var/lib/asterisk/sounds/custom/enteraccount')
    else:
        agi.verbose('Error')
        # Если ответ не да и ни нет, говорим об ошибки и ставим метку на 1 что бы вернуться к шагу 2
        agi.set_variable('label', '1')
elif sys.argv[2].replace(' ','')=="3":
    agi.verbose('label='+sys.argv[2].replace(' ',''))
    try:
        result=yadexASR(uuid, key, 'notes', sys.argv[1]+'label'+sys.argv[2].replace(' ',''))
    except:
        agi.set_variable('label', '2')
    if 'Горяч' in str(result.encode('utf-8')):
        agi.verbose('Hot')      
        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')
        generate(key, u'Сообщите показания горячего счетчика', file+'.mp3')
        agi.set_variable('audio', file)
    elif 'Холод' in str(result.encode('utf-8')):
        agi.verbose('Cold')     
        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')
        generate(key, u'Сообщите показания холодного счетчика', file+'.mp3')
        agi.set_variable('audio', file)
    else:
        agi.verbose('Error')
        agi.set_variable('label', '2')
elif sys.argv[2].replace(' ','')=="4":
    agi.verbose('label='+sys.argv[2].replace(' ',''))
    try:
        result=yadexASR(uuid, key, 'notes', sys.argv[1]+'label'+sys.argv[2].replace(' ',''))      
        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')
        generate(key, u'Ваши показания '+result+u'Скажите да или Нет', file+'.mp3')
        agi.set_variable('audio', file)
    except:
        agi.set_variable('label', '3')
        agi.verbose('label=3')
elif sys.argv[2].replace(' ','')=="5":
    try:
        result=yadexASR(uuid, key, 'notes', sys.argv[1]+'label'+sys.argv[2].replace(' ',''))
    except:
        agi.set_variable('label', '1')
    if 'Да' in str(result.encode('utf-8')):
        
        #/////////////
        #Обрабатываем результат и заносим в базу
        #/////////////
 
        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')
        generate(key, u'Хотите сообщить показания другого счетчика да или нет?', file+'.mp3')
        agi.set_variable('audio', file)
    elif 'Нет' in str(result.encode('utf-8')):
        agi.set_variable('label', '2')
        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')
        generate(key, u'Показания какого счетчика вы хотите сообщить горячего или холодного?', file+'.mp3')
        agi.set_variable('audio', file)
    else:
        agi.verbose('Error')
        agi.set_variable('label', '2')
elif sys.argv[2].replace(' ','')=="6":
    try:
        result=yadexASR(uuid, key, 'notes', sys.argv[1]+'label'+sys.argv[2].replace(' ',''))
    except:
        agi.set_variable('label', '1')
    if 'Да' in str(result.encode('utf-8')):
        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')
        generate(key, u'Показания какого счетчика вы хотите сообщить горячего или холодного?', file+'.mp3')
        agi.set_variable('audio', file)
        agi.set_variable('label', '2')
    elif 'Нет' in str(result.encode('utf-8')):
        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')
        generate(key, u'Досвидания', file+'.mp3')
        agi.set_variable('audio', file)
    else:
        agi.verbose('Error')
        file=sys.argv[1]+'outlabel'+sys.argv[2].replace(' ','')
        generate(key, u'Хотите сообщить показания другого счетчика да или нет', file+'.mp3')
        agi.set_variable('label', '5')

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

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!:

ИТ Проффи

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: