На просторах интернета представлены различные реализации, но, на мой взгляд, все они достаточно простые. Хочу представить свой вариант голосового справочника под астериск. Примечание: я не являюсь профессиональным программистом, и, возможно, некоторые решения могут показаться вам дикими. Некоторые приемы могут быть устаревшими. Я готов принять критику и исправить систему к лучшему. Краткое описание возможностей: Пользователь попадает в IVR, произносит свой запрос и, в большинстве случаев, попадает туда, куда ему надо. К системе также прикручена статистика с записью в таблицу mysql.
Коротко о компании и сети, в которой развернута данная система:
~1000 телефонов, около 50 отделов Программные продукты, используемые системой: Описание диалплана в астериск. В данном фрагменте запускается макрос проверки того, бросил ли звонивший трубку едва услышав приветственное сообщение. Далее идет установка значения переменных:
ITERATIONS — необходима для повтора процесса распознавания заданного количества раз. HANGFLAG – данная переменная используется макросом hangercheck. Устанавливаем переменную файла записи, записываем файл. Запускаем agi-скрипт, отвечающий за отправку файла на распознавание и поиск номера (описание скрипта будет дано далее), проверка переменной NUMTOCALL (значение устанавливается скриптом), ставим признак HANGFLAG, означающий, что человек не бросил трубку раньше времени. В данном фрагменте запускается Макрос проверки факта того, бросил ли звонивший трубку едва услышав приветственное сообщение, далее идет установка значения переменных, ITERATIONS — необходима для повтора процесса распознавания заданного количества раз. HANGFLAG – данная переменная используется макросом hangercheck. Устанавливаем переменную файла записи, записываем файл. Запускаем скрипт, отвечающий за отправку файла на распознавание и поиск номера (описание скрипта будет ниже), проверка переменной NUMTOCALL (значение устанавливается скриптом), ставим признак HANGFLAG, что человек не бросил трубку раньше времени. Запуск макроса vrstat (отвечает за статистику, описан не будет ввиду своей тривиальности). Проверяем есть ли описание FNAME (переменную задает pyreq8.py) у запроса. Если описание есть, задаем в переменную имя файла кеша и проверяем его наличие. Если файл не существует – синтезируем его, конвертируем в mp3, увеличиваем громкость и, далее(или если кеш существует), проигрываем его и вызываем абонента. Повторение распознавания. Если количество итераций превышает заданное, то переводим на секретарей. Перевод на секретарей. Заносим в статистику, устанавливаем флаг, что трубку не бросили. Вызываем секретаря. Вызов абонента, у которого отсутствует описание в справочнике. Проигрываем сообщение, заносим в статистику, вызываем. Обработка окончания вызова для работы макроса hangercheck.  Описание диалплана. Макросы. Проверяем в базе статистики, звонил ли данный номер последние 48 часов, и, если он вешал трубку не дождавшись окончания распознавания – заносим в статистику и соединяем с секретарем. Краткое описание используемых sql и mysql таблиц. Sql таблица dbo.phrases. id(PK, int), phrase (text), number(varchar(50)) Для данной таблицы поднят полнотекстовый поиск, используется для переключения по ключевым словам при получении длинной фразы. Например поступила фраза: «соедините меня пожалуйста с представителем рекламного отдела», если в бд есть запись, где phrase= «рекламный отдел», то звонящего соединится с соответствующим номером(number). Mysql таблица recogStats. id(PK, int), date (datetime), ctime(float), rtime(float),stime(float), phrase(varchar(60)) Данная таблица используется для хранения результатов распознавания и сбора статистики по времени распознавания. ctime – время затраченное на конвертацию аудио файла, rtime – время затраченное на загрузку и распознавание, stime – время затраченное на поиск  Mysql таблица ivr_stat. id(PK, int), calldate (datetime),clid(varchar(15)),duration(int(20)),callednum(varchar(10)),rstatus(varchar(20)),channame(varchar30)),RECREZ(varchar(200)) Данная таблица используется для ведения учета результатов распознавания(RECREZ,rstatus), на кого ушел звонящий по результатам поиска распознанной фразы(callednum), для ведения статистики, сколько времени провел человек в меню распознавания(duration) и для отладки(channame) Mysql таблица CustomRequests. id(PK, int), nomer(int(10)), request(varchar(100))
Вспомогательный справочник дополнительных групп и отделов. Mysql таблица numdescriptions. Num(text), name(text) Справочник c описанием внесенного номера для озвучки. Mysql таблицы spravochnik_rus и spravochnik_rus_name_num_no_tops nomer(varchar(11)), fio(varchar(100)) Справочники персон с номерами. Первый — полный, для внутреннего использования. У второго, для внешнего использования, номера директоров и руководителей завернуты на секретариат. AGI скрипт осуществляющий конвертацию, отправку и поиск распознанной фразы. Используемые библиотеки: А также библиотека asterisk.agi, которую импортируем в зависимости от отладки(отладка производится на windows машине). Описание переменных. Флаг отладки. Переменная скомпилированного регулярного выражения на цифры. Переменная уникального идентификатора. API-ключ яндекс speech kit. Опция языка для яндекс speechkit. Опция темы распознавания для яндекс speechkit. Номер для вызова по умолчанию. Установка номера для вызова по умолчанию, в случае, если что-нибудь пойдет не так. Словарь ФИО – номер. Словарь ФИ — номер. Словарь Фамилия – номер. Словарь с прочими записями вида Запись – номер. Словарь с описаниями для генерации озвучки, вид Запись – номер. Служебный список для фильтрации дублей. Список со всеми внутренними номерами. Переменная временного выходного аудио файла. Реквизиты для подключения к mysql и mssql. Импорт библиотеки, установка переменной имени входного аудиофайла и номера звонящего в зависимости от отладки. Описание функций В зависимости от значения переменной отладки, выводим сообщения в консоль asterisk или в stdout. В зависимости от значения переменной отладки присваиваем значение переменной диалплана в астериск или выводим в stdout. Проверка содержит ли s цифры. Возвращаем из s только цифры. Проверка существования добавочного номера в списке nums. Функция установки добавочного номера. Проверка полученного файла аудио-записи для распознавания, если размер слишком маленький, полагаем, что в трубку молчали. Функция записи статистики распознавания. Данная функция заполняет словари Фамилий(persondicF), Фамилий Имен(persondicFI), ФИО(persondic), названий отделов(otherdic), описаний для синтеза речи(descriptions) и всех номеров компании(nums).
В зависимости от длины номера звонящего берется таблица, где содержатся номера директоров(внутренний звонящий) или не содержит(внешний звонящий).
Справочник фамилий проходит проверку на уникальность, чтобы исключить наличие в нем двух Ивановых с разными номерами. Функция конвертации записанного в астериске файла, в случае, если sox выдает ошибку, устанавливаем номер по умолчанию и выходим из скрипта. Функция отправки файла на распознавание и получения ответа от яндекса. В случае, если распознавание удалось, берем первый ответ. С библиотекой curl мне такое провернуть не удалось, по этой причине используется такой вариант. Функция поиска полного ФИО в зависимости от того, пришла ли на вход только фамилия или фамилия и имя. Функция поиска комбинаций, пример: phrase = «Алексей Петр», в pdic содержится запись «Алексеев Пётр», функция get_close_matches вернет «Алексеев Пётр». Функция может выдавать и неправильные результаты, но, как показала практика, корректных срабатываний значительно больше. Параметр quality позволяет задать точность поиска похожих фраз. Основная функция поиска номера по фразе. Разберем эту функцию по частям. Пример: на фразу «Пожалуйста добавочный 1234» вернет добавочный номер (если он есть). В случае, если пользователь произнес четырёхзначный номер – вернуть соответствующий добавочный (если он есть). Чтобы не делать лишние прогоны программы по коротким фразам (такое может случиться, когда яндекс услышал и распознал часть разговора, когда звонящий не слушал сообщение о распознавании). По длинным фразам(более пяти слов) мы сразу обращаемся к FT базе mssql. Если распознанная фраза состоит из одного слова, сперва смотрим FT базу данных, при точности совпадения в 80%, ищем описание распознанного номера, выставляем переменную результата и переменную статуса номерного плана, иначе производим поиск похожих слов в словаре фамилий. Если фраза состоит из двух слов, полагаем, что это фамилия и имя.
Составляем список комбинаций (иванов иван, иван иванов) и ищем похожие совпадения. В случае получения фразы из трёх слов, полагаем что это ФИО, составляем список комбинаций и ищем в словаре с ФИО. Возвращаем result если переменная не пуста. В случае, если мы не нашли совпадений, делаем поиск в FT базе данных, в случае нахождения соответствия возвращаем результат и описание, иначе – возвращаем номер по умолчанию и ставим статус о том, что фраза не найдена. Основное тело программы. Запускается функция заполнения словарей, если не находимся в отладке программы — заполняем переменные таймеров, проверяем размер файла, конвертируем, отправляем на распознавание, иначе – заполняем переменную checkstring проверочной фразой.
Далее, заполняем переменные таймеров для распознавания, проводим поиск фразы в нашей структуре. И, в случае боевого функционирования, устанавливаем переменную для номерного плана и заносим статистику. Немного статистики. Июнь 2018:
успешное распознавание — 1010
молчали в трубку — 78
распознавание не удалось (совпадение не найдено) — 79
короткий запрос — 4
распознанный департамент — 7
среднее время распознавания(среднее время ответа яндекса) — 2.6 сек Июнь 2017:
успешное распознавание — 1271
распознанный департамент — 18
распознавание не удалось (совпадение не найдено) — 127
короткий запрос — 9
молчали в трубку — 71
среднее время распознавания(среднее время ответа яндекса) — 1.5 сек Данный сервис успешно используется в компании, где я работаю. Надеюсь мои наработки помогут другим людям в реализации своих идей или подобного функционала. Готов ответить на все вопросы.