Поиск по этому блогу

понедельник, 13 июля 2015 г.

IVR на VXML скрипте в Cisco Router

Необходимо чтобы звонки на один из номеров компании попадали на голосовое меню.
Реализовано это будет на шлюзе - маршрутизаторе Cisco ISR 2911.
Первоначально скрипт должен проигрывать приветствие на 3 языках и предлагает выбрать на каком из трех языков предпочитает продолжить работу пользователь.

Например:
Вы дозвонились в Компанию. Для выбора русского языка нажмите 1.
You have reached Company. For English language press 2
Sie haben das Unternehmen erreicht. Die deutsche Sprache, und drücken Sie 3


В дальнейшем структура дерева остается одинаковой, просто меняются подгружаемые голосовые файлы.

Приветственный промпт сделан прерываемым, и также есть возможность сразу набрать внутренний номер сотрудника через 0. То есть если нужно позвонить сотруднику по номеру 300 не ожидая переходов IVR можно набрать 0300 и будет установлено соединение. Но данный вариант только для тех кто знает это правило набора.
<form id="Start">
<property name="timeout" value="3s"/>
 <block>
  <prompt bargein="true"> <!-- You can interrupt this prompt -->
   <audio src="flash:/prompt/in_welcome.wav"/> <!-- First greeting vibor yazika -->
  </prompt>
  <goto next="#Main"/><!-- Goto to Main Part dlya sbora cifer-->
 </block>
</form>
<form id="Main">
 <field name="getdigit" type="digits?length=1"><!-- Expect one digit to be entered -->
  <grammar type="application/grammar+regex">[0123]</grammar><!-- Expect 0, 1, 2 or 3 as user input -->
   <noinput count="1"><!-- 1 raz ne nabral-->
    <prompt bargein="true">
    <audio src="flash:/prompt/in_welcome.wav"/>
    </prompt>
   </noinput>
<noinput count="2"> <!-- 2 raz ne nabral otboy-->
    <disconnect/>
  </noinput>
  <nomatch count="1"><!-- Ne nabrali ni4ego -->
   <prompt bargein="true">
       <audio src="flash:/prompt/in_welcome.wav"/>
   </prompt>
  </nomatch>
  <nomatch count="2"><!-- 2 raz ne nabrali - disconnect-->
   <disconnect/>
   </nomatch>
   <filled>
    <if cond="getdigit=='0'"> <!-- Na donabor vnutrennego nomera -->
    <goto next="#IntNum" />
     <elseif cond="getdigit=='1'">  <!-- LANG1 language -->
     </elseif>
    <assign name="LANG1" expr="LANG1" />
    <goto next="#LANG1" />
   <elseif cond="getdigit=='2'"/>
    <assign name="LANG3" expr="LANG3"  />  <!-- LANG3 language -->
    <goto next="#LANG3" />
   <elseif cond="getdigit=='3'"/>
    <assign name="LANG2" expr="LANG2"  />  <!-- LANG2 language -->
    <goto next="#LANG2" />
    <else/>
      <prompt bargein="false">
   <audio src="flash:/prompt/in_welcome.wav"/> <!-- First greeting vibor yazika -->
  </prompt>
   </if>
  </filled>
 </field>
</form>

В блоке Main сначала проверяется что цифра будет только 1 и значение 0-3.
<field name="getdigit" type="digits?length=1">
<grammar type="application/grammar+regex">[0123]</grammar>
В случае неверного ввода цифры, или отсутствия ввода, после 1-го раза повторяется проигрывания промпта, после 2-го раза соединение сбрасывается скриптом.
После выбора языка сразу проигрывается дополнительное приветствие на выбранном языке, и затем происходит выбор одного из 2 сценариев, поступил звонок в рабочее время с 9 до 18 буднего дня, или в нерабочее время.
<form id="LANG1">
     <block>
         <prompt bargein="true">
                <audio src="flash:/prompt/LANG1_welcome.wav"/> <!--  greeting LANG1 language -->
          </prompt>
       <goto next="#LANG1_TimeCondition"/>
    </block>
  </form>

 <!-- Time condition -->
<form id="LANG1_TimeCondition">
    <block>
        <if cond="9 &lt;= VAR_Hour &amp;&amp; VAR_Hour &lt; 18 &amp;&amp; 0 &lt; VAR_Day &amp;&amp; VAR_Day &lt; 6">
            <goto next="#LANG1_Day" />
        <else />
            <goto next="#LANG1_Night" />
        </if>
    </block>
</form>

В нерабочее время можно сделать либо донабор внутреннего номера сотрудника либо дождаться перевода на голосовую почту оператора (332).

<!-- Nerabochee -->
<form id="LANG1_Night">
<block>
 <prompt>
<audio src="flash:/prompt/LANG1_out.wav"/>
 </prompt>
<goto next="#IntNum_out"/>
</block>
</form>
 <form id="IntNum_out">
 <field name="GetDigits" type="digits?length=3">
  <grammar type="application/grammar+regex">[0-5][0-9][0-9]</grammar>
  <noinput>
  <goto next="#oper_vm"/> <!-- perevod na VM operatora -->
  </noinput>
  <filled>
   <assign name="DestNumber" expr="'phone://' + GetDigits"/>
   <goto next="#TransferToDestNumber"/>
  </filled>
 </field>
</form>
<form id="oper_vm">  <!-- Perevod na Voice Mail Operatora -->
<transfer connecttimeout="20s" name="mycall"  dest="phone://332" bridge="false">
</transfer>
</form>

В рабочее время будет проигрываться промпт озвучивающий коды быстрого доступа, в случае неверного ввода или отсутствия ввода звонок будет переведен на оператора.

<form id="LANG1_Day">    <block>        <prompt>          <audio src="flash:/prompt/LANG1_worktime.wav"/>        </prompt>      <goto next="#LANG1_IVR"/>    </block>   </form>
<form id="LANG1_IVR"> <field name="getdigit" type="digits?length=1"><!-- Expect one digit to be entered -->  <grammar type="application/grammar+regex">[1234]</grammar><!-- Expect 1,2,3,4 as user input -->  <noinput>  <goto next="#operator"/>  </noinput> <nomatch count="1">    <prompt bargein="true">   <audio src="flash:/prompt/LANG1_worktime.wav" caching="fast"/>  </prompt>   </nomatch>   <nomatch count="2"><goto next="#operator"/>  </nomatch>  <filled>    <if cond="getdigit=='1'">      <assign name="DestNumber" expr="'phone://400'"/>      <goto next="#TransferToDestNumber"/>       <elseif cond="getdigit=='2'"/>      <assign name="DestNumber" expr="'phone://127'"/>      <goto next="#TransferToDestNumber"/>      <elseif cond="getdigit=='3'"/>      <assign name="DestNumber" expr="'phone://111'"/>      <goto next="#TransferToDestNumber"/>       <elseif cond="getdigit=='4'"/>       <goto next="#IntNum"/>   <else/>   </if>  </filled> </field></form>

Набор внутреннего номера:
 <form id="IntNum"> <field name="GetDigits" type="digits?length=3">  <grammar type="application/grammar+regex">[0-5][0-9][0-9]</grammar>  <noinput>  <goto next="#operator"/> <!-- perevod na operatora -->   </noinput>  <filled> <!-- Right digits were caught -->   <assign name="DestNumber" expr="'phone://' + GetDigits"/>   <goto next="#TransferToDestNumber"/>  </filled> </field></form>

Перевод на оператора на номер хант группы 333:
<form id="operator"><transfer connecttimeout="20s" name="mycall"  dest="phone://333" bridge="false"> </transfer></form>  
Одна особенность создания голосового ящика для номера Hunt Group оператора, заключается в том что нельзя создать голосовой ящик на виртуальный номер. Ящик может быть создан на пользователя, за которым закреплен определенный DN. Однако во внерабочее время все звонки должны попадать в голосовую почту операторов и которая должна быть доступна для всех операторов.
Вариантов есть 2- создать фейкового пользователя или назначить одному из членов Hunt Group (первому для работы индикатора оповещения) второй виртуальный номер внутри Unity.
В моем скрипте использован второй вариант. В дневное время все звонки на оператора падают на 333 номер. В нерабочее время на номер 332, который не закреплен ни за одним из телефонов в CUCM. Для него прописано перенаправление Forward All на VoiceMail.
На Cisco Unity же 332 ext. прописан как дополнительный для первого члена операторской Hunt Group. Также изменены настройки Call Handler для данного extention на Greeting.

Полностью скрипт

После написания скрипта, его и звуковые файлы нужно загрузить на flash маршрутизатора. Далее создать приложение для скрипта и  dial-peer с указанием нужного набранного номера на котором "поднимать трубку" будет скрипт:

application
service ivr flash:/prompt/script_ivr_lang.vxml

dial-peer voice 99 pots
 service ivr
 incoming called-number 2646999

Если скрипт был изменен то необходимо его перегрузить:
application
no service ivr flash:/prompt/script_ivr_lang.vxml
service ivr flash:/prompt/script_ivr_lang.vxml

Аудио файлы маршрутизатор загружает при первом прочтении в RAM и при замене голосового файла его также нужно перегрузить вручную:
audio-prompt load in_welcome.wav

Для отладки скрипта полезны команды:
debug voip dialpeer
debug voip application error

Информация:
http://blog.alakin.org/2013/02/vxml.html  - очень сильно помогло с начальным пониманием
http://vxml.ru/ - подробно и с примерами описана структура языка и операторы
Простой IVR или автоответчик на маршрутизаторе
Cisco IOS VoiceXML Quick Start Guide


2 комментария:

  1. Добрый день!

    не сталкивались с таким, что после набора внутреннего номера звонящий не слышит гудков (тишина), при это у внутреннего абонента телефон звонит?

    ОтветитьУдалить
  2. Добрый день,
    нет, КПВ присутствовал, очевидно вам надо проверить настройки транка между шлюзом и CUCM.

    ОтветитьУдалить

Ограничение количества MAC адресов на порту коммутатора Cisco

Для того чтобы ограничить количество MAC адресов ( количество подключенных узлов) на порту коммутатора Cisco необходимо использовать функци...