Разработка → Asterisk+Lua — IVR и некоторые другие моменты

Sayman_nsk 14 ноября 2014 в 15:51 7,1k
И снова здрасьте! IVR — сегодня это даже не фишка, а некий стандарт работы предприятия. В некоторых случаях многие, как клиенты, так и конкуренты считают, что если этого самого IVR нет, то «там» низкое качество предоставляемых услуг. Этой штукой нынче никого не удивишь. Однако, мы же говорим про реализацию IVR на языке lua под Астериском. И если вы переходите от обычного плана набора к Lua, то тут можно кое-что пояснить.


Предположим, что нужные файлы для меню у вас уже есть и они лежат в нужной папке. Возможно, что на старом конфиге они даже использовались. Тогда, при описании голосового меню на Lua делаем (я делал) так:

Описываем где-то в начале файла табличку с файлами. Всё удобнее в одном месте при необходимости менять:

mhold = {
    m_hello = "custom/message_01";        -- Приветствие
    m_menu = "custom/message_02";       -- описание меню
    m_thx = "custom/message_05";           -- Спасибо за выбор нашей компании...
    good_day = "custom/wav_gd_2";         -- типа "Хорошего вам дня"...
    comerc = "custom/com_1";                  -- Нажмите для того-то 1
    live = "custom/live_2";                          -- ну и т.д. другие варианты выбора и нажатий.
    other = "custom/other_3";
}


Таким образом вы описали в табличке поля с указанием применяемых файлов. В моём случае — файлы с приветствием, какие-то благодарственные слова и выборка меню. Так же был резервный (на всякий случай) вариант, при котором каждое меню было разбито на свой файл…

Далее, в первой статье я в описании входящих звонков, в функции foo() указал вызов ivr(). Так вот, фактически в моём примере это работало так:
Событие — Входящий звонок. Вызов foo(). Проверка некоторых условий -> проигрывание приветствия -> вызов ivr(). Само приветствие я проигрывал до вызова ivr().

function ivr(d)
    app.noop("Включено голосовое меню.")
    app.noop("DID: "..d)
    app.background(mhold.m_menu,"","","menu")
    app.waitexten(3)
    return
end


Не такая уж и навороченная функция. app.background тут и есть вызов из ядра астериска голосового меню. Но при этом нужно так же сделать описание события menu в экстеншинах:

menu = {
	["1"] = function(c,e)
	    app.noop("Calling from menu by 1")
	    app.playback(mhold.m_thx)
	    CallSKS()                                 -- на обработчик вызова СКС
	end;
	["2"] = function(c,e)
	    app.noop("Calling from menu by 2")
	    app.playback(mhold.m_thx)
	    app.goto("local_ext","4690",1)   -- тут и далее я вызываю абонентов сразу группами.
	end;
	["3"] = function(c,e)
	    app.noop("Calling from menu by 3")
	    app.playback(mhold.m_thx)
	    app.goto("local_ext","4579",1)
	end;
	["4"] = function(c,e)
	    app.noop("Calling from menu by 4")
	    app.playback(mhold.m_thx)
	    CallSKS()                                   -- тоже вариант обращения в клиентскую службу.
	end;
    };


При этом в описании входящих звонков from_trunk нужно добавить обработку таймаута, иначе если клиент не сделал выбор в течении нужного времени, клиент услышит короткие гудки, а в консоли астера вы увидите ошибку исполнения кода.

from_trunk = {
        t = function()
                app.playback(mhold.m_thx)
                app.goto("local_ext","7090",1)
        end;
-- далее остальная часть описания событий...


Про IVR кажется всё. Теперь ещё один момент: ограничение времени звонка. Да, к сожалению мне и такое приходилось делать. Были отдельные кадры в компании, которые любили по межгороду просто десятками минут, а за месяц — часами болтать с друзьями, подругами, братьями и т.д. Конечно, таких наказывали рублём, но позиция руководства была такой, что на работе надо работать. Попросили ограничить болтунов во времени. В нижеследующем примере будет показано, как можно сделать это глобально, с выборкой направления (хотя возможно не самый лучший вариант).

-- где-то внутри функции trunk_test
if string.len(num) > 7 and not string.find(string.sub(num,1,4),"8383",1) then
        app.noop("Действует ограничение на длительность звонка 10 минут!!!")
        app.dial(string.format("%s%s,60,tTL(600000:480000:60000)",trunk.startel,num))
else
        app.noop("Звонок по городу.")
        app.dial(string.format("%s%s,60,tT",trunk.startel,num))
end


В данном случае я сделал выборку по количеству символов в набираемом номере. Если количество символов превышает количество символов нашего города, исключая код нашего города, тогда это звонок по межгороду. Сотовые местные обрабатываются отдельно, поэтому под это правило не попадают (в прошлой статье про DEF-коды). А вот сотовые межгорода — попали. В моём примере действует ограничение на 10минут. за 7 (или 8?) минут абонент слышит лёгкий beep. В данной функции можно добавить обработку только конкретных «злодеев». Можно этих злодеев
занести в таблицу и по ней уже смотреть, а можно в базу mysql и данные от туда вытаскивать, кому как удобно…

Всё. Всем до свиданья!
Проголосовать:
+7
Сохранить: