这两个月都在忙着设计针对银联客服业务的智能聊天机器人,上一周已经交完设计报告,这一周还和部门同事一块儿分享了系统设计及运行效果。由于时间的关系,系统原型我使用了Flask+jQuery的组合,感受用以原型能够,上线使用存在性能拓展瓶颈。最近技术调研发现Django框架中自带了实时通讯的工具包Channels,网上评价不错,所以测试使用并记录。html
在本文中,咱们将经过Django Channels打造一个聊天机器人的WEB框架,主要实现先后端的信息交互。
参考文档前端
首先要理解Django现有的请求响应策略是这样的:浏览器发出请求,Django服务器接受请求后经过路由匹配该请求到某个视图,视图将会返回一个响应并由服务器发送回浏览器。相似的请求响应在Flask实现也是如此。对于通常性的网页浏览(好比新闻阅读),这样的响应机制是没有问题的,但对于须要一个保持不断会话的请求来讲,这是行不通的,由于Django的声明周期只能存在一个请求中,它不能让服务器在没有请求的状况下不断地发送数据岛浏览器客服端。这样的场景目前正在不断地涌现,例如在线聊天室,会话机器人,以及最近很流行的微服务应用。
Channels改变了Django的工做方式,让它实现了一种包括通道、消费者和worker的worker监听的模式,全部消费者都会分配有单独的通道,worker监听通道的消息,确保消息到来时能进行处理。为了确保上述机制运行,Channels须要有三个工做层:python
Channels可让Django的框架变得更为可靠和可拓展,整个通讯的服务器数能够按需拓展,至少保证一台协议服务器和一台工做服务器便可。使用Channels后,你再也不须要组织code去为异步调用,Channls已经将一切都已经帮你准备好。
关于Channels的介绍,我推荐你们看一下第二篇参考文档,虽然全英文的,可是看起来不是很吃力,做者非常体谅我等词汇量不够的读者啊。jquery
本篇教程的开发环境以下,默认你们已经准备好。关于Windows redis的安装能够参见我以前的博文。git
asgi-redis==1.0.0 asgiref==1.0.0 attrs==16.3.0 autobahn==0.17.1 Automat==0.5.0 channels==1.0.3 constantly==15.1.0 daphne==1.0.3 Django==1.10.5 incremental==16.10.1 msgpack-python==0.4.8 redis==2.10.5 six==1.10.0 Twisted==17.1.0 txaio==2.6.1 zope.interface==4.3.3 txredisapi==1.4.4
example_channels/example 新增consumers.py,urls.py,新增templates/example子目录,并在该子目录下新增chat.html。
example_channels/example_channels中新增routing.py。完整的目录结构以下:
接下来的内容是如何修改上述文件使得所设计的框架能正常运行。github
首先修改example_channels/example_channels/setting.py的INSTALLED_APPS 参数web
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'channels', 'example', ]
并增长配置CHANNEL_LAYERS :redis
CHANNEL_LAYERS = { 'default': { 'BACKEND': 'asgi_redis.RedisChannelLayer', 'CONFIG': { 'hosts': [('localhost', 6379)], }, 'ROUTING': 'example_channels.routing.channel_routing', } }
修改example_channels/example/consumers.py文件,增长下面的代码:数据库
from channels import Group import json def ws_connect(message): Group('users').add(message.reply_channel) message.reply_channel.send({ 'text': json.dumps({ 'msg': u"你好,很高兴为你服务。", 'talk': False }) }) def ws_disconnect(message): Group('users').discard(message.reply_channel) def ws_receive(message): data = json.loads(message['text']) message.reply_channel.send({ 'text': json.dumps({ 'msg': u"我正在思考你的问题{%s}" % data["text"], 'talk': True }) })
三个函数能够认为是对三个管道的工做函数,这三个管道在Step6中进行了定义,分别是connect、disconnect、receive,这三个管道代替view起做用。django
from channels.routing import route from example.consumers import ws_connect, ws_disconnect,ws_receive channel_routing = [ route('websocket.connect', ws_connect), route('websocket.receive', ws_receive), route('websocket.disconnect', ws_disconnect), ]
到Step6为止,咱们完成了Channels的配置。咱们将在Step7中增长一个页面来测试上述的配置。
首先,咱们在example_channels/example/templates/example/chat.html添加相应的网页前端代码,确保用户能发送请求到服务器:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Test Django Channels</title> </head> <body> <div style="text-align: center;margin-top: 50px"> <input id="message" type="text" style="width: 300px" placeholder="输入消息"> <button id="send-message" style="width:80px;margin-left:20px;">发送</button> </div> <table id="show-message" style="width: 410px;margin: 0 auto;margin-top: 10px"> <tr> <td style="text-align: center; border-bottom:1px dashed #000;"><strong>聊天记录</strong></td> </tr> </table> </body> <script src="//code.jquery.com/jquery-3.1.1.min.js"></script> <script> var socket = new WebSocket('ws://' + window.location.host + '/users/'); if (socket.readyState == WebSocket.OPEN) { socket.onopen(); } socket.onmessage = function (message) { var data = JSON.parse(message.data); updateLog("机器人", data["msg"]); $("#message").val(""); $("#message").focus(); }; $("#send-message").click(function () { var inputText = $("#message").val(); if (typeof(inputText) == "undefined" || inputText.length < 1) { alert("没有输入信息"); } else { var msg = {"text": inputText}; socket.send(JSON.stringify(msg)); updateLog("你", inputText); } }); function updateLog(name, message) { var chat = $("#show-message"); var ele = "<tr><td>" + name + ": " + message + "</td></tr>" chat.append(ele); } </script> </html>
而后须要在服务器上配置该网页的路由,在example_channels/example_channels/urls.py中增长下面的代码:
from django.conf.urls import include, url from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^', include('example.urls', namespace='example')), ]
并在example_channels/example/urls.py中增长代码:
from django.conf.urls import url from example.views import chat urlpatterns = [ url(r'^$', chat, name='chat'), ]
至此,基于Django Channels的聊天机器人设计完成。搞懂上述的配置尤为是Step8须要具有基本的Django知识,这里就再也不描述。
测试代码运行效果,在Terminal中输入
D:\PWorkspace\example_channels>python manage.py runserver
运行效果以下:
本文原创,转载前请注明出处
相关的代码上传到github 。