
Итак, для реализации автоматизированных обзвонов мы будем использовать платформу VoxImplant, а также встроенную в нее подсистему колл-листов (CallList). Стоит сразу отметить, что автоматизированные звонки допустимо делать только тем людям, которые на это согласились. Телефонный спам ничем не лучше СМС-спама или email-спама, не надо лишний раз раздражать людей.
Давайте рассмотрим несколько сценариев — обычная нотификация о каком-то событии (например, сообщение кода-активации или напоминание о посещении мед. учреждения) и опрос о качестве обслуживания.
Настройка аккаунта
В случае VoxImplant на вход с помощью HTTP-запроса подается CSV-файл со списком номеров и дополнительной информацией к каждому номеру, которая может быть использована в сценарии, запускаемому на каждую строку файла. Первая строка — это обязательный заголовок с названием параметров, чтобы потом эти параметры можно было использовать в сценарии. Существуют еще системные параметры, которые влияют на то как система будет данную строку обрабатывать. Давайте рассмотрим следующий пример:
user_id;first_name;last_name;phone_number;activation_code 0;Сергей;Иванов;74951234567;101102
Это контент CSV-файла, который мы отправим на обзвон. При обзвоне в сценарий VoxImplant эти данные придут в виде JSON, и мы сможем их использовать по назначению.
Создаем приложение, а в нем – сценарий и правило, к которому цепляем сценарий. Маску можно не менять, она не имеет значения при запуске через HTTP-запрос.
Наш сценарий VoxEngine должен содержать следующий код:
require(Modules.CallList); // Подключаем модуль CallList require(Modules.AI); let call, first_name, last_name, phone_number, activation_code, playbackCounter = 0; // Обработка события запуска сценария VoxEngine.addEventListener(AppEvents.Started, function (e) { let data = VoxEngine.customData(); // <-- сюда пришли данные из строки CSV в JSON-формате data = JSON.parse(data); user_id = data.user_id; first_name = data.first_name; last_name = data.last_name; phone_number = data.phone_number; activation_code = data.activation_code; Logger.write("Звоним " + first_name + " " + last_name + " на номер " + phone_number); // Звоним call = VoxEngine.callPSTN(phone_number, "+1234567890"); // <-- вторым параметром нужно указать callerid, предварительно его авторизовав в разделе CallerIDs верхнего меню панели управления VoxImplant // Для определения голосовой почты call.addEventListener(CallEvents.AudioStarted, function(){ AI.detectVoicemail(call) .then(voicemailDetected) .catch(()=>{ Logger.write('Голосовая почта не обнаружена'); }) }); // Вешаем обработчики событий call.addEventListener(CallEvents.Connected, handleCallConnected); call.addEventListener(CallEvents.Failed, handleCallFailed); call.addEventListener(CallEvents.Disconnected, handleCallDisconnected); }); function voicemailDetected(e) { // Голосовая почта? if (e.confidence >= 75) { VoxEngine.CallList.reportError("Voicemail", VoxEngine.terminate); return; } } // Дозвонились function handleCallConnected(e) { connected = true; setTimeout(function () { e.call.say("Здравствуйте, " + first_name + "! Ваш код активации: " + activation_code, { "language": VoiceList.Yandex.ru_RU_oksana }); }, 500); e.call.addEventListener(CallEvents.PlaybackFinished, handlePlaybackFinished); } // Воспроизведение закончилось function handlePlaybackFinished(e) { e.call.removeEventListener(CallEvents.PlaybackFinished, handlePlaybackFinished); playbackCounter++; // Несколько раз сказали код активации и достаточно if (playbackCounter == 4) { e.call.hangup(); } else { // Делаем паузу несколько секунд и проговариваем код еще раз setTimeout(function () { e.call.say("Ваш код активации: " + activation_code, { "language": VoiceList.Yandex.ru_RU_oksana }); e.call.addEventListener(CallEvents.PlaybackFinished, handlePlaybackFinished); }, 2000); } } function handleCallFailed(e) { // Сообщаем модулю, что не удалось дозвониться // в зависимости от настроек обзвона он либо попытается дозвониться еще раз через указанное время // либо запишет результат, что дозвониться не удалось, и в колонку result_data // CSV-файла с результатами обзвона запишет данные result, msg, code в JSON-формате CallList.reportError({ result: false, msg: "Failed", code: e.code }, VoxEngine.terminate); } function handleCallDisconnected(e) { // Отправляем сообщение модулю, чтобы сообщить, что дозвонились // result и duration будут записаны в колонку result_data // CSV-файла с результатами обзвона в JSON-формате CallList.reportResult({ result: true, duration: e.duration }, VoxEngine.terminate); }
Запуск обзвона через HTTP API
Метод API для запуска обзвона CreateCallList, давайте разберем параметры запроса, чтобы все было понятно:
- account_name — имя аккаунта VoxImplant
- api_key — API KEY аккаунта VoxImplant
- rule_id — id-правила приложения, к которому мы прицепили сценарий
- priority — приоритет обзвона, если обзвонов много, то можно управлять какой будет раньше выполнен
- max_simultaneous — максимальное кол-во одновременно обрабатываемых записей
- num_attempts — кол-во попыток дозвона, новая попытка будет в случае если была вызвана функция CallList.reportError
- name — просто название обзвона
- file_content — CSV-файл нужно передавать в теле запроса (request body)
- interval_seconds — время до следующей попытки дозвона (в секундах)
- encoding — кодировка CSV-файла, нужно указывать, если отличается от UTF-8
- delimiter — разделитель столбцов в CSV-файле, по умолчанию ;
Сделаем следующий PHP-файл с парочкой функций, которые запускают обзвон:
<?php define("API_URL", "https://api.voximplant.com/platform_api/"); define("API_KEY", "ваш api key"); define("ACCOUNT_NAME", "ваш account name"); define("RULE_ID", id-правила); function httpRequest($url,$params) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); if (isset($params["post"])) curl_setopt($ch, CURLOPT_POST, 1); if (isset($params["post_data"])) curl_setopt($ch, CURLOPT_POSTFIELDS, $params["post_data"]); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/csv')); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $server_output = curl_exec ($ch); curl_close ($ch); return $server_output; } function createCallList($file) { $url = API_URL . "CreateCallList/?" . "account_name=" . ACCOUNT_NAME . "&api_key=" . API_KEY . "&rule_id=" . RULE_ID . "&max_simultaneous=10" . "&num_attempts=2" . "&interval_seconds=60" . "&priority=1" . "&name=CallList"; $data = file_get_contents($file); $params = array('post' => true, 'post_data' => $data); $result = httpRequest($url, $params); echo $result; } function getCallListDetails($list_id, $output = "json") { $url = API_URL . "GetCallListDetails/?" . "account_name=" . ACCOUNT_NAME . "&api_key=" . API_KEY . "&list_id=" . $list_id . "&output=" . $output; $params = array(); $result = httpRequest($url, $params); echo $result; } createCallList(URL-CSV-файла); //getCallListDetails($list_id, "csv"); ?>
Результат выполнения getCallListDetails будет выглядеть как-то так (если успешно дозвонились):
"activation_code";"user_id";"last_name";"phone_number";"first_name";"__end_execution_time";"__start_execution_time";"result_data";"last_attempt";"attmepts_left";"status_id";status 101102;0;Иванов;74951234567;Сергей;;;"{""result"":true,""duration"":27}";"2014-11-24 19:21:39";1;2;Processed
Естественно, можно получить список всех обзвонов GetCallLists или остановить обзвон StopCallListProcessing.
Пример сценария опроса
Немного усложним задачу — кроме звонка будем еще просить ввести оценку качества обслуживания и сохранять ее в результатах обзвона. Для этого нужно будет модифицировать функции handleCallConnected, handleCallDisconnected и добавить новую handleToneReceived:
function handleCallConnected(e) { connected = true; e.call.handleTones(true); // <-- включаем обработку ввода setTimeout(function () { e.call.say("Здравствуйте, " + first_name + "! Спасибо вам за посещение нашего магазина, "+ "пожалуйста, оцените качество обслуживания от одного до пяти.", { "language": VoiceList.Yandex.ru_RU_oksana }); }, 500); e.call.addEventListener(CallEvents.PlaybackFinished, handlePlaybackFinished); e.call.addEventListener(CallEvents.ToneReceived, handleToneReceived); } let rating; function handleToneReceived(e) { e.call.removeEventListener(CallEvents.PlaybackFinished, handlePlaybackFinished); e.call.stopPlayback(); rating = e.tone; e.call.say("Спасибо большое за ваш ответ!", { "language": VoiceList.Yandex.ru_RU_oksana }); e.call.addEventListener(CallEvents.PlaybackFinished, function(e) { e.call.hangup(); }); } function handleCallDisconnected(e) { CallList.reportResult({ result: true, duration: e.duration, rating: rating, }, VoxEngine.terminate); } // Воспроизведение закончилось function handlePlaybackFinished(e) { e.call.removeEventListener(CallEvents.PlaybackFinished, handlePlaybackFinished); playbackCounter++; // Несколько раз сказали код активации и достаточно if (playbackCounter == 4) { e.call.hangup(); } else { // Делаем паузу несколько секунд и проговариваем код еще раз setTimeout(function () { e.call.say("Пожалуйста, оцените качество обслуживания от одного до пяти.", { "language": VoiceList.Yandex.ru_RU_oksana }); e.call.addEventListener(CallEvents.PlaybackFinished, handlePlaybackFinished); }, 2000); } }
Результат будет выглядеть как-то так:
"user_id";"last_name";"phone_number";"first_name";"__end_execution_time";"__start_execution_time";"result_data";"last_attempt";"attmepts_left";"status_id";status 0;Иванов;74951234567;Сергей;;;"{""result"":true,""duration"":27,""rating"":""3""}";"2014-11-24 20:17:13";1;2;Processed
Ну вот, мы рассмотрели несколько сценариев обзвонов с помощью VoxImplant. При желании можно делать HTTP-запросы во внешний мир прямо из сценария и передавать данные куда-то в реальном времени или подключить модуль ASR с распознаванием речи и дать возможность людям ответить на вопрос прямо голосом. Звонки при желании можно отправлять через свою SIP-инфраструктуру — меняем callPSTN на callSIP в сценарии и туда передаем настройки. В общем, надеемся, что данный пост будет вам полезен и поможем вам решить свою задачу, полезных вам звонков!
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Был ли данный материал вам полезен?
75%Да42
14.29%Не очень8
10.71%Нет6
Проголосовали 56 пользователей. Воздержались 19 пользователей.

