使用websocket開發智慧聊天機器人

蟲師發表於2020-05-27

前面我們學習了非同步web框架(sanic)和http非同步呼叫庫httpx,今天我們學習websocket技術。

websocket簡介

我們知道HTTP協議是:請求->響應,如果沒有響應就一直等著,直到超時;但是有時候後臺的處理需要很長時間才能給到結果,比如30分鐘,那HTTP的請求不可能等這麼久,所以,可以通過 Ajax 輪詢來解決。那就是每間隔一段時間就請求一次。

這種傳統的模式帶來很明顯的缺點,即瀏覽器需要不斷的向伺服器發出請求,然而HTTP請求可能包含較長的頭部,其中真正有效的資料可能只是很小的一部分,顯然這樣會浪費很多的頻寬等資源。

HTML5 定義的 WebSocket 協議,能更好的節省伺服器資源和頻寬,並且能夠更實時地進行通訊。

瀏覽器通過 JavaScript 向伺服器發出建立 WebSocket 連線的請求,連線建立以後,客戶端和伺服器端就可以通過 TCP 連線直接交換資料。

好了,WebSocket就是為了解決這個問題的,感興趣去看其他資料!

智慧聊天機器人

我一開始只是為了學習WebSocket找個例子,不少例子使用了聊天功能。我稍加改進就變成了智慧聊天功能了。

通過非同步sanic非同步框架實現Web功能。官方文件裡面給個WebSocket使用的例子。

https://sanic.readthedocs.io/en/latest/sanic/websocket.html

snaic部分核心程式碼如下:

import sanic
import httpx
from sanic import Sanic
from sanic.response import json
from sanic.websocket import WebSocketProtocol
from sanic.exceptions import NotFound
from sanic.response import html
from jinja2 import Environment, PackageLoader


env = Environment(loader=PackageLoader('app', 'templates'))

app = Sanic(__name__)


@app.route('/')
async def index(request):
    """
    聊天頁面
    """
    template = env.get_template('index.html')
    html_content = template.render(title='聊天機器人')
    return html(html_content)


@app.websocket('/chat')
async def chat(request, ws):
    """
    處理聊天資訊,並返回訊息
    """
    while True:
        user_msg = await ws.recv()
        print('Received: ' + user_msg)
        intelligence_data = {"key": "free", "appid": 0, "msg": user_msg}
        r = httpx.get("http://api.qingyunke.com/api.php", params=intelligence_data)
        chat_msg = r.json()["content"]
        print('Sending: ' + chat_msg)
        await ws.send(chat_msg)


if __name__ == "__main__":
    app.error_handler.add(
        NotFound,
        lambda r, e: sanic.response.empty(status=404)
    )
    app.run(host="192.168.0.7", port=8000, protocol=WebSocketProtocol, debug=True)
  • index() 函式,返回聊天頁面。這裡用到了jinja2 模板渲染庫。
  • chat() 函式,通過webSocket實現訊息的接收、處理和返回。

智慧聊天是怎麼做到的,這裡要感謝 青雲客網路,他們提供了免費的介面。(我當時也只是抱著試試看的態度,沒想到,duang~! )

user_msg = "你好!"
intelligence_data = {"key": "free", "appid": 0, "msg": user_msg}
r = httpx.get("http://api.qingyunke.com/api.php", params=intelligence_data)
chat_msg = r.json()["content"]
print(chat_msg)

是不是超簡單。

再來看前端程式碼,主要部分:

  <div class="container theme-showcase" role="main" style="margin-top: 80px;">
      <div id="contents" style="height: 600px; background-color:#eee;"></div>
      <div>
          <textarea class="form-control" id="msg"></textarea>
          <button class="btn btn-lg btn-info" onclick="sendMsg()" style="float: right;">傳送</button>
      </div>
  </div>

  <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
  <script type="text/javascript">

          var ws = new WebSocket("ws://192.168.0.7:8000/chat");
          ws.onmessage = function(e) {
              $("#contents").append('<div class="alert alert-info" role="alert" style="float: left;">' + "機器人: " + e.data + "</div><br><br><br><br>");
          }
          function sendMsg() {
              var msg = $("#msg").val();
              $("#contents").append('<div class="alert alert-info" role="alert" style="float:right">' + msg + "</div><br><br><br><br>");
              ws.send(msg);
              $("#msg").val("");
          }

  </script>

這裡使用到了 bootstrap 前端框架,主要 呼叫部分在:

var Socket = new WebSocket(url, [protocol] );
  • Socket.send(msg): 使用連線傳送資料。
  • Socket.onmessage: 客戶端接收服務端資料時觸發。

我知道,你迫不及待想要完整的程式碼了:

https://github.com/defnngj/learning-API-test

相關文章