Делаем автоматизированный обзвон для нотификаций или опросов

  • Tutorial
В ряде случаев у компании может возникнуть необходимость обзвонить каких-то из своих клиентов и сообщить им о чем-то, или, например, провести опрос про качеству обслуживания. Данную задачу можно решать разными способами, но мы будем исходить из того, что в данном случае ее нужно решить веб-разработчику, который привык иметь дело с Javascript/веб-сервисами и не сильно хочет вникать в особенности систем IP-телефонии. К счастью для него есть подходящий инструмент, о котором подробнее под катом.

Итак, для реализации автоматизированных обзвонов мы будем использовать платформу VoxImplant, а также встроенную в нее подсистему колл-листов (CallList). Стоит сразу отметить, что автоматизированные звонки допустимо делать только тем людям, которые на это согласились. Телефонный спам ничем не лучше СМС-спама или email-спама, не надо лишний раз раздражать людей.
Давайте рассмотрим несколько сценариев — обычная нотификация о каком-то событии (например, сообщение кода-активации или напоминание о посещении мед. учреждения) и опрос о качестве обслуживания.

Настройка аккаунта


В случае VoxImplant на вход с помощью HTTP-запроса подается CSV-файл со списком номеров и дополнительной информацией к каждому номеру, которая может быть использована в сценарии, запускаемому на каждую строку файла. Первая строка — это обязательный заголовок с названием параметров, чтобы потом эти параметры можно было использовать в сценарии. Существуют еще системные параметры, которые влияют на то как система будет данную строку обрабатывать. Давайте рассмотрим следующий пример:

user_id;first_name;last_name;phone_number;activation_code
0;Сергей;Иванов;74951234567;101102


Это контент CSV-файла, который мы отправим на обзвон. При обзвоне в сценарий VoxImplant эти данные придут в виде JSON, и мы сможем их использовать по назначению. Создаем следующий сценарий VoxEngine:

require(Modules.CallList); // Подключаем модуль CallList
require(Modules.AI);

var call,
	first_name,
	last_name,
	phone_number,
	activation_code,
	playbackCounter = 0;

// Обработка события запуска сценария
VoxEngine.addEventListener(AppEvents.Started, function (e) {
	var 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)});
	// Вешаем обработчики событий
	call.addEventListener(CallEvents.Connected, handleCallConnected);
	call.addEventListener(CallEvents.Failed, handleCallFailed);
	call.addEventListener(CallEvents.Disconnected, handleCallDisconnected);
        call.addEventListener(AI.Events.VoicemailDetected, voicemailDetected);
});

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.RU_RUSSIAN_FEMALE);
	}, 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.RU_RUSSIAN_FEMALE);
                        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);
}

Сохраняем сценарий, создаем приложение и правило приложения, к которому цепляем сценарий. Pattern можно не менять, он не имеет значения при запуске через HTTP-запрос.

Запуск обзвона через HTTP API


Метод API для запуска обзвона http://voximplant.com/docs/references/httpapi/#toc-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

Естественно, можно получить список всех обзвонов http://voximplant.com/docs/references/httpapi/GetCallLists.html или остановить обзвон http://voximplant.com/docs/references/httpapi/StopCallListProcessing.html.

Пример сценария опроса


Немного усложним задачу — кроме звонка будем еще просить ввести оценку качества обслуживания и сохранять ее в результатах обзвона. Для этого нужно будет модифицировать функции handleCallConnected, handleCallDisconnected и добавить новую handleToneReceived:
function handleCallConnected(e) {
	connected = true;
    e.call.handleTones(true); // <-- включаем обработку ввода
	setTimeout(function () {
		e.call.say("Здравствуйте, " + first_name + "! Спасибо вам за посещение нашего магазина, "+
                   "пожалуйста, оцените качество обслуживания от одного до пяти.", Language.RU_RUSSIAN_FEMALE);
	}, 500);
	e.call.addEventListener(CallEvents.PlaybackFinished, handlePlaybackFinished);
    e.call.addEventListener(CallEvents.ToneReceived, handleToneReceived);
}

var rating;

function handleToneReceived(e) {
  	e.call.removeEventListener(CallEvents.PlaybackFinished, handlePlaybackFinished);
    e.call.stopPlayback();
	rating = e.tone;
  	e.call.say("Спасибо большое за ваш ответ!", Language.RU_RUSSIAN_FEMALE);
  	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.RU_RUSSIAN_FEMALE);
            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 в сценарии и туда передаем настройки. В общем, надеемся, что данный пост будет вам полезен и поможем вам решить свою задачу, полезных вам звонков!

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

Был ли данный материал вам полезен?

Voximplant
95,00
Облачная платформа голосовой и видеотелефонии
Поделиться публикацией

Комментарии 2

    0
    Каждый раз нахожу что-то новое в коде ваших статей на хабре, что можно использовать для улучшения своих сценариев на VoxImplant, сейчас вот ToneDetected и VoicemailTone. Пишите почаще! :)

    P.S. Очень хочется ко всем методам в документации, примеры кода, иллюстрирующие их использование.
      0
      Ну ко всем это было бы слишком, но некоторые вещи еще действительно не документированы.

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

    Самое читаемое