這兩個月都在忙着設計針對銀聯客服業務的智能聊天機器人,上一週已經交完設計報告,這一週還和部門同事一塊兒分享了系統設計及運行效果。由於時間的關係,系統原型我使用了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 。