使用Hobot框架在复杂的聊天机器人中进行路由



几年前开始为Telegram开发机器人程序后,我发现将它们作为命令行界面的特例使用时的性能,简单性和灵活性。今天,许多人都可以使用这些特性,这在很大程度上是由于流行的telegraf.js框架等提供了简化的使用Telegram API的方法。

同时,项目的架构完全取决于开发人员,从数量不多的复杂和多功能bot来看,我们在这方面仍有增长的空间。

在本文中,我想谈谈一个小型的聊天机器人路由框架,没有它,我们的项目将无法开发。

一些基本信息


在聊天机器人和CLI中,单个逻辑操作的执行通常包括几个优化步骤或分支步骤。这就要求程序存储一个特定的坐标,以便记住用户在流中的位置,并根据该坐标执行他的命令。

最简单的说明是执行npm init命令,在此期间,程序会要求您依次为package.json指定一个或另一个数据。

在第一步中,她告诉用户她正在等待包名称的文本输入-由于写入了此等待变量,因此用户将使用下一条命令向她发送的内容保存为包名称。

我们称此变量路径-该代码或该代码在逻辑上附加到的路径。如果机器人在几个步骤中发布了导航或命令,就总是需要它。

机器人架构的今天实践


我最初从其他开发人员那里看到的方法是这样的:对于来自用户的任何更新,将编写路径变量的特定值的检查列表,并将业务逻辑和进一步的导航以最基本的形式放置在这些检查中:

onUserInput(ctx, input) {
    switch(ctx.session.path) {
        case 'firstPath':
	    if (input === '!') {
               // -  
	        ctx.reply('!');
	        ctx.session.path = 'secondPath';
	    } else {
	        ctx.reply(' "!"');
	    }
	    break;
        case '...':
       	    //   
    }
}

如果您只有几个团队,每个团队只有几个步骤,那么此解决方案是最佳选择。如果您开始认为出了点问题,请转到第三和第七队。

在我们有机会在后期使用的其中一个机器人中,该功能的核心是4000行代码和大约70个条件(只有两个if组成的顶级条件),并检查了产生的影响-有时是路径,有时是命令,有时是路径和命令。所有这些条件都针对每个用户操作进行了检查,并从相邻的图纸对象访问了辅助功能,该对象也从几行开始增长。不用说,这个项目进行得有多缓慢和疯狂?

Hobot框架


ActualizeBot开始我们已经想象过它将有多大,而我们的首要任务是保持开发的可扩展性和速度。

为此,我们将客户端逻辑分解为分配给路径的控制器,并编写了一个小的抽象来在这些控制器之间导航并处理从用户那里收到的消息。

所有这些都是基于大型项目的,都是用TypeScript编写的,并被赋予了Hobot的雅致名称,这当然暗示了导航管道。

控制器是具有三个属性的简单对象:

  • path-用于初始化和导航已初始化路径的路径的字符串标识符
  • get — , , hobot.gotoPath(ctx, path, data?). — data ,
  • post — . , , . updateType — , : text, callback_query . updateType ctx

控制器示例:

const anotherController = {
    path: 'firstPath',
    get: async (ctx, data) => 
        await ctx.reply('Welcome to this path! Say "Hi"'),
    post: async (ctx, updateType) => {
        //     : text / callback_query / etc...
        if (updateType === updateTypes.text && ctx.update.message.text === 'Hi') {
            await ctx.reply("Thank you!");
            // hobot       this:
            this.hobot.gotoPath(ctx, 'secondPath', { userJustSaid: "Hi" });
        } else {
            //     ,       
            await ctx.reply('We expect "Hi" text message here');
        }
    }
}

它看起来比开始时要复杂一些,但是当您拥有100或200条路径时,难度将保持不变。

内部逻辑是微不足道的,令人惊讶的是尚未有人做到这一点:将
这些控制器添加到一个对象,该对象的键是path属性的值,并在用户操作或使用hobot.gotoPath导航时由这些键从中调用(ctx,路径,数据? )

导航是通过单独的方法分配的,以便不接触变量路径和导航逻辑,而只考虑业务逻辑,尽管您始终可以用手更改ctx.session.path,但是当然不建议这样做。

要使您的新机器人具有不可破坏的结构,您要做的就是启动一个常规的telegraf机器人,并将其和config对象传递给Hobot构造函数。config对象由要初始化的控制器,默认路径和命令/控制器对组成。

//   telegraf-
const bot = new Telegraf('_');

//  
export const hobot = new Hobot(bot, {
    defaultPath: 'firstPath',
    commands: [
        //  ,     
        // get    :
        { command: 'start', path: 'firstPath' }
    ],
    controllers: [
        // -,    
        startController,
        nextController
    ]
});

// C telegraf-,       
bot.launch();

结论


将工作表划分为控制器的隐式优点:

  • 能够将锁定到此控制器逻辑的隔离功能,方法和接口放在控制器旁边的单独文件中
  • 大大降低了意外破坏一切的风险
  • 模块化:打开/关闭/向特定受众群体提供此逻辑或逻辑可以简单地通过从阵列中添加和删除控制器来完成,包括无需编程即可更新配置-为此,我们当然需要写几个字母,因为我们仍然不需要这些到达
  • 在后方法处理结束时,能够清楚地告诉用户当他(经常发生)做错了什么,然后在正确的地方做的事情时,对用户的确切期望

我们的计划

本文介绍了使用文本消息传递Hobot的基本脚本。
如果发现该主题相关,我们将在以后的文章中分享该框架的其他技术细节以及从开发和使用电报自动程序的实践中得出的意见。

链接

安装bot的过程如下所示:README.MD中具有演练的npm i -s hobot
存储库以及基于Hobot的生产中使用沙盒
Ready bot

谢谢您的关注,我很高兴听到您对新机器人的问题,建议或想法!

All Articles