[日常灌水]Telegram Bot Sample–M1sakaBot的简介

刚刚考完试,游戏还在更新,我想趁这段时间记录一下本次翻新M1sakaBot的过程,也就是简要介绍一下这个Bot现在的构成吧。

本次翻新是为了今年校内的Hackathon比赛,至于为什么参赛我就不说了。翻新的需求是我自己Cognitive Service的key过期了,但是我没有visa卡去azure全球版购买服务,也登录不上世纪互联,不知道为什么。所以为了使得上一版的功能可用,我必须选择新的API提供方。此外,我希望为自己的Bot加入一定程度的自然语言理解能力,使得用户在执行某个功能时可以不需要记忆指令而是像正常说话一样就可以。接下来就简要介绍一下这个Bot的每个部分。

首先是Bot的核心,这部分是基于Python-Telegram-Bot这个模块构建的,大致设计思路是这样的。一个Bot的主体是一个Updater对象,然后实时接收发给Bot的消息。同时,这个Updater会绑定一个过滤器,准确来讲是Updater.dispatcher对象,这个过滤器是一组Handler的集合,Handler需要绑定在这个过滤器上才能生效。每一个Handler会有一个过滤消息的规则,例如过滤文本,过滤文件,过滤语音等。每一个Handler的过滤优先级由绑定的顺序决定。例如我先绑定一个Filter.text的Handler,然后绑定一个支持/start指令的CommandHandler,当我输入/start时,会被匹配成text然后被处理。所以说绑定Handler的时候顺序也是比较重要的。每个Handler除了过滤规则,还有一个最主要的部分,就是FSM,你需要构造一组函数和一组对应的返回值构造一个完整的有限状态机,进而可以让这个Bot在响应到对应的规则时可以完整地执行完一组指令,或者接收到对应的异常处理。Handler是需要事先声明出来的,所以在绑定前你需要编写好对应的函数,然后在声明一个新的Handler的时候根据你需要的指令和已经准备好的函数构建FSM,进而构造好这个对象,然后才能绑定在dispatcher上

这一部分的核心可以抽象成类似以下的代码:

def echo_request():
    #do something
    pass
updater=Updater("your config")
dp=updater.dispatcher
echo_handler = ConversationHandler(entry_points=
               [CommandHandler("echo",echo_request)],
               states={},fallbacks=
               [CommandHandler('cancel',cancel)])
dp.add_handler(echo_handler)

第二部分就是每个功能对应的模块了。这部分主要分成三类。

第一类是本机操作。第一个是/command指令,由于是测试功能,为了保证安全性,我事先设置好了允许的用户ID和操作指令黑名单,当且仅当是我个人使用/command指令且指令不在黑名单中,才会被执行,然后返回执行结果。另外还有一个模块是/mail邮件模块,也就是拿Bot快速发邮件的,这个就是新建一个SMTP Server ,然后根据用户事先设置好的邮件配置去执行发送任务,可以只发送文字也可以发送附件。

第二类是爬虫,由于需要的功能不错且爬虫实现不难,我选择采用urllib搭配相应的模块去写,这一部分是很久以前的代码直接复用的,当时并没有想着去使用解析HTML语言的模块,而是写了正则表达式去过滤,然后去爬取相应的内容,然后整理成标准格式文本去返回。下次再维护的时候会去重构一下,换成足够优美的方式重新实现。在这个Bot里,对应的模块是/pixiv和/btdigg。

第三类是各种API,其中天气模块/weather使用的是心知天气,翻译模块/translate采用的是百度翻译(其实日常用精度还是可以的),图像描述/description使用的是Face++的pic description接口,短链接/short我使用的是t.cn的(不知道将来有没有机会上线自己的短链接服务),音乐模块/music是用的段大喵(https://github.com/yumendy)编写的网易云音乐库。选择这些API的原因是我没法去买微软认知服务,本来最初版本是全对接MS服务的。等到将来有了VISA卡估计就会有转机了。

最后一个部分是本次翻新的核心目标,加入一定程度的自然语言理解支持,思路来自今年的编程之美。由于QNA Maker可以通过少量标记过的问答对进行fine-tuning,进而训练出接近你需要的对应的语言模型,我就想到了一个最简单的方式,问答对的问题是正常的指令语句,例如“我要听歌”,或者“今天的天气是怎样的”。然后给出统一的标签,例如第一句标记是command:song,第二句标记是command:weather。然后retrain and publish。再次调用时,如果输入类似的话,例如什么“诶嘿嘿我想听歌嘛”,这句话会被最后一个Handler接收到,然后发送到QNA Maker开放的API,接收返回的答案,然后分类处理,即丢给对应的状态处理函数,如果返回的是Not Match,则直接丢弃。fin-tuning的过程其实消耗了点时间,因为需要逐步收集大家不同的提问形式进而去拟合的。

其实第三部分我还是需要跟Touko好好学习一下,他们组编程之美的作品做得很棒,在LUIS和QNA Maker的使用上也比我熟练。

大概就是这样了,图什么的简单贴一点好了。

源码也已经在GitHub公开了,寒假的时候继续重构。

发表评论

电子邮件地址不会被公开。

This site uses Akismet to reduce spam. Learn how your comment data is processed.