给你的公众号添加一个智能机器人

开发 开发工具
我们代码使用 Python 开发,所以需要配置好 Python 开发环境,安装 Flash 库。最后需要注册一个图灵机器人账号,调用其 API 接口。

环境和工具

  • 公众号一个
  • 云服务器一台
  • Python 环境
  • Flask(Python 第三方库)
  • 图灵机器人账号

以上就是我们实现公众号后台智能对话机器人需要的环境和工具,前两个就不多说了。我们代码使用 Python 开发,所以需要配置好 Python 开发环境,安装 Flash 库。最后需要注册一个图灵机器人账号,调用其 API 接口。

[[342172]]

欢迎到我的公众号 码小白TM 里调戏机器人,去看看这个机器人智不智能!

Web 服务器搭建

我们想要接收公众号后台发送的消息,就需要搭建一个 Web 服务器了。我们在云服务器上安装好 Python 和 Flask 后,就可以进行 Web 服务器的搭建了。

我们首先搭建一个非常简单的 Web 服务器,就是在网页显示出 HelloWorld!,来跑通我们的代码。我们来看一下主程序代码。

main.py

  1. from flask import Flask 
  2. app = Flask(__name__)@app.route("/"
  3. def index(): 
  4.     return "Hello World!" 
  5. if __name__ == "__main__"
  6.     app.run(host='0.0.0.0'

代码非常简单,我们直接运行代码,启动 Web 服务器:

  1. python main.py 

运行成功后,我们可以在云服务器机器浏览器上访问 127.0.0.1,如果我们能看到 Hello World! 就说明我们服务器启动成功了。我们也可以在外网机器浏览器上访问你云服务器的外网 IP,来检测 Web 服务器是否成功启动。

公众号后台配置和验证

然后我们去公众号后台开发->基本配置页找到服务器配置,可以看到我们需要一个服务器的 URL 地址、Token 令牌、消息加解密密钥。

 

给你的公众号添加一个智能机器人
公众号后台配置

服务器的 URL 地址就是:http://服务器外网IP/wechat,/ 前面是你的云服务外网 IP 地址,后边是我们在代码里定义的路由入口(可以自己定义),后边我们会在代码中看到。Token 令牌是我们自己定义的,后边代码中也会用到。消息加解密密钥可以通过自动生成,消息加解密方式我们选择明文模式即可。

你第一次配置的时候下边会有保存按钮,这个时候我们先不要点击,因为我们需要在 Web 服务器端对消息字段进行解析处理,然后回传结果进行验证。

我们到微信公众号开发文档里看一下消息验证流程。

 

给你的公众号添加一个智能机器人
验证流程

根据上图流程我们进行我们的代码编写。

main.py

  1. from flask import Flask 
  2. from flask import request 
  3. import hashlibapp = Flask(__name__)@app.route("/"
  4. def index():    return "Hello World!" 
  5. # 公众号后台消息路由入口@app.route("/wechat", methods=["GET""POST"]) 
  6. def wechat(): # 验证使用的是GET方法    if request.method == "GET"
  7.         signature = request.args.get('signature'
  8.         timestamp = request.args.get('timestamp'
  9.         nonce = request.args.get('nonce'
  10.         echostr = request.args.get('echostr'
  11.         token = "公众号后台填写的token" 
  12.   # 进行排序        dataList = [token, timestamp, nonce]        dataList.sort()        result = "".join(dataList) 
  13.   #哈希加密算法得到hashcode        sha1 = hashlib.sha1()        sha1.update(result.encode("utf-8")) 
  14.         hashcode = sha1.hexdigest()        if hashcode == signature: 
  15.             return echostr 
  16.         else
  17.             return "" 
  18. if __name__ == "__main__"
  19.     app.run(host='0.0.0.0', port=80) #公众号后台只开放了80端口 

这里需要注意 http 的端口号固定使用80,不可填写其他。这里坑了我很久,因为我的服务器上还有我自己的博客,80端口被博客占用了,为了把80端口让出来,我重新搭了我的博客,修改了端口,导致现在访问我的博客后边必须加上修改后的端口。这里如果有同学有更高的方法,还请劳烦告知一下!

好了,现在我们的验证流程完成,运行我们的 Web 服务器。然后到公众号后台配置处点击保存,如果提示验证通过,那么恭喜你完成了验证。

如果提示验证失败,我们自己根据报错提示来查看是哪里的问题。

实现“你问我答”和“图”上往来

我们验证成功了,下面就要开始处理粉丝在公众号发过来的消息了。我们先来实现一个简单的“你问我答”, 粉丝给公众号一条文本消息,公众号立马回复一条相同文本消息给粉丝;还有图上往来,接受粉丝发送的图片消息,并立马回复相同的图片给粉丝。

我们通过公众号文档知道,普通用户向公众号发消息是用的 POST 方法,消息分为文本消息、图片消息、语音消息、视频消息等很多种。这里我们只对文本消息和图片消息进行处理和回复(后续你也可以针对其他消息进行处理和回复)。

消息的格式为XML数据包,下面看一下文本消息的实例:

  1. <xml> 
  2.   <ToUserName><![CDATA[toUser]]></ToUserName> 
  3.   <FromUserName><![CDATA[fromUser]]></FromUserName> 
  4.   <CreateTime>1348831860</CreateTime> 
  5.   <MsgType><![CDATA[text]]></MsgType> 
  6.   <Content><![CDATA[this is a test]]></Content> 
  7.   <MsgId>1234567890123456</MsgId> 
  8. </xml> 
  • ToUserName 开发者微信号
  • FromUserName 发送方帐号(一个OpenID)
  • CreateTime 消息创建时间 (整型)
  • MsgType 消息类型,文本为text,图片为image
  • Content 文本消息内容
  • MsgId 消息id,64位整型

被动回复文本消息,就是我们回复给用户的文本消息类型为:

  1. <xml> 
  2.  <ToUserName><![CDATA[粉丝号]]></ToUserName> 
  3.  <FromUserName><![CDATA[公众号]]></FromUserName> 
  4.  <CreateTime>1460541339</CreateTime> 
  5.  <MsgType><![CDATA[text]]></MsgType> 
  6.  <Content><![CDATA[test]]></Content> 
  7. </xml> 

Content 回复的消息内容

回复的图片消息类型:

  1. <xml> 
  2.   <ToUserName><![CDATA[toUser]]></ToUserName> 
  3.   <FromUserName><![CDATA[fromUser]]></FromUserName> 
  4.   <CreateTime>12345678</CreateTime> 
  5.   <MsgType><![CDATA[image]]></MsgType> 
  6.   <Image> 
  7.     <MediaId><![CDATA[media_id]]></MediaId> 
  8.   </Image> 
  9. </xml> 

MediaId 通过素材管理中的接口上传多媒体文件,得到的id。

接收和回复消息的格式我们知道了,下面我们来看一下整个流程。

 

给你的公众号添加一个智能机器人

 

给你的公众号添加一个智能机器人

我们根据流程来修改一下我们的代码。我们增加两个文件来处理接收的消息,和回复的消息 receive.py,reply.py。

receive.py

  1. import xml.etree.ElementTree as ET 
  2. def parse_xml(web_data):    if len(web_data) == 0: 
  3.         return None 
  4.     xmlData = ET.fromstring(web_data)    msg_type = xmlData.find('MsgType').text 
  5.     if msg_type == 'text'
  6.         return TextMsg(xmlData) 
  7.     elif msg_type == 'image'
  8.         return ImageMsg(xmlData) 
  9. class Msg(object): 
  10.     def __init__(self, xmlData): 
  11.         self.ToUserName = xmlData.find('ToUserName').text 
  12.         self.FromUserName = xmlData.find('FromUserName').text 
  13.         self.CreateTime = xmlData.find('CreateTime').text 
  14.         self.MsgType = xmlData.find('MsgType').text 
  15.         self.MsgId = xmlData.find('MsgId').text 
  16. class TextMsg(Msg):    def __init__(self, xmlData): 
  17.         Msg.__init__(self, xmlData)        self.Content = xmlData.find('Content').text 
  18. class ImageMsg(Msg):    def __init__(self, xmlData): 
  19.         Msg.__init__(self, xmlData)        self.PicUrl = xmlData.find('PicUrl').text 
  20.         self.MediaId = xmlData.find('MediaId').text 

reply.py

  1. import time 
  2. class Msg(object):    def __init__(self):        pass    def send(self):        return "success"class TextMsg(Msg):    def __init__(self, toUserName, fromUserName, content):        self.__dict = dict()        self.__dict['ToUserName'] = toUserName        self.__dict['FromUserName'] = fromUserName        self.__dict['CreateTime'] = int(time.time())        self.__dict['Content'] = content    def send(self):        XmlForm = """            <xml> 
  3.                 <ToUserName><![CDATA[{ToUserName}]]></ToUserName> 
  4.                 <FromUserName><![CDATA[{FromUserName}]]></FromUserName> 
  5.                 <CreateTime>{CreateTime}</CreateTime> 
  6.                 <MsgType><![CDATA[text]]></MsgType> 
  7.                 <Content><![CDATA[{Content}]]></Content> 
  8.             </xml> 
  9.             """        return XmlForm.format(**self.__dict)class ImageMsg(Msg):    def __init__(self, toUserName, fromUserName, mediaId):        self.__dict = dict()        self.__dict['ToUserName'] = toUserName        self.__dict['FromUserName'] = fromUserName        self.__dict['CreateTime'] = int(time.time())        self.__dict['MediaId'] = mediaId    def send(self):        XmlForm = """            <xml> 
  10.                 <ToUserName><![CDATA[{ToUserName}]]></ToUserName> 
  11.                 <FromUserName><![CDATA[{FromUserName}]]></FromUserName> 
  12.                 <CreateTime>{CreateTime}</CreateTime> 
  13.                 <MsgType><![CDATA[image]]></MsgType> 
  14.                 <Image> 
  15.                 <MediaId><![CDATA[{MediaId}]]></MediaId> 
  16.                 </Image> 
  17.             </xml> 
  18.             """        return XmlForm.format(**self.__dict) 

main.py

  1. from flask import Flask 
  2. from flask import request 
  3. import hashlibimport receiveimport replyapp = Flask(__name__)@app.route("/"
  4. def index():    return "Hello World!" 
  5. # 公众号后台消息路由入口@app.route("/wechat", methods=["GET""POST"]) 
  6. def wechat(): # 验证使用的GET方法    if request.method == "GET"
  7.         signature = request.args.get('signature'
  8.         timestamp = request.args.get('timestamp'
  9.         nonce = request.args.get('nonce'
  10.         echostr = request.args.get('echostr'
  11.         token = "公众号后台填写的token" 
  12.   # 进行排序        dataList = [token, timestamp, nonce]        dataList.sort()        result = "".join(dataList) 
  13.   #哈希加密算法得到hashcode        sha1 = hashlib.sha1()        sha1.update(result.encode("utf-8")) 
  14.         hashcode = sha1.hexdigest()        if hashcode == signature: 
  15.             return echostr 
  16.         else
  17.             return "" 
  18.  else
  19.         recMsg = receive.parse_xml(request.data) 
  20.         if isinstance(recMsg, receive.Msg): 
  21.             toUser = recMsg.FromUserName            fromUser = recMsg.ToUserName            if recMsg.MsgType == 'text'
  22.                 content = recMsg.Content                replyMsg = reply.TextMsg(toUser, fromUser, content)                return replyMsg.send() 
  23.             elif recMsg.MsgType == 'image'
  24.                 mediaId = recMsg.MediaId                replyMsg = reply.ImageMsg(toUser, fromUser, mediaId)                return replyMsg.send() 
  25.             else
  26.                 return reply.Msg().send() 
  27.         else
  28.             return reply.Msg().send() 
  29. if __name__ == "__main__"
  30.     app.run(host='0.0.0.0', port=80) #公众号后台只开放了80端口 

然后我们启动 Web 服务器,去公众号后台发消息发图片测试,如果成功的话立马就会回复你相同的文字和图片。

微信提供了一个在线测试的平台,可以很方便的进行开发中的各种测试。

接入图灵机器人

首先我们去图灵机器人官网注册一个账号。然后在后台创建一个机器人。

然后我们根据图灵机器人接入文档的使用说明:

  • 编码方式:调用调用图灵API的各个环节的编码方式均为 UTF-8
  • 接口地址:http://openapi.tuling123.com/openapi/api/v2
  • 请求方式: HTTP POST
  • 请求参数:参数格式为 json

请求参数示例:

  1.  "reqType":0, 
  2.     "perception": { 
  3.         "inputText": { 
  4.             "text""附近的酒店" 
  5.         },        "inputImage": { 
  6.             "url""imageUrl" 
  7.         },        "selfInfo": { 
  8.             "location": { 
  9.                 "city""北京"
  10.                 "province""北京"
  11.                 "street""信息路" 
  12.             }        }    },    "userInfo": { 
  13.         "apiKey"""
  14.         "userId""" 
  15.     }} 

输出参数示例:

  1.     "intent": { 
  2.         "code": 10005, 
  3.         "intentName"""
  4.         "actionName"""
  5.         "parameters": { 
  6.             "nearby_place""酒店" 
  7.         }    },    "results": [ 
  8.         {          "groupType": 1, 
  9.             "resultType""url"
  10.             "values": { 
  11.                 "url""http://m.elong.com/hotel/0101/nlist/#indate=2016-12-10&outdate=2016-12-11&keywords=%E4%BF%A1%E6%81%AF%E8%B7%AF" 
  12.             }        },        {          "groupType": 1, 
  13.             "resultType""text"
  14.             "values": { 
  15.                 "text""亲,已帮你找到相关酒店信息" 
  16.             }        }    ]} 

其中 apiKey 是可以在我们创建的机器人的参数中找到,userId 是用户唯一标识。

好了,下面来编写我们的代码。我们增加一个 tuling.py 文件来接入图灵接口。

tuling.py

  1. import json 
  2. import urllibapiKey = '从你创建的机器人获得' 
  3. tulingUrl = "http://openapi.tuling123.com/openapi/api/v2" 
  4. # content 是接收的消息,userId 是用户唯一标识def tulingReply(content, userId):    requestData = {        "reqType": 0, 
  5.         "perception": { 
  6.             "inputText": { 
  7.                 "text": content 
  8.             },            "selfInfo": { 
  9.                 "location": { 
  10.                     "city""北京" 
  11.                 }            }        },        "userInfo": { 
  12.             "apiKey": apiKey, 
  13.             "userId": userId 
  14.         }    }     requestData = json.dumps(requestData).encode('utf8'
  15.     http_post = urllib.request.Request(        tulingUrl,        data=requestData, 
  16.         headers={'content-type''application/json'}) 
  17.      response = urllib.request.urlopen(http_post)    response_str = response.read().decode('utf8'
  18.     response_dic = json.loads(response_str)    results_code = response_dic['intent']['code'
  19.   # 免费版每天有固定次数,如果超过之后会返回4003错误码 
  20.     if results_code == 4003: 
  21.         results_text = "4003:%s" % response_dic['results'][0]['values']['text'
  22.     else
  23.         results_text = response_dic['results'][0]['values']['text'
  24.     return results_text 

修改 main.py

  1. from flask import Flask 
  2. from flask import request 
  3. import hashlibimport reimport tulingimport receiveimport replyapp = Flask(__name__)@app.route("/"
  4. def index():    return "Hello World!" 
  5. # 公众号后台消息路由入口@app.route("/wechat", methods=["GET""POST"]) 
  6. def wechat(): # 验证使用的GET方法    if request.method == "GET"
  7.         signature = request.args.get('signature'
  8.         timestamp = request.args.get('timestamp'
  9.         nonce = request.args.get('nonce'
  10.         echostr = request.args.get('echostr'
  11.         token = "公众号后台填写的token" 
  12.   # 进行排序        dataList = [token, timestamp, nonce]        dataList.sort()        result = "".join(dataList) 
  13.   #哈希加密算法得到hashcode        sha1 = hashlib.sha1()        sha1.update(result.encode("utf-8")) 
  14.         hashcode = sha1.hexdigest()        if hashcode == signature: 
  15.             return echostr 
  16.         else
  17.             return "" 
  18.  else
  19.         recMsg = receive.parse_xml(request.data) 
  20.         if isinstance(recMsg, receive.Msg): 
  21.             toUser = recMsg.FromUserName            fromUser = recMsg.ToUserName            if recMsg.MsgType == 'text'
  22.                 content = recMsg.Content    # userId 长度小于等于32位 
  23.                 if len(toUser) > 31: 
  24.                     userid = str(toUser[0:30]) 
  25.                 else
  26.                     userid = str(toUser)                userid = re.sub(r'[^A-Za-z0-9]+''', userid) 
  27.                 tulingReplay = tuling.tulingReply(content, userid)                replyMsg = reply.TextMsg(toUser, fromUser, tulingReplay)                return replyMsg.send() 
  28.             elif recMsg.MsgType == 'image'
  29.                 mediaId = recMsg.MediaId                replyMsg = reply.ImageMsg(toUser, fromUser, mediaId)                return replyMsg.send() 
  30.             else
  31.                 return reply.Msg().send() 
  32.         else
  33.             return reply.Msg().send() 
  34. if __name__ == "__main__"
  35.     app.run(host='0.0.0.0', port=80) #公众号后台只开放了80端口 

耶,我们的机器人完成了,马上迫不及待的去试试。

 

给你的公众号添加一个智能机器人

可以愉快的和你的机器人对话了。

后面发现了第一关注公众号后的欢迎语没有了,因为你自己的服务器接管了公众号的消息,所以原来后台设置的欢迎语就失效了。在公众号文档中看到关注/取消关注属于事件。其消息的格式如下。

  1. <xml> 
  2.   <ToUserName><![CDATA[toUser]]></ToUserName> 
  3.   <FromUserName><![CDATA[FromUser]]></FromUserName> 
  4.   <CreateTime>123456789</CreateTime> 
  5.   <MsgType><![CDATA[event]]></MsgType> 
  6.   <Event><![CDATA[subscribe]]></Event> 
  7. </xml> 

我们只需要判断一下 MsgType 是 event,然后 Event 是 subscribe,然后回复我们的欢迎语就可以了,很简单,这个我们就不详细展开了。

责任编辑:未丽燕 来源: 今日头条
相关推荐

2021-01-05 14:39:30

人工智能机器人购物

2015-12-10 21:49:32

IM机器人

2018-11-13 09:19:48

机器人人工智能系统

2021-01-28 19:34:49

人工智能AI机器人

2023-07-27 14:38:58

人工智能机器人开发

2022-07-28 22:00:47

核酸采样机器人机器人

2020-02-18 10:26:58

机器人人工智能系统

2022-07-28 11:26:41

人工智能机器人

2019-04-19 14:40:15

代码Python机器人

2021-04-01 10:51:44

机器人人工智能编程

2021-11-30 10:56:43

ChatterBot机器人人工智能

2015-05-22 11:40:00

希捷

2018-12-29 14:50:06

人工智能机器人编程语言

2018-03-28 09:28:16

CITE机器人智能系统馆

2012-06-21 14:20:16

CSS3

2021-05-24 15:29:24

人工智能机器人聊天

2021-02-15 15:17:15

人工智能机器人技术

2022-12-12 09:59:23

机器人人工智能

2023-10-05 13:04:27

腾讯机器人RoboticX

2020-12-02 13:00:17

Recast.AI聊天机器人人工智能
点赞
收藏

51CTO技术栈公众号