Добрый день, уважаемые читатели.
Хочу поделиться своим примером создания голосового меню для Asterisk при помощи Perl AGI.
После прочтения статьи Голосовое дерево на Asterisk своими руками у меня возникло несколько замечаний к предложенному в этой статье методу реализации голосового меню.
Основная моя претензия сводится к тому, что позвонивший абонент вынужден выслушать меню до конца, а лишь затем мы позволим ему нажать одну из предложенных клавиш. Если же он ошибётся, нажав не ту клавишу, то ему придётся слушать меню ещё раз.
Как мне кажется, абоненту это быстро надоест.
Также в компанию часто звонят люди, которые уже знают внутренний номер сотрудника. Нужно дать им возможность набрать номер, не дожидаясь окончания голосового меню.
Кроме того, почти стандартом является нажатие клавиши «ноль» для вызова секретаря.
Если абонент не желает слушать меню, а хочет сразу поговорить с секретарём — я считаю, мы можем ему это позволить.
Остальное опишу в приведённом примере.
У меня Asterisk работает на FreeBSD. Поэтому пути, которые я буду указывать в дальнейшем, у вас могут отличаться.
Я предполагаю, что Asterisk у вас уже установлен.
Также потребуется установленный Perl и модуль Asterisk:AGI
Не стану долго здесь описывать установку, просто добавлю, что если Perl уже установлен, то Asterisk:AGI устанавливается одной командой:
cpan -i Asterisk:AGI
После чего мы можем использовать его в своих скриптах.
Итак, вот фрагменты из конфигурационных файлов Asterisk:
extensions.conf
[default]
exten => 84951223344,1,Macro(call-in,${EXTEN}) ; Входящие звонки направляются в макрос call-in
exten => _X.,1,Hangup ;
Макрос я применяю для дополнительной обработки входящего звонка перед соединением. Вы же вполне можете обойтись без него.
[macro-call-in]
exten => s,1(agi),AGI(ivr.pl) ; Здесь входящий звонок передаётся на обработку Perl-скрипту.
/usr/local/share/asterisk/agi-bin/ivr.pl
#!/usr/bin/perl
use Asterisk::AGI;
$AGI = new Asterisk::AGI;
%input = $AGI->ReadParse();
$timeout = 1300;
# Таймаут для нажатия клавиши. Определяется экспериментальным путём.
# При меньшем значении звонящие могут не успеть набрать номер.
# Отвечаем на звонок
$AGI->answer();
# Начинаем собирать номер из вводимых пользователем цифр
# Проигрываем файл голосового меню
$key1 = $AGI->stream_file(["ivr"], "0123456789"); # Здесь указываются клавиши, нажатие которых прерывает воспроизведение файла.
# Я указал все клавиши, кроме * и # (их тоже можно использовать в меню).
$key2 = $AGI->wait_for_digit($timeout);
$key3 = $AGI->wait_for_digit($timeout);
$key4 = $AGI->wait_for_digit($timeout);
# Последовательно ожидаем нажатия клавиш (у меня в компании четырёхзначные номера).
$num = join ('', chr($key1), chr($key2), chr($key3), chr($key4));
# Преобразуем коды клавиш в числа, складываем числа в номер.
# Сейчас это не число, а строка символов.
$num = $num + 0;
# Здесь мы превратим строку в число.
if ( $key1 == 0 ) { $num = 0 }
# Если код первой клавиши равен нулю, значит пользователь прослушал меню целиком, и ничего не нажал.
# Отправляем звонок оператору.
# Выведем сообщение в консоль Asterisk (пригодится для отладки).
$AGI->verbose("IVR number is $num");
# Если набран четырехзначный номер - переводим звонок на внутреннего абонента.
if (length($num) = 4) {
$AGI->exec("Macro","call-local,Local/$num@office"); # Звонок будет направлен абоненту из контекста office. Пример макроса call-local см. ниже
$AGI->hangup();
}
# Если произошла ошибка при наборе, звонок переводим на оператора.
# Здесь можно прикрутить и другие обработки ошибок, но мне хватило и этого.
elsif (length($num) > 1) { $num = 0; }
# Ниже идут обработки клавиш меню
if ($num == 0) { $AGI->exec("Macro", "operator"); }
if ($num == 1) { $AGI->exec("Macro", "sale"); }
if ($num == 2) { $AGI->exec("Macro", "accounting"); }
if ($num == 3) { $AGI->exec("Macro", "marketing"); }
if ($num == 4) { $AGI->exec("Macro", "fax"); }
Далее звонки направляются в соответствующие макросы.
Примеры макросов:
Звонок в отдел маркетинга:
extensions.conf
[macro-marketing]
exten => s,1,Dial(SIP/1008,20,tTm)
Звонок внутреннему абоненту:
extensions.conf
[macro-call-local]
exten => s,1,Dial(${ARG1},25,tTm)
Вот и всё.
Может быть предложенный метод покажется вам излишне сложным.
Однако, мне нравится держать всю логику работы IVR в отдельном файле.
Также меню легко можно дополнять, добавлять подменю (путём создания дополнительных скриптов).
Помимо этого, я использую AGI в некоторых дополнительных скриптах ( для обработки пропущенных вызовов, переадресации на мобильные и др.), поэтому мне было удобно использовать его для голосового меню.
Спасибо за внимание.
Автор: jkreet