这是我构建一个简单的FacebookMessenger机器人的记录。功能很简单,它是一个回显机器人,只打印回用户写的内容。回显服务器类似于服务器的“HelloWorld”示例。这个项目的目的不是构建一个成熟的Messenger机器人,而是让您了解如何构建一个小型机器人以及如何将所有内容组合在一起。技术栈使用的技术栈:使用Heroku作为后端主机。对于这个级别的教程,免费级别就足够了。echobot不需要任何类型的数据持久性,因此不需要数据库。Python是我们的首选语言。选择了2.7版,尽管它很容易以最小的更改移植到Pyhton3。Flask作为Web开发框架。这是一个非常轻量级的框架,非常适合小型项目或微服务。***Git版本控制系统用于维护代码和部署到Heroku。值得一提的是:Virtualenv。这个python工具用于创建干净的python库“环境”,以便您可以只安装必要的要求并最小化应用程序大小。机器人架构Messenger机器人由响应两种类型请求的服务器组成:GET请求用于身份验证。它们与您注册的Facebook验证码一起由Messenger发送。POST请求用于实际通信。一个典型的工作流程是,机器人将通过用户发送带有消息数据的POST请求来建立通信,我们将处理该数据并发回我们的POST请求。如果请求完全成功(返回200OK状态代码),我们也会以200OK状态代码响应原始Messenger请求。本教程应用程序将托管在Heroku上,它为部署应用程序提供了一个优雅而简单的界面。如前所述,免费套餐足以满足本教程的需求。应用程序部署并运行后,我们将创建一个Facebook应用程序并将其连接到我们的应用程序,以便Messenger知道将请求发送到哪里,这就是我们的机器人。机器人服务器的基本服务器代码可以在Chatbot项目的Github用户hult(MagnusHult)上找到,其中一些代码修改仅回显消息并修复了我遇到的一些错误。最终版本的服务端代码如下:fromflaskiimportFlask,requestimportjsonimportrequestsapp=Flask(__name__)###这里需要填写grantedpageaccesstoken(PAT)###由将要创建的Facebook应用提供。PAT=''@app.route('/',methods=['GET'])defhandle_verification():print"HandlingVerification."ifrequest.args.get('hub.verify_token','')=='my_voice_is_my_password_verify_me':print"Verificationsuccessful!"returnrequest.args.get('hub.challenge','')else:print"Verificationfailed!"return'Error,wrongvalidationtoken'@app.route('/',methods=['POST'])defhandle_messages():print"HandlingMessages"payload=request.get_data()printpayloadforsender,messageinmessaging_events(payload):print"Incomingfrom%s:%s"%(sender,message)send_message(PAT,sender,message)return"ok"defmessaging_events(有效载荷):“”“从提供的有效载荷生成元组(发件人id,message_text)。”“”data=json.loads(有效载荷)messaging_events=data[“entry”][0][“messaging”]foreventinmessaging_events:if“message”ineventand“文本”inevent[“消息”]:yieldevent[“发件人”]["id"],event["message"]["text"].encode('unicode_escape')else:yieldevent["sender"]["id"],"Ican'techothis"defsend_message(token,recipient,text):"""Sendthemessagetexttorecipientwithidrecipient."""r=requests.post("https://graph.facebook.com/v2.6/me/messages",params={"access_token":token},data=json.dumps({"recipient":{"id":recipient},"message":{"text":text.decode('unicode_escape')}}),headers={'Content-type':'application/json'})ifr.status_code!=requests.codes.ok:printr.textif__name__=='__main__':app.run()我们把代码分解一下***部分是引入需要的依赖:fromflaskiimportFlask,requestimportjsonimportrequests接下来我们定义两个函数(使用特定于Flask的app.route装饰器)来处理对我们的机器人的GET和POST请求。@app.route('/',methods=['GET'])defhandle_verification():print"HandlingVerification".ifrequest.args.get('hub.verify_token','')=='my_voice_is_my_password_verify_me':print"验证成功!"returnrequest.args.get('hub.challenge','')else:print"Verificationfailed!"return'Error,wrongvalidationtoken'当我们创建Facebook应用程序时,我们声明的Messenger将发送verify_token对象。我们必须自己验证。***我们将“hub.challenge”返回给Messenger。处理POST请求的函数比较有意思:@app.route('/',methods=['POST'])defhandle_messages():print"HandlingMessages"payload=request.get_data()printpayloadforsender,messageinmessaging_events(payload):print"Incomingfrom%s:%s"%(sender,message)send_message(PAT,sender,message)return"ok"调用时,我们抓取消息有效负载,使用函数messaging_events对其进行反汇编,并提取发件人身份和发送的实际消息,产生一个可以在循环中处理的python迭代器。请注意,Messenger可能会针对每个请求发送多条消息。defmessaging_events(payload):"""从提供的payload中生成(sender_id,message_text)的元组。"""data=json.loads(payload)messaging_events=data["entry"][0]["messaging"]foreventinmessaging_events:if“消息”inevents“文本”inevent[“消息”]:yieldevent[“发件人”][“id”],事件[“消息”][“文本”]。编码('unicode_escape')其他:yieldevent[“发件人"]["id"],"Ican'techothis"来迭代每条消息,我们调用send_message函数,然后我们使用FacebookGraph消息API向Messenger发出一个POST请求。在此期间,我们没有回复我们被阻止的原始Messenger请求。这会导致超时和5XX错误。上面的情况是我遇到错误时发现的。用户发送表情的时候,其实发送的是unicode标识,但是被Python编码错了,最后我们发回的是一些乱码。这个返回Messenger的POST请求永远不会完成,这将导致5xx状态代码被返回到原始请求,表明该服务不可用。这可以通过使用encode('unicode_escape')包装消息然后在我们将其发回之前使用decode('unicode_escape')对其进行解码来解决。defsend_message(token,recipient,text):"""Sendthemessagetexttorecipientwithidrecipient."""r=requests.post("https://graph.facebook.com/v2.6/me/messages",params={"access_token":token},data=json.dumps({"recipient":{"id":recipient},"message":{"text":text.decode('unicode_escape')}}),headers={'Content-type':'application/json'})ifr.status_code!=requests.codes.ok:printr.text部署到Heroku一旦按照我希望的方式设置了代码,它就会进入下一步。部署应用程序。那么,怎么做呢?我以前在Heroku上部署过应用程序(主要是Rails),但是我总是按照某种教程来做,使用的配置已经创建。就本文而言,我需要从头开始。幸运的是,有官方的Heroku文档可以提供帮助。该文档很好地描述了运行应用程序所需的最低要求。长话短说,除了我们的代码之外,我们还需要两个文件。第一个文件是“requirements.txt”,其中列出了应用程序运行所依赖的库。所需的第二个文件是“Procfile”。这个文件告诉Heroku如何运行我们的服务。此外,此文件只需要一点内容:web:gunicornechoserver:appHeroku将其解释为意味着我们的应用程序通过运行echoserver.py启动,并且该应用程序将使用gunicorn作为Web服务器。我们使用额外的Web服务器,因为它与性能有关,如上面的Heroku文档中所述:并发处理传入HTTP请求的Web应用程序比一次只处理一个请求的Web应用程序更有效地利用。测试机器的资源。出于这个原因,我们建议使用支持并发请求的Web服务器来部署和运行生产级服务。Django和Flask网络框架提供了一个方便的内置网络服务器,但这些阻塞服务器一次只能处理一个请求。如果你把这种服务部署到Heroku上,你的测试机资源利用率会很差,应用会感觉反应迟钝。Gunicorn是用于WSGI应用程序的纯PythonHTTP服务器。允许您通过在单个测试机器上运行多个Python进程来同时运行各种Python应用程序。它在性能、灵活性和易于配置之间取得了完美的平衡。回到我们之前提到的“requirements.txt”文件,让我们看看它是如何与Virtualenv工具相匹配的。在许多情况下,您的开发机器可能安装了许多python库。您不想在部署应用程序时加载所有这些库,但可能很难确定您实际使用的是哪些库。Virtualenv可以创建一个新的空白虚拟环境,这样您就可以只安装应用程序需要的库。您可以运行以下命令来检查当前安装了哪些库:kostis@KostisMBP~$pipfreezecycler==0.10.0Flask==0.10.1gunicorn==19.6.0itsdangerous==0.24Jinja2==2.8MarkupSafe==0.23matplotlib==1.5.1numpy==1.10.4pyparsing==2.1.0python-dateutil==2.5.0pytz==2015.7requests==2.10.0scipy==0.17.0six==1.10.0virtualenv==15.0.1Werkzeug==0.11.10注意:pip这些工具应该已经与Python一起安装在您的机器上。如果没有,请查看官方网站如何安装它。现在让我们使用Virtualenv创建一个新的空白环境。首先,我们为我们的项目创建一个新文件夹,然后进入目录:kostis@KostisMBPprojects$mkdirechoserverkostis@KostisMBPprojects$cdechoserver/kostis@KostisMBPechoserver$现在创建一个名为echobot的新环境。运行下面的source命令激活它,然后用pipfreeze检查,我们可以看到它现在是空的。kostis@KostisMBPechoserver$virtualenvechobotkostis@KostisMBPechoserver$sourceechobot/bin/activate(echobot)kostis@KostisMBPechoserver$pipfreeze(echobot)kostis@KostisMBPechoserver$我们可以安装所需的库。我们需要烧瓶、gunicorn和请求。安装好后,我们创建一个requirements.txt文件:0.11gunicorn==19.6.0itsdangerous==0.24Jinja2==2.8MarkupSafe==0.23requests==2.10.0Werkzeug==0.11.10(echobot)kostis@KostisMBPechoserver$pipfreeze>requirements.tx以上完成后,我们创建echoserver.py文件与python代码,然后使用前面提到的命令创建Procfile,我们的最终文件/文件夹如下:(echobot)kostis@KostisMBPechoserver$lsProcfileechobotechoserver.pyrequirements.txt我们现在准备上传到Heroku。我们需要做两件事。***是安装Herokutoolbet,如果它还没有安装的话(查看Heroku获取详细信息)。第二种是通过HerokuWeb界面创建一个新的Heroku应用程序。单击右上角的大加号,然后选择“创建新应用”。为您的应用选择一个名称,然后单击“创建应用”。您将被重定向到应用程序的控制面板,您可以在其中找到有关如何将应用程序部署到Heroku的详细说明。(echobot)kostis@KostisMBPechoserver$herokulogin(echobot)kostis@KostisMBPechoserver$gitinit(echobot)kostis@KostisMBPechoserver$herokugit:remote-a
