转载

如何优雅地处理机器人指令

为了将内容维护工作转接到通过向 Bot 下达指令完成,一开始打算准备采用 Hubot 作为中转机器人:

如何优雅地处理机器人指令 后来因为安装过程中的种种不适以及对 CoffeeScript 的莫名恐惧,最终放弃这一方案。其实之前分别基于 Flask 和 Tornado 实现过 Telegram 和微信公众号的简单自动回复机器人,其中 API 响应环节一般都是非常简单明确的,比较乱的反而是对指令的解析。例如:

def parse(cmd):     cmds = cmd.split(' ')
if cmds[0] == 'share': print("Share {} to Hub".format(cmds[1]))
elif cmds[0] == 'update':
if cmds[1] == 'title': print("Update title of {} as {}".format(cmds[2], cmds[3]))
elif cmds[0] == 'unpublic': print("Unpublic link {}".format(cmds[1]))
else: print("Commands Help.") cmd1 = "share https://pyhub.cc"
cmd2 = "update title https://pyhub.cc Python头条"
cmd3 = "unpublic https://pyhub.cc"

parse(cmd1) parse(cmd2) parse(cmd3)

""" Share https://pyhub.cc to Hub Update title of https://pyhub.cc as Python头条 Unpublic link https://pyhub.cc """

这其中还省略了很多指令准确性的检查,随着指令数量、形式的增加,可读性、可维护性都会变得非常糟糕。刚好在查看 Hubot 文档的时候找到了一个 Python 版本的 slackbot ,采用修饰器和正则作为指令解析、分配的方法,看起来非常简洁:

from slackbot.bot import respond_to
import re
@respond_to('hi', re.IGNORECASE)
def hi(message): message.reply('I can understand hi or HI!')
# react with thumb up emoji message.react('+1')
@respond_to('Give me (.*)')
def giveme(message, something): message.reply('Here is {}'.format(something))

根据这一思路,写了一个简单的指令处理工具:

import reclass Jarvis(object):     dispatcher = {}     max_patt_len = 0      @classmethod     def cmd(cls, pattern, flags=0):         def wrapper(func):             cls.max_patt_len = max(cls.max_patt_len, len(pattern))             cls.dispatcher[pattern] = (func, re.compile(pattern, flags))
return func
return wrapper
def resolve(self, msg): for pattern in self.dispatcher: m = self.dispatcher[pattern][1].match(msg)
if m:
return self.dispatcher[pattern][0](self, *(m.groups()))
break else:
return self.help()

通过 dispatcher 记录每条指令绑定的 handler 函数,这样做的还可以同时将几个同义指令绑定到同一个 handler 函数上:

class M(Javis):   @Javis.cmd(r'hello')   @Javis.cmd(r'hi')   def hello(self):     return "Hello"m = M() print(m.resolve('hi')) print(m.resolve('hello'))

为了方便查看全部指令,还可以根据 handler 函数的文档或函数明自动生成所有指令的说明文档:

def help(self):   body = ""     for patt in sorted(self.dispatcher.keys()):       body += "{:.<{max_patt_len}}{}/n".format(patt,         self.dispatcher[patt][0].__doc__ or self.dispatcher[patt][0].__name__, max_patt_len=self.max_patt_len+4)
return "/nCommands:/n{0}/n{1}{0}/n".format("-"*40, body)

class M(Jarvis): @Jarvis.cmd(r'hello') @Jarvis.cmd(r'hi') def hello(self): return "Hello"
@Jarvis.cmd(r'del (.*)') def delete(self, lid): """根据lid删除记录""" return "Record {} Deleted!".format(lid)
print(m.help())
""" Commands: ---------------------------------------- del (.*)....根据lid删除记录 hello.......hello hi..........hello ---------------------------------------- """
原文  http://mp.weixin.qq.com/s?__biz=MzI0NjIxMzE5OQ==&mid=2656697861&idx=1&sn=ce8da0e4fa7f02e32015247abc50e006#rd
正文到此结束
Loading...