Многие путают интерактивный автоответчик (Interactive Voice Response,IVR) с обычным автоответчиком (Automated Attendant, AA).Поскольку изначально IVR использовался как автоответчик, это неудивительно. Тем не менее понятие IVR в телефонии намного шире,чем просто автоответчик. AA является, так сказать, средством для перенаправления вызывающего абонента на добавочный номер и встроен в большинство узкоспециализированных систем голосовой почты.

Но функционал IVR может быть намного большим. Системы IVR обычно не просто дороги по цене, их конфигурирование очень трудоемко. Для специальной системы IVR обычно требуется возможность соединения с внешней базой данных или приложением. Asterisk – пожалуй, идеальный IVR, поскольку в ней заложена возможность соединения с базами данных и приложениями на самом глубоком уровне.

«Здравствуйте! Вас приветствует компания «Ваша компания»! Для получения информации коммерческого характера, нажмите цифру 1. Для связи с технической поддержкой, нажмите 2. Для соединения с сотрудником наберите его добавочный номер или дождитесь ответа оператора. Благодарим за звонок.» — Самый простой вариант использования возможности IVR Asterisk. Добавим некоторую логику в диалплан, чтобы он осуществлял разные действия на основании ввода пользователя.

Приложение Background() используется для создания голосовых меню (которые часто называют автоответчиками или интерактивными секретарями). Для того, чтобы Asterisk ожидала ввода номера абонента после завершения воспроизведения звукового сообщения, вызываем приложение WaitExten() (Ожидание добавочного номера). Добавочные номера -i и t, обрабатывают ошибочные действия абонента, при наборе неправильного номера или истечении тайм-аута. И это все? Конечно нет!

Можно даже создать небольшую математическую программу. Asterisk может представлять ряд математических вопросов, ответы на которые вводятся посредством номеронабирателя телефона. После ответа на все вопросы система сообщит оценку. Реализация такого предельно простого Asterisk-приложения в любой офисной АТС на закрытой платформе стоила бы десятки тысяч долларов, если вообще могла бы быть выполнена. Как это часто бывает, то, что просто для Asterisk, практически невозможно или чрезвычайно дорого в любой другой системе IVR.

Давайте рассмотрим пример реализации приложения, которое поможет нам вечером выбирать маршрут домой. На главной страничке сайта вы видите информер от Яндекс о загруженности дорог. Получим информацию о баллах от Asterisk. Что для этого необходимо?

Добавим в план нумерации необходимые данные.

Используем шлюзовой интерфейс Asterisk, предоставляющий стандартный интерфейс, посредством которого внешние программы могут управлять диалпланом Asterisk. Как правило, сценарии AGI используются для реализации расширенной логики, соединения с реляционными базами данных (такими, как PostgreSQL или MySQL) и доступа к другим внешним ресурсам. Таким образом набрав номер — 1111, мы запустим исполняемый файл «trf.sh». Сценарии AGI часто располагаются в папке AGI (которая обычно находится в папке /var/lib/asterisk/agi-bin), но можно указать и полный путь к сценарию AGI. AGI-программы могут быть реализованы практически на любом языке программирования. Чтобы не быть банальными, выберем не perl, и не php, и не python а shell.

  1. #!/bin/bash
  2. while read ARG && [ «$ARG» ] ;
  3. do
  4. echo $ARG 2 > /dev/null
  5. done
  6. checkresults() {
  7. while read msg
  8. do
  9. case ${msg:0:4} in
  10. «200 » ) echo $msg >&2
  11. return;;
  12. «510 » ) echo $msg >&2
  13. return;;
  14. «520 » ) echo $msg >&2
  15. return;;
  16. * ) echo $msg >&2;;
  17. esac
  18. done
  19. }
  20. wget -O trf http://www.yandex.ru/ 2 > /dev/null
  21. ball=`/bin/gawk -v RS=’>’ -v FS=’балл’ ‘ /балл/ {print $1 } ‘ trf`
  22. echo «STREAM FILE beep \»\»»
  23. checkresults
  24. echo «SAY NUMBER $ball \»\»»
  25. checkresults
  26. echo «STREAM FILE beep \»\»»
  27. checkresults
  28. echo «STREAM FILE vm-goodbye \»\»»
  29. checkresults
  30. exit 0

2-5 строки- необходимы для чтения переменных и их значений, передаваемых Asterisk в сценарий. Использовать нам их не надо, но прочитать необходимо обязательно.

6-19 строки- на каждую команду, передаваемую сценарием, Asterisk возвращает ответ, который сценарий AGI должен прочитать.

20 строка- получает содержимое странички Яндекс и записывает в файл — «trf». Выглядит это примерно так:

21 строка— собственно находит эти — 6 баллов. Остальные передают команды в Asterisk, для того чтобы абонент услышал полученную информацию.

В интерфейсе командной строки Asterisk есть очень полезная команда для отладки сценариев AGI, которая называется «agi set debug». Если ввести в консоли Asterisk «agi set debug on» и затем запустить AGI-сценарий, вы увидите нечто подобное:

Во время выполнения сценария AGI будут выведены строки трех типов. Первый тип – строки, начинающиеся с AGI TX >>. Это строки, которые Asterisk передает в STDIN нашей программы. Второй тип – строки, начинающиеся с AGI RX <<. Это команды, которые наша AGI-программа записывает в Asterisk через STDOUT. Третий тип – строки, начинающиеся с —. Это стандартные сообщения Asterisk, выводимые при выполнении определенных команд. Чтобы отключить отладку AGI после запуска, просто введите в консоли Asterisk «agi set debug off». Используя команду «agi set debug», можно увидеть взаимодействие между Asterisk и своей программой, что может быть очень полезным при отладке.

Вот и все — набрав определенный номер, в данном случае -1111, мы получаем любую информацию (опять же в нашем случае загруженность дорог в Москве в баллах), где бы она не находилась — в интернете, базе данных ….Возможно, если не нравится shell, то вот реализация на perl.

#!/usr/bin/perl
use strict;
use LWP::Simple;
$|=1;
my %AGI;
while(<STDIN>) {
        chomp;
        last unless length($_);
        if (/^agi_(\w+)\:\s+(.*)$/) {
                $AGI{$1} = $2;
        }
}
sub checkresult {
        my ($res) = @_;
        my $retval;
        chomp $res;
        if ($res =~ /^200/) {
                $res =~ /result=(-?\d+)/;
                if (!length($1)) {
                        print STDERR "FAIL ($res)\n";
                } else {
                        print STDERR "PASS ($1)\n";
                }
        } else {
                print STDERR "FAIL (unexpected result '$res')\n";
        }
}
my $page=get 'http://www.yandex.ru';
if $page =~ /"b-probki__icon"\S+(\d)/
{
print "STREAM FILE beep \"\"\n";
my $result =<STDIN> ;
&checkresult($result);
print "STREAM FILE $1 \"\"\n";
my $result =<STDIN> ;
&checkresult($result);
print "STREAM FILE beep \"\"\n";
my $result = <STDIN>;
&checkresult($result);