Не удивительно, что во многих бизнес процессах так или иначе встречается такая задача как позвонить на один номер телефона и потом соединить его с другим номером. Чаще всего такой сервис называют callback или обратный вызов, иногда — заказ звонка. Многие встречали его на сайтах интернет-магазинов, но в большинстве случаев это не автоматизированный обратный звонок, а обычная заявка, которая падает менеджеру на email или появляется в CRM, после чего менеджер ручками набирает номер клиента и с ним беседует. Некоторые крупные компании реализуют автоматизированный callback и даже интегрируют его с очередями в контакт-центре. В данном посте мы рассмотрим как буквально за несколько минут создать callback-сценарий с помощью платформы VoxImplant, а также интегрировать это хозяйство с каким-нибудь существующим бэкендом для сохранения/получения данных по звонку, запасайтесь поп-корном и добро пожаловать под кат.
Для начала продублируем схему в более крупном размере, чтобы было проще объяснить, что, как и с чем взаимодействует при реализации нашего callback-сервиса.
Выглядит немного громоздко, но на деле все очень просто и удобно. Разработчик VoxImplant (чтобы получить аккаунт разработчика нужно зарегистрироваться на сайте, это абсолютно бесплатно) через HTTP API делает запрос к облаку VoxImplant после чего сервер сценариев запускает заранее написанный на JS сценарий, в котором описана логика совершения звонков, их соединения, а также, при желании, бизнес-логика. Перед тем как делать HTTP-запрос для запуска сценария, очевидно, нужно его написать, а также подцепить к приложению через правило (rule), id этого правила потом нужно будет указывать в HTTP-запросе, чтобы было понятно какой сценарий должен быть запущен. Итак, по порядку:
- Создаем приложение VoxImplant.
- Создаем сценарий.
- Привязываем сценарий к приложению с помощью правила.
- Делаем HTTP-запрос для запуска сценария.
После совершения HTTP-запроса для запуска сценария, если все сделано правильно, в ответ придет media_session_access_url, который позволяет после запуска сценария продолжить удаленное управление его работой. Например, если нужно в какой-то определенный момент закончить выполнение сценария, то можно написать в сценарии следующее:
VoxEngine.addEventListener(AppEvents.HttpRequest, handleHttpRequest);
function handleHttpRequest(e) {
VoxEngine.terminate();
}
В таком случае, сделав запрос по media_session_access_url, вы прекратите выполнение сценария. Возвращаемся к реализации нашего колбэка на телефонные номера. Создаем приложение в разделе Applications панели управления, назовем его банально callback (в итоге полное название будет callback.имя_аккаунта.voximplant.com), и в разделе Scenarios создаем новый сценарий следующего вида:
var call1, call2, data;
VoxEngine.addEventListener(AppEvents.Started, handleScenarioStart);
function handleScenarioStart(e) {
// в сценарий можно передать данные с помощью механизма customData,
// параметр script_custom_data в HTTP-запросе StartScenarios
// передадим в нем номера в виде строки номер1:номер2
data = VoxEngine.customData();
data = data.split(":");
// начало выполнения сценария - звоним на номер 1
call1 = VoxEngine.callPSTN(data[0]);
// обработчики событий
call1.addEventListener(CallEvents.Connected, handleCall1Connected);
call1.addEventListener(CallEvents.Failed, function(e) { VoxEngine.terminate(); });
call1.addEventListener(CallEvents.Disconnected, function(e) { VoxEngine.terminate(); });
}
function handleCall1Connected(e) {
// первый звонок соединен успешно, проигрываем сообщение
call1.say("Здравствуйте, это звонок от сервиса Колбэк, ожидайте соединения", Language.RU_RUSSIAN_FEMALE);
call1.addEventListener(CallEvents.PlaybackFinished, function(e1) {
// после проигрывания сообщения пытаемся дозвониться до номера 2
call2 = VoxEngine.callPSTN(data[1]);
// обработчики событий
call2.addEventListener(CallEvents.Connected, handleCall2Connected);
call2.addEventListener(CallEvents.Failed, function(e2) {
call1.say("К сожалению, соединение не может быть установлено", Language.RU_RUSSIAN_FEMALE);
call1.addEventListener(CallEvents.PlaybackFinished, function(e3) { VoxEngine.terminate(); });
});
call2.addEventListener(CallEvents.Disconnected, function(e2) { VoxEngine.terminate(); });
});
}
function handleCall2Connected(e) {
// соединяем два звонка - звук
VoxEngine.sendMediaBetween(call1, call2);
// и сигнализацию
VoxEngine.easyProcess(call1, call2);
}
Если коротко, то данный сценарий звонит на номера, которые мы передаем через специальный параметр запроса StartScenarios script_custom_data в виде строки номер1: номер2. Сначала дозваниваемся на номер1 и проигрываем сообщение с помощью TTS, после чего дозваниваемся на номер2 и соединяем два звонка друг с другом. В данном сценарии мы никак не отрабатываем некоторые случаи, например, если не дозвонились на номер1, то просто завершаем выполнение сценария. Если немного поколдовать, то можно оповещать внешний мир о том, что что-то пошло не так, меняем
call1.addEventListener(CallEvents.Failed, function(e) { VoxEngine.terminate(); });
на
call1.addEventListener(CallEvents.Failed, handleCall1Failed);
и описываем handleCall1Failed:
function handleCall1Failed(e) {
// тут можно узнать причину
var code = e.code,
reason = e.reason;
// и отправить ее во внешний мир с помощью HTTP-запроса
Net.httpRequest("http://somewebservice", function(e1) {
// информация по реузльтатам запроса - e1.code, e1.text, e1.data, e1.headers
// убиваем сессию
VoxEngine.terminate();
});
}
Это самый простой пример с GET-запросом. Для настройки и управления HTTP-запросом со стороны сценария доступен класс HttpRequestOptions.
Таким же образом с помощью Date можно замерять длительность отдельных звонков или сессии внутри сценария и отправлять данные во внешний мир, если по каким-то причинам лезть в историю звонков для получения этой информации не соответствует логике сервиса/приложения. Как вы уже, наверное, поняли, мы пытались сделать очень гибкую систему, чтобы механизм решения тех или иных задач разработчик мог выбирать сам.
После того как сценарий готов нам нужно его сохранить под каким-нибудь названием, например, CallbackHabr и пойти в раздел Applications, чтобы подцепить сценарий к правилу и в итоге получить его ID.
Чтобы получить ID правила нужно немного пошаманить (в будущем постараемся устранить этот недостаток панели управления) — после создания правила нужно сохранить приложение (именно приложение, а не порядок правил), то есть перейти в таб General и там нажать Save. Потом еще раз открыть приложение для редактирования и открыть таб Rules, где отобразится ID правила (его также можно получить через HTTP API):
Ну в общем и все, теперь можно делать HTTP-запрос StartScenarios, для которого потребуется еще ряд параметров, свой api_key можно узнать в разделе Profile. Запрос в итоге будет выглядеть как-то так:
https://api.voximplant.com/platform_api/StartScenarios/?account_id=1&api_key=eec36d6c-a0eb-46b5-a006-1c2b65343bac&rule_id=55033&script_custom_data=number1%3Anumber2
В результате успеха в ответ придет что-то в духе:
{
"result" : 1,
"media_session_access_url" : "http://1.2.3.4:12092/request?id=93e41c6e20811b9b.1380201554.0@1.2.3.4&token=36bc7ce95edc679e32d83bb6f3ad985f"
}
Через этот media_session_access_url можно будет дальше общаться с сессией при необходимости. Для отладки работы сценария всегда доступны логи, которые находятся в разделе Calls (стрелочка в правом верхнем углу), а также наш убердебагер, доступный здесь. Для удобства мы загрузили сценарий из данного поста на GitHub, чтобы можно было быстро поэкспериментировать.
Автор: aylarov