Создание IVR на базе Астериск, с распознаванием DTMF и имён сотрудников (на базе Voicer от уважаемого antirek) и подключение к существующей АТС.
Наступающий новый год принёс в компанию, где я работаю, (не)радостную весть — умер древний сервер с системой IVR и PCI-платой на 4 аналоговых порта от Dialogic. Внезапно выяснилось, что современные системы не имеют PCI слотов, старые — не дружат с новыми версиями ОС и неизвестно сколько проживут, а лицензия имеется лишь на конкретную старую версию программы.
Так родилась идея поднять IVR без платы (и бесплатно) на виртуальной машине с Asterisk.
Итого, нам потребуются:
Если все пункты успешно выполнены — можно приступать. Первым делом стоит поставить сам asterisk, голосовые подсказки для теста, а также nodejs и npm.
Далее нам потребуется сам сервис распознавания voicer и process manager для его запуска:
Создадим папки и конфигурацию для voicer:
И запишем конфигурацию в файл /etc/voicer/config.js, добавив туда свои логин/пароль и ключ (developer_key) к желаемому сервису. В моём случае был выбран wit.ai — бесплатен, достаточно точен для наших задач.
Далее нам понадобится создать сервис для запуска voicer. Это будет файл /etc/init.d/voicer:
Ну и активировать его:
При этом надо учесть, что voicer будет складывать записанные файлы в папку /tmp и было бы её неплохо периодически чистить. Создаём простой скрипт для этого и складываем его в /etc/cron.daily
Ну а теперь осталась более сложная часть — настроить сам asterisk. Поскольку АТС у нас уже есть и все клиенты используют её, то большая часть конфигурации нам не нужна. Удаляем (или сохраняем в тёмное прохладное сухое место — по желанию) из папки /etc/asterisk всё, кроме asterisk.conf, modules.conf и sip.conf. И дописываем конфигурацию sip.conf следующими строками, добавив нужные нам значения для:
Тут стоит обратить внимание на то, в каком режиме работают dtmf команды в вашей АТС. Учтите, что они могут обрабатываться разными методами для внешних вызовов АТС (например — из города, или с мобильного телефона) и внутренних звонков между абонентами вашей АТС. В моём случае, в первом варианте это были inband dtmf сигналы, во втором — rfc2833. Но auto с этим справился. Также вас могут ожидать интересные особенности взаимодействия именно с вашей АТС — придётся на личном опыте выяснить, что требуется, например, для сохранения АОН вызывающего (внешнего) абонента при возврате звонка с IVR на АТС (строка sendrpid).
И остался ещё один конфигурационный файл. Самый важный. Dialplan, он же extensions.conf. В нём вам обязательно нужно указать ваш внешний номер (на который будут звонить люди), номер секретаря (на который уйдут звонки по умолчанию) и пути до ваших голосовых подсказок.
В данном примере используются записи с приветствием, именами сотрудников и фраза «соединяю вас». При этом подсказка для сотрудника ищется по его номеру, а если её нет произносится просто «с сотрудником». Подобные подсказки рекомендую заказать студии — системы синтеза речи, увы, не совершенны и их произношение названия вашей компании и фамилий сотрудников годится лишь для развлечения. 40XX — номера в компании, 4001 — секретарь.
Особенность данной ситуации в том, что у нас звонками занимается именно АТС. Таким образом, мы вместо обычной команды Dial используем команду Transfer — и тогда входящий звонок после IVR полностью уходит с asterisk и освобождает sip каналы АТС (их количество часто жёстко зафиксировано лицензией). В большинстве случаев в команде Transfer советуют использовать название направления (main_link), но для моей АТС подошло только прямое указание адреса станции.
Пришло время добавить пользователей для системы распознавания. Для этого заходим на адрес нашего сервера и порт 3100, после чего прописываем там имена, фамилии и номера сотрудников.
Теперь наш астериск умеет получать входящие звонки, распознавать DTMF сигналы, распознавать имена сотрудников и перенаправлять на их внутренние номера. Осталось лишь убедить станцию, что ей нужно отправлять входящие звонки на наш сервер. В зависимости от производителя эти настройки могут быть абсолютно разнообразны, но желаемый путь будет содержать слова ARS и маршрутизация звонков. Но это уже совсем другая история.
Наступающий новый год принёс в компанию, где я работаю, (не)радостную весть — умер древний сервер с системой IVR и PCI-платой на 4 аналоговых порта от Dialogic. Внезапно выяснилось, что современные системы не имеют PCI слотов, старые — не дружат с новыми версиями ОС и неизвестно сколько проживут, а лицензия имеется лишь на конкретную старую версию программы.
Так родилась идея поднять IVR без платы (и бесплатно) на виртуальной машине с Asterisk.
Итого, нам потребуются:
- Существующая АТС с абонентами
- Виртуальная машина (в примере — ubuntu 18.04 lts).
- Регистрация на каком-либо из сервисов распознавания голоса: wit.ai, google или яндекс
- Минимальное знание линукс систем
- Желание разобраться с Астериск
Если все пункты успешно выполнены — можно приступать. Первым делом стоит поставить сам asterisk, голосовые подсказки для теста, а также nodejs и npm.
apt install nodejs asterisk npm asterisk-core-sounds-ru-gsm
Далее нам потребуется сам сервис распознавания voicer и process manager для его запуска:
npm install voicer -g
npm install pm2 -g
Создадим папки и конфигурацию для voicer:
mkdir -p /etc/voicer/data
И запишем конфигурацию в файл /etc/voicer/config.js, добавив туда свои логин/пароль и ключ (developer_key) к желаемому сервису. В моём случае был выбран wit.ai — бесплатен, достаточно точен для наших задач.
module.exports = {
agi: {
port: 3000
},
web: {
port: 3100,
auth: true,
username: 'ИМЯ_ПОЛЬЗОВАТЕЛЯ',
password: 'ПАРОЛЬ_ПОЛЬЗОВАТЕЛЯ',
realm: 'НАЗВАНИЕ_КОМПАНИИ'
},
processing: {
totalAttempts: 2,
playGreeting: true,
playBeepBeforeRecording: false //use system beep
},
asterisk: {
sounds: {
onErrorBeforeFinish: 'invalid',
onErrorBeforeRepeat: 'invalid',
greeting: 'beep'
},
recognitionDialplanVars: {
status: 'RECOGNITION_RESULT',
target: 'RECOGNITION_TARGET'
}
},
record: {
directory: '/tmp',
type: 'wav',
duration: 3,
},
recognize: {
directory: '/tmp',
type: 'witai', // ['yandex', 'google', 'witai']
options: {
developer_key: 'XXXXXXXXXXXXXXXXXXX'
}
},
lookup: {
type: 'file',
options: {
dataFile: '/etc/voicer/data/peernames.json'
}
},
logger: {
console: {
colorize: true
},
file: {
filename: '/var/log/voicer.log',
json: false
}
}
};
Далее нам понадобится создать сервис для запуска voicer. Это будет файл /etc/init.d/voicer:
#!/bin/sh
### BEGIN INIT INFO
# Provides: voicer
# Required-Start: $network $syslog $named
# Required-Stop: $network $syslog $named
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start/stop voicer
### END INIT INFO
set -e
if [ -z "$1" ] ; then
echo "Usage: $0 [start|stop|restart]"
exit 0
fi
if [ "$1" = "start" ] ; then
VOICER_CONFIGFILE=/etc/voicer/config pm2 start voicer
elif [ "$1" = "stop" ] ; then
pm2 stop voicer
elif [ "$1" = "restart" ] ; then
$0 stop
sleep 5
$0 start
fi
Ну и активировать его:
systemctl daemon-reload
systemctl enable voicer
systemctl start voicer
При этом надо учесть, что voicer будет складывать записанные файлы в папку /tmp и было бы её неплохо периодически чистить. Создаём простой скрипт для этого и складываем его в /etc/cron.daily
#!/bin/sh
rm /tmp/*.wav
Ну а теперь осталась более сложная часть — настроить сам asterisk. Поскольку АТС у нас уже есть и все клиенты используют её, то большая часть конфигурации нам не нужна. Удаляем (или сохраняем в тёмное прохладное сухое место — по желанию) из папки /etc/asterisk всё, кроме asterisk.conf, modules.conf и sip.conf. И дописываем конфигурацию sip.conf следующими строками, добавив нужные нам значения для:
- fromdomain — адрес сервера с астериск
- host — адрес АТС
- fromuser:secret и defaultuser:remotesecret — пары логин: пароль, которыми обменяются asterisk и АТС
[main_link]
fromdomain=xxx.xxx.xxx.xxx
host=xxx.xxx.xxx.yyy
insecure=port
port=5060
realm=asterisk
sendrpid=pai
fromuser=111
secret=111
defaultuser=222
remotesecret=222
qualify=yes
type=friend
disallow=all
allow=alaw
context=main_link
promiscredir=yes
dtmfmode=auto
Тут стоит обратить внимание на то, в каком режиме работают dtmf команды в вашей АТС. Учтите, что они могут обрабатываться разными методами для внешних вызовов АТС (например — из города, или с мобильного телефона) и внутренних звонков между абонентами вашей АТС. В моём случае, в первом варианте это были inband dtmf сигналы, во втором — rfc2833. Но auto с этим справился. Также вас могут ожидать интересные особенности взаимодействия именно с вашей АТС — придётся на личном опыте выяснить, что требуется, например, для сохранения АОН вызывающего (внешнего) абонента при возврате звонка с IVR на АТС (строка sendrpid).
И остался ещё один конфигурационный файл. Самый важный. Dialplan, он же extensions.conf. В нём вам обязательно нужно указать ваш внешний номер (на который будут звонить люди), номер секретаря (на который уйдут звонки по умолчанию) и пути до ваших голосовых подсказок.
[general]
static=yes
writeprotect=no
[globals]
[main_link]
exten => ВАШ_ВНЕШНИЙ_НОМЕР,1,Goto(ivr_tree,s,1)
[ivr_tree]
;allow direct dialing to internal users
exten => _40XX,1,Background(custom/common/SoedinyauVas)
;check user voice existance
same => n,Set(exists=${STAT(e,${ASTDATADIR}/sounds/custom/${EXTEN}.vox)})
same => n,Playback(custom/${IF($[ ${exists} = 1 ] ? ${EXTEN} : Sotrudnik)})
same => n,Transfer(SIP/${EXTEN}@АДРЕС_СТАНЦИИ)
;start intro
exten => s,1,Answer()
same => n,Set(CHANNEL(language)=ru)
same => n,Background(custom/common/Welcome)
;start recognition
same => n,AGI(agi://localhost:3000)
same => n,GotoIf($[${RECOGNITION_RESULT}=SUCCESS]?:default)
same => n,Background(custom/common/SoedinyauVas)
;check user voice existance
same => n,Set(exists=${STAT(e,${ASTDATADIR}/sounds/custom/${RECOGNITION_TARGET}.vox)})
;play user name or default name
same => n,Playback(custom/${IF($[ ${exists} = 1 ] ? ${RECOGNITION_TARGET} : Sotrudnik)})
same => n,Transfer(SIP/${RECOGNITION_TARGET}@АДРЕС_СТАНЦИИ)
same => n,Hangup()
;default route
same => n(default),Transfer(SIP/4001@АДРЕС_СТАНЦИИ)
В данном примере используются записи с приветствием, именами сотрудников и фраза «соединяю вас». При этом подсказка для сотрудника ищется по его номеру, а если её нет произносится просто «с сотрудником». Подобные подсказки рекомендую заказать студии — системы синтеза речи, увы, не совершенны и их произношение названия вашей компании и фамилий сотрудников годится лишь для развлечения. 40XX — номера в компании, 4001 — секретарь.
Особенность данной ситуации в том, что у нас звонками занимается именно АТС. Таким образом, мы вместо обычной команды Dial используем команду Transfer — и тогда входящий звонок после IVR полностью уходит с asterisk и освобождает sip каналы АТС (их количество часто жёстко зафиксировано лицензией). В большинстве случаев в команде Transfer советуют использовать название направления (main_link), но для моей АТС подошло только прямое указание адреса станции.
Пришло время добавить пользователей для системы распознавания. Для этого заходим на адрес нашего сервера и порт 3100, после чего прописываем там имена, фамилии и номера сотрудников.
Теперь наш астериск умеет получать входящие звонки, распознавать DTMF сигналы, распознавать имена сотрудников и перенаправлять на их внутренние номера. Осталось лишь убедить станцию, что ей нужно отправлять входящие звонки на наш сервер. В зависимости от производителя эти настройки могут быть абсолютно разнообразны, но желаемый путь будет содержать слова ARS и маршрутизация звонков. Но это уже совсем другая история.
Комментарии (6)
demonit
17.01.2019 21:27афигеть — это ж сколько это говнище от диалоджика проработало? я с такими еще 12 лет назад работал :)
DaemonGloom Автор
18.01.2019 07:3311 лет примерно. И дальше бы работало, но материнская плата подвела.
arheops
Несовершенны как раз системы распознавания.
А вот системы синтезирования, у того же гугла, слабо отличаются от средне-проффесиональных записей уже.
Недостаток данного подхода — голос распознается с задержкой от 3 секунд.
Более коректно исспользовать EAGI и google GRPC, распознается без задержки на лету.
DaemonGloom Автор
Обычно уходит примерно секунда на распознавание. Системы, которые распознают на лету, а не предварительно записывают удобны, но и стоят ощутимо больше при этом. При этом несут в себе всё те же задержки из-за интернета.
Как раз синтезирование гугла и пробовал. Синтез названия компании и некоторых фамилий вызывает желание посмеяться, но не желание использовать гугл для озвучивания фраз.
arheops
Секунда + время записи. Это если у пользователя нет шума. Если есть — ваш подход вообще не прекращает запись.
Google cloud recognition упомянутый вами в статье стоит одинаково в версии streaming и post.
DaemonGloom Автор
Не совсем так. Пишется указанное количество секунд и отправляется на сервер. В конкретном примере — 3 секунды. Этого хватает, чтобы назвать любого сотрудника.