Не так давно появился долгожданный онлайн чат на сайт от bitrix24... Но ожидания, конечно, в полном объеме не оправдались.
Подключив на сайт и обработав несколько заявок - оказалось, что инструмент пока не очень приспособлен к боевым условиям. ждать обновлений?! вопрос скользкий - а зарядить инструмент и использовать уже хочется сейчас... Итак первые проблемы: 1. Идентификация клиента 2. Небесные гости в названиях 3. Создание лида 4. Кнопка вызова чата стремновата
1. Идентификация клиента и небесные гости Сейчас для того чтобы узнать имя и контактные данные, нужно задать в чате вопросы клиенту (при условии что оператор онлайн)... Иначе ответить на заявку в чате станет невозможным.
Решил попробовать написать, чат бота. Который при обращении запрашивал у клиента необходимые нам данные. В будущем планирую подключить к нему базу знаний и интерактивное меню (пока этого нет).
<?php
error_reporting(0);
define('DEBUG_FILE_NAME', ''); // if you need read debug log, you should write unique log name
define('CLIENT_ID', ''); // like 'app.67efrrt2990977.85678329' or 'local.57062d3061fc71.97850406' - This code should take in a partner's site, needed only if you want to write a message from Bot at any time without initialization by the user
define('CLIENT_SECRET', ''); // like '8bb00435c88aaa3028a0d44320d60339' - TThis code should take in a partner's site, needed only if you want to write a message from Bot at any time without initialization by the user
myApp::writeToLog($_REQUEST, 'ImBot Event Query');
$firstMessage = false;
$appsConfig = Array();
if (file_exists(__DIR__.'/config.php'))
include(__DIR__.'/config.php');
if (file_exists(__DIR__.'/config_group.php'))
include(__DIR__.'/config_group.php');
if ($_REQUEST['event'] == 'ONIMBOTMESSAGEADD')
{
$dataChat = explode("|",$_REQUEST['data']['PARAMS']['CHAT_ENTITY_ID']);
$addName = ($groupsConfig[$dataChat[1]]['NAME']) ? $groupsConfig[$dataChat[1]]['NAME'] : "линия ".$dataChat[1];
if (!isset($appsConfig[$_REQUEST['auth']['application_token']]))
return false;
if ($_REQUEST['data']['PARAMS']['CHAT_ENTITY_TYPE'] != 'LINES')
return false;
$data = myApp::currentUserData($_REQUEST['data']['PARAMS']['DIALOG_ID']);
myApp::writeToLog($data);
if(!$data->NAME){
$data->NAME = '-';
myApp::currentUserData($_REQUEST['data']['PARAMS']['DIALOG_ID'],$data);
}elseif($data->NAME=='-' && $_REQUEST['data']['PARAMS']['MESSAGE']){
$data->NAME = trim($_REQUEST['data']['PARAMS']['MESSAGE']);
myApp::currentUserData($_REQUEST['data']['PARAMS']['DIALOG_ID'],$data);
$result = myApp::restCommand('imbot.message.add', Array(
"DIALOG_ID" => $_REQUEST['data']['PARAMS']['DIALOG_ID'],
"MESSAGE" => $data->NAME.", укажите пожалуйста данные для связи с Вами:",
"ATTACH" => array(
array("MESSAGE" => "Email адрес"),
array("MESSAGE" => "либо мобильный телефон (с кодом страны и оператора)."),
),
), $_REQUEST["auth"]);
sleep(1);
$result = myApp::restCommand('imbot.chat.updateTitle', Array(
'CHAT_ID' => substr($_REQUEST['data']['PARAMS']['DIALOG_ID'],4),
'TITLE' => 'Чат с '.$data->NAME.' - '.$addName
), $_REQUEST["auth"]);
myApp::writeToLog($result);
}elseif(!$data->EMAIL && !$data->PHONE && $_REQUEST['data']['PARAMS']['MESSAGE']){
$reg="/([a-z0-9_.-]+)@([a-z0-9.-]+)/is";
if(preg_match_all($reg, $_REQUEST['data']['PARAMS']['MESSAGE'], $matches)){
foreach ($matches[0] as $email){
$data->EMAIL = $email;
break;
}
}
$phone = preg_replace("/([^0-9+])/is","",$_REQUEST['data']['PARAMS']['MESSAGE']);
if(strlen($phone)>6) {
$data->PHONE = $phone;
}else{
$data->PHONE = '-';
}
myApp::currentUserData($_REQUEST['data']['PARAMS']['DIALOG_ID'],$data);
$result = myApp::restCommand('imbot.message.add', Array(
"DIALOG_ID" => $_REQUEST['data']['PARAMS']['DIALOG_ID'],
"MESSAGE" => $data->NAME.", спасибо за оставленные данные. \nСейчас я попробую поискать для Вас свободного сотрудника и подключу его к диалогу.\nПримерное время ожидания 3-5 минут...",
), $_REQUEST["auth"]);
sleep(1);
$result = myApp::restCommand("user.update", array(
'ID'=>$_REQUEST['data']["USER"]["ID"],
'NAME'=>$data->NAME,
'FIRST_NAME'=>$data->NAME,
//'UF_SKYPE'=>str_replace('|'.'_','imol|'.$_REQUEST['data']['PARAMS']['CHAT_ENTITY_ID'])
//"PERSONAL_PHONE"=>"+79211234455"
), $_REQUEST["auth"]);
myApp::writeToLog($result);
sleep(1);
$result = myApp::restCommand('imopenlines.bot.session.operator', Array(
"CHAT_ID" => substr($_REQUEST['data']['PARAMS']['DIALOG_ID'],4)
), $_REQUEST["auth"]);
myApp::writeToLog($result);
}
}
if ($_REQUEST['event'] == 'ONIMBOTJOINCHAT')
{
if (!isset($appsConfig[$_REQUEST['auth']['application_token']]))
return false;
if ($_REQUEST['data']['PARAMS']['CHAT_ENTITY_TYPE'] != 'LINES')
return false;
$result = myApp::restCommand('imbot.message.add', Array(
"DIALOG_ID" => $_REQUEST['data']['PARAMS']['DIALOG_ID'],
"MESSAGE" => "Здравствуйте, я Робот, я задам Вам несколько вопросов, а после передам запрос свободному оператору.",
"ATTACH" => array(
array("MESSAGE" => "Как к Вам обращаться (как Вас зовут)?")
)
), $_REQUEST["auth"]);
myApp::currentUserData($_REQUEST['data']['PARAMS']['DIALOG_ID']);
}
else if ($_REQUEST['event'] == 'ONIMBOTDELETE')
{
if (!isset($appsConfig[$_REQUEST['auth']['application_token']]))
return false;
unset($appsConfig[$_REQUEST['auth']['application_token']]);
myApp::saveParams($appsConfig);
myApp::writeToLog($_REQUEST['event'], 'ImBot unregister');
}
else if ($_REQUEST['event'] == 'ONAPPINSTALL')
{
$handlerBackUrl = ($_SERVER['SERVER_PORT']==443||$_SERVER["HTTPS"]=="on"? 'https': 'http')."://".$_SERVER['SERVER_NAME'].(in_array($_SERVER['SERVER_PORT'], Array(80, 443))?'':':'.$_SERVER['SERVER_PORT']).$_SERVER['SCRIPT_NAME'];
$result = myApp::restCommand('imbot.register', Array(
'CODE' => 'openline',
'TYPE' => 'O',
'EVENT_MESSAGE_ADD' => $handlerBackUrl,
'EVENT_WELCOME_MESSAGE' => $handlerBackUrl,
'EVENT_BOT_DELETE' => $handlerBackUrl,
'OPENLINE' => 'Y',
'PROPERTIES' => Array(
'NAME' => 'Робот #'.(count($appsConfig)+1),
'WORK_POSITION' => "Бот для сбора контактов с открытых линий",
'COLOR' => 'RED',
'PERSONAL_PHOTO' => base64_encode(file_get_contents(__DIR__.'/avatar.png')),
)
), $_REQUEST["auth"]);
$botId = $result['result'];
$result = myApp::restCommand('event.bind', Array(
'EVENT' => 'OnAppUpdate',
'HANDLER' => $handlerBackUrl
), $_REQUEST["auth"]);
$appsConfig[$_REQUEST['auth']['application_token']] = Array(
'BOT_ID' => $botId,
'LANGUAGE_ID' => $_REQUEST['data']['LANGUAGE_ID'],
'AUTH' => $_REQUEST['auth'],
);
myApp::saveParams($appsConfig);
myApp::writeToLog(Array($botId), 'ImBot register');
}
else if ($_REQUEST['event'] == 'ONAPPUPDATE')
{
if (!isset($appsConfig[$_REQUEST['auth']['application_token']]))
return false;
if ($_REQUEST['data']['VERSION'] == 2)
{
}
else
{
$result = myApp::restCommand('app.info', array(), $_REQUEST["auth"]);
}
myApp::writeToLog($result, 'ImBot update event');
}
class myApp {
public static function saveParams($params)
{
$config = "<?php\n";
$config .= "\$appsConfig = ".var_export($params, true).";\n";
$config .= "?>";
file_put_contents(__DIR__."/config.php", $config);
return true;
}
public static function restCommand($method, array $params = Array(), array $auth = Array(), $authRefresh = true)
{
$queryUrl = "https://".$auth["domain"]."/rest/".$method;
$queryData = http_build_query(array_merge($params, array("auth" => $auth["access_token"])));
myApp::writeToLog(Array('URL' => $queryUrl, 'PARAMS' => array_merge($params, array("auth" => $auth["access_token"]))), 'ImBot send data');
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_POST => 1,
CURLOPT_HEADER => 0,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYPEER => 1,
CURLOPT_URL => $queryUrl,
CURLOPT_POSTFIELDS => $queryData,
));
$result = curl_exec($curl);
curl_close($curl);
$result = json_decode($result, 1);
if ($authRefresh && isset($result['error']) && in_array($result['error'], array('expired_token', 'invalid_token')))
{
$auth = myApp::restAuth($auth);
if ($auth)
{
$result = myApp::restCommand($method, $params, $auth, false);
}
}
return $result;
}
public static function restAuth($auth)
{
if (!CLIENT_ID || !CLIENT_SECRET)
return false;
if(!isset($auth['refresh_token']) || !isset($auth['scope']) || !isset($auth['domain']))
return false;
$queryUrl = 'https://'.$auth['domain'].'/oauth/token/';
$queryData = http_build_query($queryParams = array(
'grant_type' => 'refresh_token',
'client_id' => CLIENT_ID,
'client_secret' => CLIENT_SECRET,
'refresh_token' => $auth['refresh_token'],
'scope' => $auth['scope'],
));
myApp::writeToLog(Array('URL' => $queryUrl, 'PARAMS' => $queryParams), 'ImBot request auth data');
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_HEADER => 0,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $queryUrl.'?'.$queryData,
));
$result = curl_exec($curl);
curl_close($curl);
$result = json_decode($result, 1);
if (!isset($result['error']))
{
$appsConfig = Array();
if (file_exists(__DIR__.'/config.php'))
include(__DIR__.'/config.php');
$result['application_token'] = $auth['application_token'];
$appsConfig[$auth['application_token']]['AUTH'] = $result;
myApp::saveParams($appsConfig);
}
else
{
$result = false;
}
return $result;
}
public static function currentUserData($dialogId,$newParams=false)
{
$cacheId = md5($dialogId);
if (file_exists(__DIR__.'/cache') && file_exists(__DIR__.'/cache/'.$cacheId.'.cache') && !$newParams)
{
return json_decode(file_get_contents(__DIR__.'/cache/'.$cacheId.'.cache'));
}
else
{
if (!file_exists(__DIR__.'/cache'))
{
mkdir(__DIR__.'/cache');
chmod(__DIR__.'/cache', 0777);
}
if($newParams){
$config = json_encode($newParams);
}else{
$config = json_encode(array("DIALOG"=>$dialogId,"NAME"=>"","EMAIL"=>"","PHONE"=>""));
}
file_put_contents(__DIR__.'/cache/'.$cacheId.'.cache', $config);
return json_decode($config);
}
}
public static function writeToLog($data, $title = '')
{
if (!DEBUG_FILE_NAME)
return false;
$log = "\n------------------------\n";
$log .= date("Y.m.d G:i:s")."\n";
$log .= (strlen($title) > 0 ? $title : 'DEBUG')."\n";
$log .= print_r($data, 1);
$log .= "\n------------------------\n";
file_put_contents(__DIR__."/".DEBUG_FILE_NAME, $log, FILE_APPEND);
return true;
}
}
В файле конфигурации (config_group.php) можно указать название открытой линии (небесные гости будут подменяться с префиксом "NAME", "8"=> array( - это идентификатор открытой линии в вашем bitrix24)
Итак что же делает бот?
1. Задает вопрос. как к Вам обращаться для получения имени в последующем это имя будет использоваться для названия чата, а также для установки имени у созданного пользователя чата (Гость) 2. После получения имени запрашивает email или телефон для связи 3. После получения мыла или телефона приглашает в чат оператора и устанавливает заголовок чата + имя клиента. 4. Если нет оператора - действия из настроек открытой линии.
3. Создание лида данную проблему так и не удалось решить (так чтобы автоматически связать его с текущим чатом). Думал сделать обновление лида из полученых данных (но без контактных данных лид не создается в автоматическом режиме)
4. Замена кнопки это оказалось самым простым рисуем кнопку и просто подменяем стили прямо на сайте
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».