adellantado/bot-template-framework

轻松构建机器人场景并在Botman上运行

1.12.0 2020-10-27 11:03 UTC

This package is auto-updated.

Last update: 2024-09-29 05:20:49 UTC


README

使用Botman简化聊天机器人开发。使用一个场景文件,您可以使机器人工作。

您可以在这里找到可下载的聊天机器人示例。

例如,简单的Telegram Hello World聊天机器人

    {
        "name": "Hello World Chatbot",
         "fallback": {
            "name": "Hello Block",
            "type": "block"
         },
         "blocks": [
            {
                "name": "Hello Block",
                "type": "text",
                "content": "Hello World!",
                "template": "Hi;Hello;What's up;Good day;/start"
            }
         ], 
         "drivers": [
            {
                "name": "Telegram",
                "token": "590000000:AAHp5XAGrpIyZynnIjcLKJSwUpPu0b1FXEY"
            }
         ]
    }

用法

  1. 使用composer安装包

     composer require adellantado/bot-template-framework
    
  2. 将您的聊天机器人场景模板template.json文件添加到storage/app

  3. 添加驱动到配置文件

     $this->app->singleton('botman', function ($app) {
         $config = TemplateEngine::getConfig(file_get_contents(storage_path('app/template.json')));
         return BotManFactory::create($config);
     });
    
  4. 在Botman之前调用listen()到模板引擎

     $botman = resolve('botman');
     
     $templateEngine = new TemplateEngine(file_get_contents(storage_path('app/template.json')), $botman);
     $templateEngine->listen();
     
     // Start listening
     $botman->listen();
    

场景文件结构

    // template.json
    
    {
        "name": "Chatbot Name",
        "fallback": "This is fallback message",
        "blocks": [
            {
                "name": "Simple Text Block",
                "type": "text",
                "content": "Hi, this is simple text message"
            },
            {
                ...
            }
        ],
        "drivers": [
            {
                "name": "Telegram",
                "token": "<your-telegram-token>"
            },
            {
                ...
            }
        ]
    }

使用块,您可以描述要执行的动作和数据,例如发送文本或图像,请求用户的位置或提问

在驱动程序中,您设置机器人想要工作的平台,例如Facebook或Telegram

有21种类型的块

    text, image, menu, audio, video, file, location, attachment, carousel, list, request, ask, intent, if, method, extend, idle, save, random, payload, validate

每个块都扩展了抽象块,它具有以下属性

    {
        "name": "Block Name",
        "type": "idle",
        "template": "Image;Show image;Want to see an image",
        "typing": "1s",
        "drivers": "any;!telegram",
        "locale": "en",
        "options": {"someProperty": "someValue"}
        "next": "Next Block Name"
    },

name - (必需) 块的名称,用于标识块;
type - (必需) 块的类型(例如图像,文本 ..);
template - (可选) 识别聊天机器人会对其做出反应的关键短语(请参阅$botman->hear());
typing - (可选) 在运行块之前在聊天中显示打字效果;
drivers - (可选) 对于某些驱动程序排除/包含块执行(例如,'any'或'*' - 对所有驱动程序运行,'facebook;telegram' - 对telegram和facebook运行,'any;!telegram' - 对任何驱动程序运行,但不是telegram);
locale - (可选) 将块分配给特定区域设置,类似于命名空间。例如,您用区域设置'zh'描述块,然后复制带有区域设置'ge'的翻译块;
options - (可选) 设置某些特定于驱动程序的属性;
next - (可选) 执行链中下一个块要执行的名字

文本块

发送简单的文本响应

   {
        "name": "Greetings",
        "type": "text",
        "content": "Hi! Nice to meet you {{user.firstName}};Hi there, {{user.firstName}}",
        "template": "Hello;Hi;Good day",
        "typing": "1s"
   }

注意:了解变量

图像块

使用描述和按钮或没有按钮绘制图像

    {
        "name": "Logo",
        "type": "image",
        "content": {
            "text": "This is the logo;Our logo is following",
            "url": "https://logo.com/logo.jpg",
            "buttons": {
                "Callback": "Learn More"
            }
        },
        "template": "Show me the logo"
    }

url - (必需) 图像URL;
text - (可选) 图像描述;
buttons - (可选) 在图像下添加按钮;

注意:了解菜单块

菜单块

1.显示按钮

    {
        "name": "Menu Block",
        "type": "menu",
        "content": {
            "text": "This is a simple menu; This is a menu",
            "buttons": [
                {"Callback": "Learn More"},
                {
                    "https://website.com/": "Visit Website", 
                    "Ask Support": "Ask Support"
                }
            ]
        } 
    }

注意:按钮可能因驱动程序而异(在官方文档中了解更多信息)

例如:Telegram

    Format #1
     "buttons": [ 
        {                                                     This is a simple menu
            "https://website.com/": "Visit Website",   ==>    ------------------------------------
            "Ask Support": "Ask Support"                      |   Visit Website  |  Ask Support  |
        }                                                     ------------------------------------
     ]                                                        
                                                              
    Format #2
     "buttons": [ 
        {                                                     This is a simple menu
            "https://website.com/": "Visit Website"   ==>     ---------------------
        },{                                                   |   Visit Website   |
            "Ask Support": "Ask Support"                      ---------------------
        }                                                     |    Ask Support    |
     ]                                                        ---------------------

例如:Facebook - 在一个菜单中只有3个按钮。

2.显示快速按钮

    {
        "name": "Quick Menu Block",
        "type": "menu",
        "mode": "quick",
        "content": {
            "text": "This is a quick menu",
            "buttons": [
                {
                    "https://website.com/": "Visit Website", 
                    "Ask Support": "Ask Support"
                }
            ]    
        } 
    }   

音频,视频和文件块

直接将视频,音频和文件拖到聊天中

    {
        "name": "File Block",
        "type": "file",
        "content": {
            "text": "Download the file",
            "url": "https://sample.com/doc.pdf"
        } 
    }

url - (必需) 文件,视频或音频链接;
text - (可选) 描述;

位置块

从用户请求位置

    {
        "name": "Location Test",
        "type": "location",
        "content": "Please, share your location by clicking button below;Send your location",
        "template": "share location",
        "result": {
            "save": "{{location}}"
        }
    }

content - (必需) 描述;
result.save - (必需) 将数据以json {latitude:.., longitude: ..} 的形式保存到变量中;

注意:了解变量

附件块

从用户请求图像,视频,音频或文件

    {
        "name": "Attachment Test",
        "type": "attachment",
        "mode": "image",
        "content": "Please, make a photo to verify your identity",
        "result": {
            "save": "{{photo}}"
        }
    }

mode - (可选) 可以为image,video,file,audio,如果没有提供模式,则默认为file;

轮播和列表块

绘制轮播或组件列表

    {
        "name": "List Test",
        "type": "list",
        "content": [
            {
                "url": "https://image.com/img1.jpg",
                "title": "Component #1",
                "description": "This is component #3"
            },
            {
                "url": "https://image.com/img2.jpg",
                "title": "Component #2",
                "description": "This is component #3"
            },
            {
                "url": "https://image.com/img3.jpg",
                "title": "Component #3",
                "description": "This is component #3",
                "buttons": {
                    "example btn": "Example Button"
                }
            }
        ],
    }

注意:某些平台可能不支持列表或轮播组件

请求块

执行自定义GET/POST请求

    {
        "name": "Tell a joke",
        "type": "request",
        "method": "GET",
        "url": "http://api.icndb.com/jokes/random",
        "result": {
            "field": "value.joke",
            "save": "{{joke}}"
        },
        "template": "Tell a joke;Joke;Do you know some jokes?"
    }

result.field - (可选) 从结果中读取数据;
result.save - (可选) 将结果保存到变量中;

注意:了解变量

询问块

提问并等待用户回答

    {
        "name": "Ask Phone",
        "type": "ask",
        "content": "Can you left us your phone to contant you only in case of urgency?",
        "validate": "number|min:10",
        "errorMsg": "This is custom error message occurs if validation hasn't been passed",
        "skip": "pause;skip",
        "stop": "stop;off",
        "result": {
            "prompt": "yes;no"
        },
        "next": {
            "yes": "Type Phone Block",
            "no": "Ask Email Block",
            "fallback": "Ask Email Block"
        }
    }

validate - (可选) 验证用户输入,不保存变量并在验证未通过时重复问题。可能的值:number(验证整数),email(发送快速按钮用于Facebook并验证电子邮件),urlphone(发送快速按钮用于Telegram和Facebook),imagefilevideoaudiolocation(发送快速按钮用于Telegram和Facebook),confirm(需要两次输入),size:<number>min:<number>max:<number>(精确/最小/最大字母),numeric(验证浮点值),digitsnon-free-inputfree-input(对于使用文本输入栏输入的值),/^[0-9]*$/(任何正则表达式,类似于这个);
errorMsg - (可选) 验证错误信息;
skipstop - (可选) 暂停/停止对话关键词;
result.prompt - (可选) 显示快速按钮;
next.<user answer> - (可选) 根据用户回答,运行下一个块('fallback' - 保留用于列表中未包含的任何回答)。

注意:规则可以用 "|" 符号组合(例如:numeric|min:10|max:12)
注意:了解更多关于结果的信息
注意:您需要在Botman网站上了解如何设置持久缓存(如Redis)

意图块

    {
        "name": "AlexaTest",
        "provider": "alexa",
        "type": "intent",
        "template": "BeverageIntent",
        "content": "well done; cool",
        "result": {
            "field": "beverage",
            "save": "{{user_beverage}}"
        },
        "next": {
            "coffee": "Coffee Card Block",
            "tea": "Tea Card Block",
            "default": "Repeat Question Block"
        }
    }

provider - (必需) 可以是 'alexa'、'wit' 或 'dialogflow';
template - (必需) Alexa和wit的意图名称,dialogflow的动作名称;
content - (必需(alexa)| 可选(dialogflow)| 可选(wit)) 回答到聊天;
result.field - (可选) 实体或槽位名称;
result.save - (可选) 保存实体或槽位值;
next.<entity_value> - (可选) 通过实体或槽位值触发下一个块;

注意:您应该使用Amazon Alexa控制台、wit或dialogflow控制台来运行此块;

注意:对于dialogflow v2,需要官方PHP库 - google/cloud-dialogflow;

注意:在dialogflow执行后调用块,请在dialogflow控制台中添加下一个有效负载 - {"next": "MyNextBlock"};

如果块

    {
        "name": "Comparison Test",
        "type": "if",
        "next": [
            ["{{var}}", "==", "1", "Block 1"],
            ["{{var}}", "<", "1", "Block 2"],
            ["{{var}}", ">", "1", "Block 3"],
        ]
    }

例如,当 {{var}} == 1 时简单地调用 "块 1",当 {{var}} < 1 时调用 "块 2",当 {{var}} > 1 时调用 "块 3"。;

支持的运算符:==!=>>=<<=

方法块

简单地从您自己的策略调用方法

    {
        "name": "Test method",
        "type": "method",
        "method": "myMethod"
    }

method - (必需) 方法名称

注意:对于每个驱动程序,您应该在App\Strategies文件夹中有策略类,其中包含'myMethod'函数

     namespace App\Strategies;
     use BotTemplateFramework\Strategies\Strategy;
     
     class Telegram extends Strategy {
     
        function myMethod() {
            $this->bot->reply('This is my method replies');
        }
     }

扩展块

简单地覆盖父块属性。当您需要制作非常相似的块但有微小变化时非常有用。

    {
        "name": "Oysters Extended",
        "type": "extend",
        "base": "Oysters Block",
        "content": {
            "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/37/Oysters_p1040741.jpg/330px-Oysters_p1040741.jpg"
        }
    },
    {
        "name": "Oysters Block",
        "type": "image",
        "template": "Oysters",
        "content": {
            "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Crassostrea_gigas_p1040848.jpg/450px-Crassostrea_gigas_p1040848.jpg"
        }
    }

base - (必需) 父块名称

例如,通过覆盖 content 字段扩展 "Oysters Block"。

注意:不要扩展 intentask 块;
注意:仅扩展第一层嵌套的字段(如 typecontentnext,但无法仅从图像内容中扩展 url(第二层嵌套)字段);

空闲块

简单地不做任何事情,但可以用来调用下一个块

   {
        "name": "Does Nothing",
        "type": "idle",
        "template": "call idle",
        "typing": "1s",
        "next": "Next Block"
   }    

保存块

简单地保存一些值(包括现有变量的值)到某个变量

   {
        "name": "Saves to Variable",
        "type": "save",
        "value": "123",
        "variable": "{{someVar}}"
   }   

随机块

    {
        "name": "Random Block",
        "type": "random",
        "next": [
            ["20%", "Block 1"],
            ["30%": "Block 2"],
            ["40%": "Block 3"]
        ]
    }

验证块

验证变量并在成功时执行带有 'true' 键的块

    {
        "name": "Validate Block",
        "type": "validate",
        "validate": "number|size:5",
        "variable": "{{myVar}}",
        "next": {
            "true": "Block 1",
            "false": "Block 2"
        }
    }        

variable - (必需) 变量名称;
validate - (必需) 可能的值:number(验证整数),email(发送快速按钮用于Facebook并验证电子邮件),urlphone(发送快速按钮用于Telegram和Facebook),imagefilevideoaudiolocation(发送快速按钮用于Telegram和Facebook),size:<number>min:<number>max:<number>(精确/最小/最大字母),numeric(验证浮点值),digitsnon-free-inputfree-input(对于使用文本输入栏输入的值),/^[0-9]*$/(任何正则表达式,类似于这个);

有效负载块

向消息传递者发送有效负载

    {
        "name": "Test payload",
        "type": "payload",
        "payload": {
            "text": "This is an inline keyboard example",
            "reply_markup": {
                "inline_keyboard": [
                    [
                        {
                            "text": "Button1",
                            "callback_data": "callback1"
                        },
                        {
                            "text": "Button2",
                            "callback_data": "callback2"
                        }                                          
                    ]
                ]
            }
        },
        "drivers": "telegram"
    }

payload - (必需) 要发送的有效载荷;
drivers - (必需) 设置精确的驱动程序非常重要,因为每个驱动程序都有一个独特的数据包

注意:学习适当信使的API文档

驱动程序

在使用这里的驱动程序之前,首先您需要为Botman安装适当的驱动程序。可用的驱动程序如下

    Facebook, Telegram, Skype, Dialogflow, Alexa, Viber, Web, Chatbase, Wit

注意:由于BotMan没有附带Viber驱动程序,您需要运行

    composer require adellantado/botman-viber-driver,

注意:由于BotMan没有附带Chatbase,您需要运行

    composer require bhavyanshu/chatbase-php   

示例

    "drivers": [
        {
            "name": "Dialogflow",
            "token": "b71dd842a2eb43434f4fg5eee55"
        },
        {
            "name": "Web",
            "token": "web"
        },
        {
            "name": "Chatbase",
            "token": "b71dd-842a-2eb4-3434-fw32e3233"
        },
        {
            "name": "Facebook",
            "app_secret": "FACEBOOK_APP_SECRET",
            "token": "FACEBOOK_TOKEN",
            "verification": "FACEBOOK_VERIFICATION",
            "config": "true",
            "events": {
                "delivery": "BlockExecOnDeliveryEvent",
                "read": "BlockExecOnReadEvent"
            }
        }
    ]

name - (必需) 驱动程序名称
token - (必需/可选) 用于Telegram、Viber、Dialogflow、Chatbase、Web(可选,默认令牌为'web')。字段:verification、token、app_secret - 用于Facebook;app_id、app_key - 用于Skype;project_id、key_path、version=2 - 用于Dialogflow v2 API。
config - (可选) 表示字段应从env()中读取
events - (可选) 通过事件触发阻塞。例如,在Facebook中“delivery”事件,触发名为“BlockExecOnDeliveryEvent”的阻塞。请参阅Botman中的事件。

变量

变量存储在Botman userStorage()中,所以请确保将正确的存储传递给Botman实例。

    BotManFactory::create($config, null, null, new FileStorage(__DIR__));

使用变量

使用括号中的变量

    {{my_variable}}

使用'result.save'字段与请求、询问、意图块一起保存变量。并且通过使用特殊的保存块。

预定义变量

- {{user.id}}
- {{user.firstName}}
- {{user.lastName}}
- {{bot.name}}
- {{bot.driver}}
- {{message}}(这是用户发送的最后一条消息)

结果

有5个返回结果的块:locationattachmentrequestaskintent

对于每个,您都可以应用

    "result": {
        "save": "{{my_variable}}"
    },

其中三个(requestaskintent)的next字段可能会根据结果值受到影响

例如,在这个例子中,触发Type Phone Block,然后结果是字符串值yes,触发Ask Email Block - 当结果是no以及既不是yes也不是no

    "next": {
        "yes": "Type Phone Block",
        "no": "Ask Email Block",
        "fallback": "Ask Email Block"
    }

注意:对于intent块,结果是实体值(Dialogflow)或插槽值(Alexa),其名称由field字段设置

询问结果

使用prompt字段添加快速按钮并简化用户回复,如下例所示

    {
        "name": "Ask Phone",
        "type": "ask",
        "content": "Can you left us your phone to contant you only in case of urgency?",
        "result": {
            "prompt": "yes;no"
        },
        "next": {
            "yes": "Type Phone Block",
            "no": "Ask Email Block",
            "fallback": "Ask Email Block"
        }
    }

请求结果

使用field字段快速从JSON响应中提取数据,如下所示

    {
        "name": "Tell a joke",
        "type": "request",
        "method": "GET",
        "url": "http://api.icndb.com/jokes/random",
        "result": {
            "field": "value.joke",
            "save": "{{joke}}"
        },
        "template": "Tell a joke;Joke;Do you know some jokes?"
    }

响应看起来像这样

     { 
        "type": "success", 
        "value": {
            "id": 495, 
            "joke": "Chuck Norris doesn't needs try-catch, exceptions are too afraid to raise.", 
            "categories": ["nerdy"] 
        } 
    }

回退

回退可以设置为3种不同的格式

1.文本

    "fallback": "This is default reply messsage"

2.Dialogflow

    "fallback": {
        "type": "dialogflow",
        "default": "This is default reply message when no answer from Dialogflow"
    }

3.块

    "fallback": {
        "name": "Hello Block",
        "type": "block"
    }

构建器

使用构建器很简单,以下是一个简单聊天机器人的示例

    $template = (new Template('Beedevs Chatbot'))
        ->addDrivers([
            new TelegramDriver('123123wefwef:wefonwewerwerwerw')
        ])
        ->addFallbackMessage('This is default message')
        ->addBlocks([

            (new TextBlock())
                ->text('Hi! Welcome to beedevs chatbot')
                ->template([
                    'Hello',
                    'Hi',
                    'What\'s up',
                    'Good day'
                ])->typing(1)
                ->next(
                    $about = (new ImageBlock())
                        ->url('https://pbs.twimg.com/profile_images/799239637684355072/SGIDpffc_400x400.jpg')
                        ->buttons([
                            (new Button('Visit'))->url("https://beedevs.com")
                        ])
                        ->text('Beedevs is a chatbot development studio. Want to know more? Visit our website!')
                        ->template([
                            'About'
                        ])
                ),

            $about,

            (new RequestBlock())
                ->url('http://api.icndb.com/jokes/random')
                ->method('GET')
                ->result((new RequestResult())
                    ->field(['value', 'joke'])
                    ->save('{{joke}}')
                )->template([
                    'Tell a joke',
                    'Joke',
                    'Do you know some jokes?'
                ])
                ->next(
                    $joke = (new TextBlock())
                        ->text('{{joke}}')
                        ->typing(1)
                ),

            $joke,

            (new MenuBlock())
                ->text('Menu')
                ->buttons([
                    (new Button('Website'))->url("https://beedevs.com"),
                    (new Button('About'))->callback('About')
                ])
                ->template([
                    'Show menu',
                    'Menu',
                    'Main menu'
                ]),

            (new ListBlock())->items([
                (new ListItem('ListItem1', 'https://static.addtoany.com/images/dracaena-cinnabari.jpg'))
                    ->buttons([
                        (new Button('About'))->callback('About')
                    ])
                    ->description('National Park'),
                (new ListItem('ListItem2', 'https://cloud.google.com/blog/big-data/2016/12/images/148114735559140/image-classification-1.png'))
                    ->buttons([
                        (new Button('About'))->callback('About')
                    ])
                    ->description('Sunflower fields at summer time')
            ])->template([
                'List',
                'Show list'
            ])

        ]);

然后只需将您的$template插入到引擎中,如下所示

    $templateEngine = new TemplateEngine($template, $botman);
    $templateEngine->listen();
            
    // Start listening
    $botman->listen();

在引擎内部,它将其转换为与您之前使用的类似JSON的数组,但使用构建器,您的功能在便利性和开发速度方面得到提升。