isamarin/alisa

YandexAlisa PHP Bot

1.0.2 2019-11-28 16:09 UTC

README

预配置

形态学词典

Bot 使用将单词转换为第一形式以更准确地识别用户请求。为了正确运行,需要具有所需语言的单词词典。对于俄语,适合 这个集合。必须指定词典的路径。

$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;
);

标准触发器

根据工作协议,Bot 至少需要有三个触发器用于问候、错误处理(请求帮助)。

//Будет вызван автоматически, при первом обращении пользователя к навыку
$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;
);

如果这些触发器未定义,Bot 将发送默认响应,其中包含指向此点的链接。如果你正在阅读此文本的原因是恶作剧,那么你的恶作剧成功了。

触发器

触发器

触发器 - Bot 应该响应的命令。

令牌

令牌 - 关键词或查询选项(取决于所选的识别类型)

MORPHY_STRICT

此模式使用逐个比较令牌组,仅选择合适的选项。从左到右进行解析 - 如果第一个组未通过搜索,则不会检查其余组,并且 Bot 将开始查看下一个触发器。如果所有组首次出现 - 触发器将被标记为已识别,其余组将不再参与解析。

$greenTea->linkTokens(['дай','хочу','налей'],['чай'],['зеленый']);
$blackTea->linkTokens(['дай','хочу','налей'],['чай'],['черный','индийский']);
$coffeTrigger->linkTokens(['дай','хочу','налей'],['кофе']);

对于查询 "请给我倒杯黑茶" 将触发 $blackTea; 对于查询 "没劲了,我想要一杯提神的咖啡" - 将触发 $coffeTrigger;

优点

  • 很好地区分相似的查询
  • 当所有令牌组首次匹配时,处理以下触发器将停止
  • 可以通过添加触发器的顺序来确定哪些触发器将首先处理。见上文。
  • 如果命令未被识别,可以引发错误触发器。在此示例中,请求倒啤酒时,Bot 会说它没有这样的权限。

缺点

  • 必须严格定义关键字的重要性。在 $greenTea 和 $blackTea 的例子中,决定因素将是第三个令牌组 - 黑茶还是绿茶。
  • 触发器的数量和令牌组的数量都会影响运行速度。

德玛尔-莱文斯坦

与 MORPHY_STRICT 不同,关键字将自动确定,但需要指定一些查询选项。参与解析的所有触发器,将选择与查询最匹配的触发器作为识别结果。

$greenTea->linkTokens(['Налей зеленого чая'],['Хочу зеленого чая'],['Дай зеленый чай']);
$blackTeas->linkTokens(['Налей чергого чая'],['Хочу черного чая'],['Дай черный чай']);
$coffeTrigger->linkTokens(['Налей кофе'],['Хочу кофе'],['Дай кофе']);

优点

  • 不需要定义关键词组。只需指定用户可能请求的一些可能选项即可。
  • 通常,查询的处理速度比 MORPHY_STRICT 类型的查询处理速度快。

缺点

  • 处理所有已指定令牌的触发器。即使正确的触发器首先被选中,其余触发器也会进行检查。结果触发器 - 最匹配的触发器。因此,触发器越多,运行越慢。
  • 与 MORPHY_STRICT 不同,不能引发错误识别消息。此模式始终返回某个触发器。在此示例中,请求倒啤酒时,由于某种原因,Bot 倒了咖啡。

委托

在 Bot 用于执行连续命令的情况下,可以将下一个触发器绑定到触发器。例如,如果需要从用户收集某些信息,例如姓名、姓氏等。

// Декларируем триггеры
$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;
);

机器人只保存一个触发器的数据实例,因此只能获取最后接收到的数据

响应

响应是触发器被触发后机器人发送给用户的信息。

文本和TTS

//$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;
});

内部委托

为触发器手动设置数据

响应后处理