среда, 21 декабря 2016 г.

Cisco IOS IVR с помощью VXML

Cisco IOS IVR с помощью VXML

Давайте напишем VXML-скрипт, который будет работать на голосовом шлюзе Cisco в качестве IVR по приведенной схеме.
Алгоритм работы: при звонке на 2100 проиграть файл (Нажмите 1, 2 или 3). Если звонящий ничего не нажимает или нажимает, но не то – проигрываем приглашение снова и терпеливо ждем адекватных действий со стороны звонящего.
Если нажали 1, то переводим звонок на номер 9991, если 2, то предлагаем набрать внутренний номер абонента (четыре цифры, начинающиеся с 2 или 3), ну а если 3, то разрываем соединение, не забыв предварительно попрощаться.

Начало скрипта простое до неприличия:
<?xml version="1.0" encoding="UTF-8"?>
<vxml version = "2.1" >

<var name="DestNumber"/> <!-- Variable used to carry the destination number -->
Рассказали о себе (скрипте) и объявили переменную DestNumber, которую будем использовать для перевода звонков на внутренний номер.

В качестве эксперимента создал отдельную форму (form), которая используется только для проигрывания приветствия, которое нельзя "перебивать" вводом DTMF и переходом к следующей форме (id="Main").
<form id="Start">
 <block>
  <prompt bargein="false"><!-- You cannot interrupt this prompt -->
   <audio src="tftp://192.168.2.213/quickstart/audio/welcome.au"/>
  </prompt>
  <goto next="#Main"/><!-- Goto оно и в Африке Goto -->
 </block>
</form>
id тега <form> используется для переходов с помощью Goto. Параметр bargein="false" тега <prompt> запрещаете (false) или разрешает (true) прерывать проигрывание аудио-файлов вводом DTMF.
В качестве места хранения голосовых сообщений использовал TFTP, чтобы не копировать все файлы на лабораторный маршрутизатор. Следует учитывать задержку на копирование по TFTP при первом проигрывании, а также то, что роутер кэширует файлик у себя (в RAM?) и при замене файла на стороне TFTP-сервера, роутер просто так перекачивать файлик не будет (если знаете как сбросить такой кэш для того, чтобы роутер перезалил файл – напишите, пожалуйста в комментариях).

Очень полезно дебажить скрипт командой
debug voip application vxml error

Ниже приведен вывод дебага, когда я использовал тег <prompt> сразу после тега <form>, методом наблюдения за другими скриптами оказалось, что в этом случаем <prompt> нужно "обернуть" с помощью <block> (пример выше).
Lab_BB1_CME(config-app-param)#do deb voip app vxml erro
vxml software & call error debugging are on

Lab_BB1_CME(config-app-param)#
Feb  1 10:53:38.966: //0/77A7A02681C2/VXML:/vxml_start_element_handler:  
   CALL_ERROR; tftp://192.168.2.213/hello.vxml
   at line 8: Element <prompt> is not used according to DTD
Feb  1 10:53:38.970: //-1//VXML:/vxml_create:  
   CALL_ERROR; code=ERROR vapp=VAPP_SUCCESS vxml=
Lab_BB1_CME(config-app-param)#

Итак, повторим корректную структуру для проигрывания голосового приветствия:
<form>
 <block>
  <prompt>
   <audio/>
  </prompt>
 </block>
</form>

Теперь посмотрим на структуру VXML-скрипта для интерактивного диалога с пользователем:
<form>
 <field>
  <grammar></grammar><!-- Здесь будут описываться RegExp'ы -->

  <noinput>
   <!-- Пользователь ничего не ввёл -->
  </noinput>

  <nomatch>
   <!-- Пользователь брутфорсит -->
  </nomatch>

  <prompt>
   <!-- Расскажем пользователю что делать -->
   <audio/>
  </prompt>
  
  <filled>
   <!-- Обрабатываем ввод пользователя -->
  </filled>
 </field>
</form>

Короткий пример того, как при вводе цифры 1, 2 или 3 происходит присвоение значения переменной и переход к другой форме (TransferToDestNumber):
<form id="Main">
 <field name="getdigit" type="digits?length=1"><!-- Expect one digit to be entered -->
  <grammar type="application/grammar+regex">[123]</grammar><!-- Expect 1, 2, or 3 as user input -->
  <filled> <!-- Right digits were caught -->
   <assign name="DestNumber" expr="'phone://9991'"/>
   <goto next="#TransferToDestNumber"/>
  </filled>
 </field>
</form>

Осталось посмотреть на форму, которая используется для перевода звонка на внутренний номер:
<form id="TransferToDestNumber">
 <transfer connecttimeout="20s" name="mycall"  destexpr="DestNumber" bridge="false"> </transfer>
 <block>
  <prompt bargein="true">
   <audio src="tftp://192.168.2.213/quickstart/audio/busy.au" caching="fast"/>
   <audio src="tftp://192.168.2.213/quickstart/audio/goodbye.au" caching="fast"/>
  </prompt>
  <disconnect/>
 </block>
</form>

И тут (барабанная дробь) на сцене появляется завершающая часть скрипта :)
</vxml>

Скрипт целиком

Нажав на кнопку вы сможете просмотреть мой лабораторный скрипт целиком:


А теперь закономерный вопрос: что же делать с этим скриптом?

Ответ: нужно скопировать скрипт и все прилагающиеся аудио-файлы на flash голосового шлюза и "привязать" скрипт к dial-peer.
Есть много примеров того, как привязать VXML-скрипт к dial-peer типа POTS, но вот как быть, если в моём распоряжении вообще нет аналоговых портов? Оказалось, что можно привязать и к dial-peer типа VOIP.

Конфигурация для случая с dial-peer типа VOIP: 
!
application
 service NAME_OF_SERVICE flash:/vxml_script.vxml
!
dial-peer voice 1 voip
 service NAME_OF_SERVICE out-bound
 destination-patter ^2100$
 session target ipv4:1.1.1.1
Session target можно указать любой, он нужен только для того, чтобы этот outbound dial-peer пришел в состояние UP.

Немного ссылок:

Cisco IOS Tcl IVR and VoiceXML Application Guide - 12.3(14)T and later (Outbound Voice Applications)
Cisco IOS VoiceXML Quick Start Guide
Voice Gateway API (VGAPI) Developer Center (можно скачать Sample Scripts для QSG)
Cisco IOS Voice Troubleshooting and Monitoring -- Cisco VoiceXML Troubleshooting
VoiceXML Development Guide
Cisco VoiceXML Programmer's Guide

Простейшее голосовое меню на Cisco VoiceXML
VXML IVR на IOS гейтвее
Простой IVR или автоответчик на маршрутизаторе

P.S.

Получилось немного сумбурно и не последовательно, но если будет время, то я постараюсь реорганизовать материал для более удобного усвоения.

Всем успехов! :)

А напоследок небольшое видео (4,2 МБ) с попыткой объяснением алгоритма работы скрипта (удачно или нет, решать Вам, уважаемые читатели):

Комментариев нет:

Отправить комментарий