人工智能与聊天机器人

打造微信聊天机器人1

2016-11-05  本文已影响380人  FunFeast

摘要:利用微信公众号开发一个聊天机器人。

前置条件

原理

聊天机器人原理图

上图给出了聊天机器人的基本原理。用户A在微信客户端中给公众号发送一条消息,这条消息会通过微信服务器,转发到公众号指定的服务器上,也就是图中的“聊天机器人服务器”,聊天机器人服务器收到消息之后,经过“思考”,给出一个回复到微信服务器,然后微信服务器就会把这个回复发送到用户A的客户端,一次“对话”就完成了。整个过程中的大部分工作,都已经由微信包办了,我们要做的,只是红框中的聊天机器人服务器,让它按照微信指定的协议,接收消息和发送回复,就是这么简单!

微信服务器和聊天机器人之间通过HTTP通信,所以我们的聊天机器人服务器,实际上就是一个符合微信标准的CGI,基本上你可以用任何语言进行开发。本文将使用Python和Bottle框架进行开发。

申请微信公众号

微信公众平台注册一个帐号,注意这里使用的邮箱不能跟微信其他服务所绑定的邮箱相同,包括个人微信号、微信开放平台、微信小程序等等。幸好只是换邮箱注册,不是换手机注册。注册之后请按照官方的指引填写相关信息。公众平台提供了编辑和发布图文消息的功能,但是要实现一个聊天机器人,必须使用开发者模式。在"开发" -> "接口权限"下,可以查看当前公众号能够使用的接口,目前个人用户只能申请订阅号,并且不能进行认证,因此权限最低,能使用的接口有限。不过接收消息和自动回复的权限还是有的,并且没有调用次数的限制,这就足够了。

进入"开发" -> "基本配置" -> "服务器配置",修改服务器配置,这里的关键选项是URL和Token。URL就是原理图中,微信服务器和你的聊天机器人服务器之间通信的接口。Token让你的聊天机器人可以验证消息的来源,防止微信服务器之外的恶意调用。微信服务器发送的每条消息,都会带上一个使用Token加密的签名,我们只要使用相同的Token和算法,就能验证收到的消息是否来自微信服务器。关于签名的方法,微信官方的接入指南里有更详细的描述,以及对应的PHP实现。"消息加解密方式"选择"明文模式",EncodingAESKey直接点"随机生成",这样省去了消息加解密的麻烦。

此时直接点击“提交”是不能成功的,因为微信公众平台会立刻发送一个验证消息,检验URL是否可用。我们必须先让自己的服务器跑起来,才能通过验证。

一个最小的公众号服务器

这里我们使用Bottle这个小巧而美丽的Web框架来编写一个能通过验证的最简单的服务器。在你的云主机或者VPS上创建robot.py文件,内容如下:

from bottle import request, route, run
from hashlib import sha1

TOKEN = '这里填写你的Token'

def valid():
    l = [TOKEN, request.query.timestamp, request.query.nonce]
    l.sort()
    h = sha1()
    h.update("".join(l))
    if request.query.signature == h.hexdigest():
        return True
    return False

@route('/wx/chatbot')
def check():
    if valid():
        return request.query.echostr
    return "failed"

run(host='0.0.0.0', port=80)

这段端程序的含义是,服务器收到一个访问/wx/chatbot的GET请求时,按照微信指定的算法计算签名,跟请求中的signature参数进行对比,如果二者相符,就把请求中的echostr原样返回。事实上,这个服务器还不是最简单的。因为微信服务器只要收到了echostr,就会认为验证成功,因此我们完全可以跳过签名验证的过程,直接返回echostr。

运行这段程序必须要bottle模块,可以直接从这里下载压缩包,解压出里面的bottle.py放在你程序的目录下。不过更推荐的方法是使用pip,安装方法见这里

pip install bottle

现在让我们的服务器运行起来,然后回到微信公众平台的配置页面,在URL里填写“http://你的域名或ip/wx/chatbot”, 点击“提交”完成配置,再点击“启用”让我们的配置生效。

python robot.py

A Dumb Robot

到这里,我们已经有了一个可以接收微信消息的服务器了。微信发过来的消息是下面这个样子:

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[this is a test]]></Content>
<MsgId>1234567890123456</MsgId>
</xml>

这是一个XML文件,我们只关注3个字段:ToUserName、FromUserName和Content,分别表示消息的接收者(这里是我们的公众号ID,可以在公众平台的"设置" -> "公众号设置" -> "原始ID"中看到),发送者和内容。要回复消息给用户,也要返回一个指定格式的XML给微信服务器:

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[你好]]></Content>
</xml>

知道了往返消息的格式(详细信息参见微信的开发文档),我们就可以开始“对话”了。在代码中添加下面内容:

from time import time

@route('/wx/chatbot', method='POST')
def chat():
    if not valid():
        return "invalid msg"
    return """
    <xml>
    <ToUserName><![CDATA[toUser]]></ToUserName>
    <FromUserName><![CDATA[fromUser]]></FromUserName>
    <CreateTime>12345678</CreateTime>
    <MsgType><![CDATA[text]]></MsgType>
    <Content><![CDATA[Hello]]></Content>
    </xml>
    """ % int(time()) 

chat()函数将接收来自微信服务器的POST请求,然后返回一个固定的回复。要让发消息的用户能够收到回复,还需要正确的填写回复中的toUser和fromUser。由于是回复消息,toUser和fromUser跟用户发送给公众号的消息正好是反过来的,我们可以用print语句把收到的消息打印出来,找到对应的字段填在回复里,这样就可以成功的回复消息了。因为toUser是写死的,这个公众号只能给固定的用户回复消息,而且只能say hello。不过,它总算是“活过来”了。在后续的内容里,我们将真正打造一个能够跟用户对话,并且具备一定智能的聊天机器人。

上一篇下一篇

猜你喜欢

热点阅读