經過Django Channels設計聊天機器人WEB框架

這兩個月都在忙着設計針對銀聯客服業務的智能聊天機器人,上一週已經交完設計報告,這一週還和部門同事一塊兒分享了系統設計及運行效果。由於時間的關係,系統原型我使用了Flask+jQuery的組合,感受用以原型能夠,上線使用存在性能拓展瓶頸。最近技術調研發現Django框架中自帶了實時通訊的工具包Channels,網上評價不錯,所以測試使用並記錄。html

在本文中,咱們將經過Django Channels打造一個聊天機器人的WEB框架,主要實現先後端的信息交互。
參考文檔前端

Django Channels介紹

首先要理解Django現有的請求響應策略是這樣的:瀏覽器發出請求,Django服務器接受請求後經過路由匹配該請求到某個視圖,視圖將會返回一個響應並由服務器發送回瀏覽器。相似的請求響應在Flask實現也是如此。對於通常性的網頁瀏覽(好比新聞閱讀),這樣的響應機制是沒有問題的,但對於須要一個保持不斷會話的請求來講,這是行不通的,由於Django的聲明週期只能存在一個請求中,它不能讓服務器在沒有請求的狀況下不斷地發送數據島瀏覽器客服端。這樣的場景目前正在不斷地涌現,例如在線聊天室,會話機器人,以及最近很流行的微服務應用。
Channels改變了Django的工做方式,讓它實現了一種包括通道、消費者和worker的worker監聽的模式,全部消費者都會分配有單獨的通道,worker監聽通道的消息,確保消息到來時能進行處理。爲了確保上述機制運行,Channels須要有三個工做層:python

  1. 接口服務器,Django和用戶(瀏覽器)之間通訊的橋樑,包括一個實現WSGI協議的適配器和一個獨立的websocket服務器。
  2. 通道後端, 在接口服務器和worker之間傳遞消息,由插拔式的python代碼和存儲組成,存儲能夠是內存、數據庫或者redis,推薦使用redis,兼具其他二者的優勢。
  3. worker,監聽全部channel,當有新消息到來時候喚醒功能函數。

Channels可讓Django的框架變得更爲可靠和可拓展,整個通訊的服務器數能夠按需拓展,至少保證一臺協議服務器和一臺工做服務器便可。使用Channels後,你再也不須要組織code去爲異步調用,Channls已經將一切都已經幫你準備好。
關於Channels的介紹,我推薦你們看一下第二篇參考文檔,雖然全英文的,可是看起來不是很吃力,做者非常體諒我等詞彙量不夠的讀者啊。jquery

實驗教程

本篇教程的開發環境以下,默認你們已經準備好。關於Windows redis的安裝能夠參見我以前的博文git

  • Windows7
  • Python2.7.13
  • pyCharm2016.2
  • redis 3.0.53 Windows x64
    本實驗的目的是搭建一個用於聊天機器人的WEB交互框架,能夠直接拉到最下方看實現效果。
    note: 下面的代碼運行須要redis服務開啓了6379端口正常運行。

Step1:安裝第三方工具包,建議經過pip install -r的方式安裝。

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

Step2:新建django項目「example_channels」,建議用pycharm新建很方便

Step3: 分別在如下目錄新建文件:

example_channels/example 新增consumers.py,urls.py,新增templates/example子目錄,並在該子目錄下新增chat.html。
example_channels/example_channels中新增routing.py。完整的目錄結構以下:

接下來的內容是如何修改上述文件使得所設計的框架能正常運行。github

Step4:修改配置文件,增長channels的配置,你能夠認爲這是配置Channels的管道

首先修改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',
    }
}

Step5:增長worker來對管道中的消息進行監控

修改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

Step6:在example_channels/example_channels/routing.py中增長管道的定義

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中增長一個頁面來測試上述的配置。

Step8:聊天機器人前端框架設計

首先,咱們在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

相關文章
相關標籤/搜索