Бот использует преобразование слов в первую форму для более точного распознавания пользовательского запроса. Для корректной работы необходимо иметь словарь слов с нужным языком. Для русского языка подойдет этот набор. В обязательном порядке необходимо указать путь до словаря.
$bot = new Alisa('NAME');
//Такой используется по умолчанию
$bot->setDictionaryPath($_SERVER['DOCUMENT_ROOT'] . '/dicts/');
Сессии – *.json файл в котором хранится вся сервисная информация в рамках сущности одного диалога. Необходимо указать путь до дирректории, в которую будут складироваться данные.
$bot = new Alisa('NAME');
//Такой используется по умолчанию
$bot->setDictionaryPath($_SERVER['DOCUMENT_ROOT'] . '/sessions/');
//Создаем бота. Аргумент – название навыка
$bot = new Alisa('myawesomebot');
//Создаем триггер, в качестве аргумента строка с уникальным именем
$helloTrigger = new Trigger('HELLO');
//Привязываем к триггеру токены – в данном случае в одну группу.
//Токены – ключевые слова, объединенные в группы
$helloTrigger->linkTokens(['привет','здравствуйте','приветсвую']);
$bayTrigger = new Trigger('bay');
$bayTrigger->linkTokens(['пока','до свидания','прощай']);
//Привязываем триггеры боту
$bot->addTrigger($helloTrigger,$bayTrigger);
//Отправляем ответ, если распознан $helloTrigger
$bot->sendResponse($helloTrigger,static function(){
//$answer - экземпляр отправляемого ответа
$answer = new Response();
$answer->addText('Привет!');
$answer->addText('Доброго времени суток!');
//обязательно возвращаем объект Response
return $answer;
);
//Отправляем ответ, если распознан $bayTrigger
$bot->sendResponse($bayTrigger,static function(){
$answer = new Response();
$answer->addText('Прошай!');
$answer->addText('Всего доброго');
//обязательно возвращаем объект Response
return $answer;
);
По протоколу работы бот обязан иметь как минимум триггер для приветствия, обработку ошибки (вызов помощи).
//Будет вызван автоматически, при первом обращении пользователя к навыку
$helloTrigger = new Trigger('HELLO');
$helloTrigger->setAsInit(true);
//Будет вызыван автоматически, если ну удалось распознать запрос
$mistakeTrigger = new Trigger('MISTAKE');
$mistakeTrigger->setAsMistake(true);
//Отправляем ответ, если распознан $mistakeTrigger
$bot->sendResponse($mistakeTrigger,static function(){
$answer = new Answer();
$answer->addText('Не удалось понять вашу команду :( ');
return $answer;
);
В случае, если данные триггеры не определены, бот отошлет ответ по умолчанию со ссылкой на данный пункт. И если это причина, по которой ты читаешь этот текст – шалость удалась.
Триггер – команда, на которую должен отреагрировать бот.
Токены – ключевые слова, или варианты запроса (зависит от выбранного типа распознования)
Данный режим использует поочередное сравнение групп токенов, отбирая только подходящие варинты. Разбор идет слева направо – если первая группа не прошла поиск – остальные группы перебираться не будут и бот приступит к просмотру следующего триггера. При первом вхождении всех групп – триггер будет помечен как распознанный, остыльне учавствовать в разборе не будут
$greenTea->linkTokens(['дай','хочу','налей'],['чай'],['зеленый']);
$blackTea->linkTokens(['дай','хочу','налей'],['чай'],['черный','индийский']);
$coffeTrigger->linkTokens(['дай','хочу','налей'],['кофе']);
При запросе "Налейка, пожалуйста черного чая" сработает $blackTea; При запросе "Сил нет как хочу бодрящего такого кофе" – $coffeTrigger;
Плюсы:
- Хорошо различает очень похожие запросы
- При первом свопадении всех групп токенов, обработка следующих триггеров прекращается
- Очередностью добавления триггеров можно определить те триггеры, которые будут обрабатываться первым. См пункт выше.
- Может вызывать триггер с ошибкой, если команда не была распознана. В данном примере, попросив налить пива, бот скажет что такими полномочиями не обладает.
Минусы:
- Необходимо строго определять важность того или иного ключевого слова. В случае с $greenTea и $blackTea, с аналогичными двумя первыми группами, решающим фактором сыграет третья гурппа токенов – черный чай или все таки чай зеленый.
- И колличество триггеров, и колличеество групп токенов сказывается на скорости работы.
В отличие от MORPHY_STRICT ключевые слова будут определяться автоматически, но необходимо прописать несколько вариантов запросов. В разборе учавствуют все триггеры, за распознный будет выбираться триггер с наилучшим совпаденеием запроса.
$greenTea->linkTokens(['Налей зеленого чая'],['Хочу зеленого чая'],['Дай зеленый чай']);
$blackTeas->linkTokens(['Налей чергого чая'],['Хочу черного чая'],['Дай черный чай']);
$coffeTrigger->linkTokens(['Налей кофе'],['Хочу кофе'],['Дай кофе']);
Плюсы:
- Не нужно определять группы ключевых слов. Достаточно прописать только несколько возможных вариантов, которые может запросить пользователь
- Как правило, запрос обрабатывается быстрее, чем аналогичная вариация MORPHY_STRICT
Минусы:
- Обрабатываются все триггеры, для которых прописаны токены. Даже если правильный триггер был выбран первым, остальные триггеры все равно пройдут проверку. Результирующий триггер – триггер с наибольшим совпадением. Соответвено чем больше триггеров, тем медленее работает.
- В отличие от MORPHY_STRICT не может вызывать сообщение с ошибкой распознования. Данный режим всегда выдает какой-либо триггер. В данном примере, попросив налить пива, по какой-то причине бот наливает кофе.
В случаях, когда бот используется для последовательного выполнения команд, можно привязать к триггеру следующий триггер. Например если нужно собрать какую-либо информацию от пользователя, например имя, фамилию итд.
// Декларируем триггеры
$nameTrigger = new Trigger('NAME');
$sNameTrigger = new Trigger('SECOND_NAME');
$yoTrigger = new Trigger('YEARS');
$personTrigger = new Trigger('PERSON');
// Назначаем токены для триггера
$nameTrigger->setTokens(['давай','хочу','может'],['знакомиться','познакомиться','представлюсь']);
// Привязываем следующие триггеры
$nameTrigger->nextDelegate($sNameTrigger);
$sNameTrigger->nextDelegate($yoTrigger);
$yoTrigger->nextDelegate($personTrigger);
// Обрабочтик запроса. Сработает если пользователь произнес "Давай познакомимся"
$bot->sendResponse($nameTrigger,static function() use ($bot){
$answer = new Response();
$answer->addText('Какое твое имя?');
return $answer;
});
// После шага $nameTrigger сработает обработчик $sNameTrigger
$bot->sendResponse($sNameTrigger,static function() use ($bot){
$answer = new Response();
$answer->addText('А фамилия?');
return $answer;
});
// После шага $sNameTrigger сработает обработчик $yoTrigger
$bot->sendResponse($yoTrigger,static function() use ($bot){
$answer = new Response();
$answer->addText('Сколько тебе лет?');
return $answer;
});
Для каждого из триггеров нужно создать обработчик с вопросом. При запросе пользователя "Ну давай познакомимся" сработает триггер $nameTrigger. Для триггеров $sNameTrigger и $yoTrigger токены не нужны (в общем то в данном случае они и не смогут сработать, тк пользотваель будет передавать информацию, и в ней нельзя распознать команду), они будут вызваны автоматически друг за другом.
Триггеры можно использовать не только как способ определения команды пользователя, но и для сбора информации.
//$personTrigger – назначен как следующий триггер после $yoTrigger
$bot->sendResponse($personTrigger,static function() use ($bot){
//В качестве аргумента строка, уникальное название триггера
$name = $bot->getTriggerData('NAME');
$sName = $bot->getTriggerData('SECOND_NAME');
$yo = $bot->getTriggerData('YEARS');
$answer = new Answer();
$answer->addText("Хорошо {$name} {$sName}, я тебя запомнила, и что тебе {$yo} лет – тоже");
return $answer;
);
Бот сохраняет только один экземпляр данных для триггера, таким образом получить можно только последние полученные данные
Ответы – это информация, которую бот отсылает пользователю, как только сработал триггер.
//$personTrigger – назначен как следующий триггер после $yoTrigger
$bot->sendResponse($personTrigger,static function() use ($bot){
$answer = new Answer();
$answer->addText('Один вариант ответа','Од!ин вари!ант отв!ета');
return $answer;
);
В методе addText два строчных аргумента. Первый используется для вывода текста, который будет отображен пользователю, второй – тот же самый текст в формате TTS.
Для большей интерактивности следует использовать несколько возможных вариантов ответа. Вариант при отправке будет выбран случайно.
$bot->sendResponse($bullshitTrigger,static function() {
$answer = new Answer();
$answer->addText('Да не может быть!');
$answer->addText('Чушь собачья!');
$answer->addText('Не верю!');
return $answer;
);
Для ответа можно прикрепить кнопку. Это может быть ссылка на веб-страницу или кнопка, при нажатии на которую будет вызван триггер. Кнопок может быть несколько и разных видов.
$bot->sendResponse($helloPerson,static function() {
$answer = new Answer();
$answer->addText('Может познакомимся?');
$buttonY = new Button('Давай');
$answer->addButton($button);
$buttonN = new Button();
$buttonN->setTitle('Неа');
return $answer;
);
В данном примере при нажатии на кнопку будет вызван $nameTrigger из примера в пункте "Делегирование". Таким образом $nameTrigger может быть взыван как голосом пользователя, так и нажатием на кнопку, если пользователь не разговорчив.
Бот Алисы может выводить пользователи кнопки в двух разных видах – как кнопка, размещенная под диалогом, так и ссылка внутри отправляемого ответа.
$bButton = new Button('Это кнопка');
//Будет отображена как кнопка, под диалогом. Со следующем ответом отображена не будет, если ее не привязатели к ответу Response
$bButton->setHide(true);
$bLink = new Button('Это кнопка, но как ссылка')
//Будет отображена в ответе. Даже если пользователь выбирал что-то другие, эта ссылка так и останется в сообщении.
$bButton->setHide(false);
$bButton = new Button('Это кнопка');
* * *
// Можно установить заголовок не в конструкторе, а в методе. Можно использовать как способ изменеия заголовка имеющейся кнопки, тем самым создавая вариативность
$bButton->setTitle('Это все еще кнопка')
// К кнопке можно добавить ссылку. При клике на нее произойдет переход по адресу в браузере.
$bButton->addLink('www.SITENAME.DOMAIN');
// Кнопке можно добавить обработчик какого-нибудь тригера. При клике на кнопку бот в первую очередь проверяет есть ли связанный Триггер для кнопки, и если есть – вызывает именно его.
$bButton->linkTrigger(Trigger $trigger);
//Кнопке можно передать какие-нибудь данные, которые можно будет забрать и использовать, если пользователь нажимал на эту кнопку.
$bButton->addPayload(['DATA'=>'SOME_DATA']);
Помимо отправленных пользователем данных, которые привязывается и сохраняеются триггером, можно сохранить и свои данные.
$bot->sendResponse($firstRequest,static function() use($bot) {
* * *
$bot->storeCommonData('Черный чай','TEA');
$bot->getCommonData('TEA'); // Вернет "Черный чай", в т.ч. если пользователь уже перешел к другому запросу
* * *
);
$bot->sendResponse($secondRequest,static function() use($bot) {
* * *
$bot->getCommonData('TEA'); // Вернет "Черный чай", в т.ч. если пользователь уже перешел к другому запросу
* * *
);
В случаях, когда триггер предполагает не только принятие данных, но и валидацию, следует использовать зацикливание
//Допустим что код триггера $chooseMeds – "MEDS"
$bot->sendResponse($chooseMeds, static function () use ($bot) {
$answer = new Response();
//Проверяем, это первичный запрос или цикл?
if ( ! $bot->isRepeatedRequest()) {
//Нет, значит это первичный запрос со стороны пользователя, предлагаем выбор
$answer->addText('Какую таблетку ты выберешь, Нео?');
//Задаем циклирование, результат будем проверять в этом же триггере
$bot->setRepeat(true);
} else {
//Неправильный выбор?
if ($bot->getTriggerData('MEDS') !== 'Синяя') {
$answer->addText('Неверный выбор, Нео');
//Задать цикл
$bot->setRepeat(true);
} else {
//Все ок, выход из триггера
$answer->addText('Ты сделал правильный выбор о-о');
}
}
return $answer;
});