《Python實戰進階》No 7: 一個AI大模型聊天室的構建-基于WebSocket 實時通信開發實戰

第7集: 一個AI大模型聊天室的構建-基于WebSocket 實時通信開發實戰

在現代 Web 開發中,實時通信已經成為許多應用的核心需求。無論是聊天應用、股票行情推送,還是多人協作工具,WebSocket 都是實現高效實時通信的最佳選擇之一。本集將一個AI大模型聊天室的實戰案例,帶你深入了解 WebSocket 的基礎知識、Python 實現方式以及實際應用場景。
在這里插入圖片描述
以下截圖為 AI助手多人聊天室 頁面,完整代碼和搭建說明在第4節中提供:
在這里插入圖片描述


在這里插入圖片描述

1. WebSocket 基礎知識

1.1 WebSocket 協議與 HTTP 的區別

WebSocket 是一種全雙工通信協議,允許客戶端和服務器之間建立持久連接,從而實現低延遲的數據傳輸。與傳統的 HTTP 請求-響應模式相比,WebSocket 有以下特點:

特性HTTPWebSocket
連接類型短連接(每次請求后斷開)長連接(持久化)
數據傳輸方向單向(客戶端 -> 服務器)雙向(客戶端 <-> 服務器)
性能每次請求需要重新建立連接一次握手后持續通信
應用場景頁面加載、表單提交等實時聊天、股票行情推送等

在這里插入圖片描述

1.2 WebSocket 的應用場景

WebSocket 的實時性和高效性使其適用于以下場景:

  • 實時聊天:用戶之間的即時消息傳遞。
  • 股票行情推送:實時更新股票價格。
  • 在線游戲:玩家之間的實時互動。
  • 通知系統:訂單狀態更新、系統告警等。

1.3 WebSocket 的握手過程與數據幀格式

WebSocket 的通信從 HTTP 握手開始,握手完成后切換到 WebSocket 協議。以下是握手過程的簡化流程:

  1. 客戶端發送一個帶有 Upgrade: websocket 的 HTTP 請求。
  2. 服務器響應 101 Switching Protocols,表示協議切換成功。
  3. 雙方通過 WebSocket 協議進行數據傳輸。

WebSocket 數據幀格式如下:

  • FIN:標識是否為最后一幀。
  • Opcode:操作碼(如文本幀、二進制幀)。
  • Payload:實際傳輸的數據。

2. Python 中實現 WebSocket

2.1 使用 websockets 庫構建 WebSocket 服務器和客戶端

websockets 是一個簡單易用的 Python 庫,用于實現 WebSocket 通信。以下是一個簡單的示例:

Python版本:3.11.5, 建議新建一個虛擬環境目錄 websocket **
** 安裝依賴:

python -m venv websocket
pip install asyncio websockets
服務器端代碼 server.py
import asyncio
import websocketsasync def echo(websocket):# 注意這里移除了 path 參數async for message in websocket:print(f"Received: {message}")await websocket.send(f"Echo: {message}")async def main():# 在異步函數內創建并啟動服務器server = await websockets.serve(echo, "localhost", 8765)print("WebSocket server started at ws://localhost:8765")# 保持服務器運行await asyncio.Future()  # 這會一直運行,直到被取消# 使用新的異步運行方式
if __name__ == "__main__":asyncio.run(main())
客戶端代碼 client.py
import asyncio
import websocketsasync def hello():uri = "ws://localhost:8765"async with websockets.connect(uri) as websocket:await websocket.send("Hello, WebSocket!")response = await websocket.recv()print(f"Received: {response}")# 使用新的異步運行方式
if __name__ == "__main__":asyncio.run(hello())

分別在兩個cmd啟動同一個虛擬環境 scripts/activate ,然后先運行 python server.py
在另一個cmd運行 python client.py
運行上述代碼后,客戶端會向服務器發送消息,服務器會返回一個回顯消息。
注意:要開兩個cmd或shell窗口,一個運行服務,一個運行客戶端

客戶端

(websocket) D:\python_projects\websocket>python client.py
Received: Echo: Hello, WebSocket!

服務端

WebSocket server started at ws://localhost:8765
Received: Hello, WebSocket!

2.2 使用 Flask 或 Django 集成 WebSocket

對于 Flask 和 Django,可以分別使用 Flask-SocketIODjango Channels 來集成 WebSocket。
以下是簡單示例,不用上手代碼,在第4節有完整的基于socket的AI聊天室代碼

Flask-SocketIO 示例
from flask import Flask, render_template
from flask_socketio import SocketIOapp = Flask(__name__)
socketio = SocketIO(app)@app.route("/")
def index():#return render_template("index.html")return "WebSocket Server is running!"@socketio.on("message")
def handle_message(message):print(f"Received: {message}")socketio.emit("response", f"Echo: {message}")if __name__ == "__main__":socketio.run(app, host="0.0.0.0", port=5000)
Django Channels 示例
  1. 安裝 channels 并配置 settings.py
  2. 編寫消費者邏輯:
from channels.generic.websocket import AsyncWebsocketConsumer
import jsonclass ChatConsumer(AsyncWebsocketConsumer):async def connect(self):await self.accept()async def disconnect(self, close_code):passasync def receive(self, text_data):text_data_json = json.loads(text_data)message = text_data_json["message"]await self.send(text_data=json.dumps({"message": f"Echo: {message}"}))

3. 性能優化與安全性

3.1 如何處理高并發連接

  • 使用異步框架(如 asynciouvloop)提高性能。
  • 部署負載均衡器(如 Nginx)分擔流量壓力。

3.2 WebSocket 的安全問題

  • 防止 CSRF 攻擊:驗證 WebSocket 連接來源。
  • 數據加密:使用 SSL/TLS 加密 WebSocket 通信。

3.3 使用 SSL/TLS 加密 WebSocket 通信

在生產環境中,建議使用 HTTPS 和 WSS(WebSocket Secure)。以下是一個啟用 SSL 的示例:

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_context.load_cert_chain(certfile="cert.pem", keyfile="key.pem")start_server = websockets.serve(echo, "localhost", 8765, ssl=ssl_context)

4. 實際案例

構建一個基于AI的Websocket聊天室

使用flask框架,基于本地部署的ollama提供大模型接口,構建一個用戶與人工智能助手的聊天室。

主程序代碼 websocket_demo.py :

from flask import Flask, render_template
from flask_socketio import SocketIO, emit
import requests
import jsonapp = Flask(__name__)
socketio = SocketIO(app)# Ollama API 配置
OLLAMA_API_URL = "http://localhost:11434/api/generate"
MODEL_NAME = "glm4:latest"  # 可以根據你本地安裝的模型修改# 使用 Ollama 生成回復
def get_ollama_response(prompt):try:payload = {"model": MODEL_NAME,"prompt": prompt,"stream": False}response = requests.post(OLLAMA_API_URL, json=payload)if response.status_code == 200:result = response.json()return result.get("response", "抱歉,我無法生成回復。")else:print(f"Ollama API 錯誤: {response.status_code}")return "抱歉,連接大模型時出現錯誤。"except Exception as e:print(f"調用 Ollama 時出錯: {str(e)}")return "抱歉,連接大模型時出現錯誤。"# 路由:返回 HTML 頁面
@app.route("/")
def index():return render_template("index.html")# WebSocket 事件處理
@socketio.on("message")
def handle_message(data):print(f"Received message: {data}")user_message = data["message"]username = data["username"]# 發送用戶原始消息emit("response", {"message": user_message, "username": username}, broadcast=True)# 獲取 Ollama 的回復prompt = f"用戶 {username} 說: {user_message}\n請簡短回復:"ai_response = get_ollama_response(prompt)# 發送 AI 回復emit("response", {"message": ai_response, "username": "AI助手"}, broadcast=True)if __name__ == "__main__":print("Starting Flask-SocketIO WebSocket server with Ollama integration...")socketio.run(app, host="0.0.0.0", port=5000)

在虛擬環境主目錄下新建一個templates文件夾,放置以下index.html頁面文件:

<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>基于AI的 WebSocket 聊天室</title><style>body {font-family: Arial, sans-serif;max-width: 800px;margin: 0 auto;padding: 20px;}#chat-box {height: 400px;border: 1px solid #ccc;padding: 10px;margin-bottom: 10px;overflow-y: auto;}.message {margin-bottom: 10px;padding: 8px;border-radius: 5px;}.user-message {background-color: #e6f7ff;}.system-message {background-color: #f0f0f0;font-style: italic;}.username {font-weight: bold;margin-right: 10px;}#message-form {display: flex;}#message-input {flex-grow: 1;padding: 8px;margin-right: 10px;}</style>
</head>
<body><h1>WebSocket 聊天室</h1><div id="username-container"><label for="username">請輸入用戶名:</label><input type="text" id="username" value="用戶"><button id="join-btn">加入聊天</button></div><div id="chat-container" style="display: none;"><div id="chat-box"></div><form id="message-form"><input type="text" id="message-input" placeholder="輸入消息..." autocomplete="off"><button type="submit">發送</button></form></div><script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script><script>document.addEventListener('DOMContentLoaded', () => {const socket = io();const chatBox = document.getElementById('chat-box');const messageForm = document.getElementById('message-form');const messageInput = document.getElementById('message-input');const usernameInput = document.getElementById('username');const joinBtn = document.getElementById('join-btn');const usernameContainer = document.getElementById('username-container');const chatContainer = document.getElementById('chat-container');let username = '';// 加入聊天joinBtn.addEventListener('click', () => {username = usernameInput.value.trim() || '用戶';usernameContainer.style.display = 'none';chatContainer.style.display = 'block';// 發送加入消息socket.emit('message', {message: '加入了聊天室',username: username});});// 發送消息messageForm.addEventListener('submit', (e) => {e.preventDefault();const message = messageInput.value.trim();if (message) {socket.emit('message', {message: message,username: username});messageInput.value = '';}});// 接收消息socket.on('response', (data) => {const messageDiv = document.createElement('div');messageDiv.className = data.username === '系統' ? 'message system-message' : 'message user-message';const usernameSpan = document.createElement('span');usernameSpan.className = 'username';usernameSpan.textContent = data.username + ':';const messageContent = document.createElement('span');messageContent.textContent = data.message;messageDiv.appendChild(usernameSpan);messageDiv.appendChild(messageContent);chatBox.appendChild(messageDiv);// 自動滾動到底部chatBox.scrollTop = chatBox.scrollHeight;});});</script>
</body>
</html> 

運行主程序:

python websocket_demo.py

cmd窗口輸出如下:

Starting Flask-SocketIO WebSocket server with Ollama integration...* Serving Flask app 'websocket_demo'* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.   * Running on all addresses (0.0.0.0)* Running on http://127.0.0.1:5000* Running on http://192.168.31.52:5000
Press CTRL+C to quit
127.0.0.1 - - [27/Feb/2025 21:29:42] "GET /socket.io/?EIO=4&transport=polling&t=PL7cKLt HTTP/1.1" 200 -
127.0.0.1 - - [27/Feb/2025 21:29:42] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [27/Feb/2025 21:29:42] "GET /socket.io/?EIO=4&transport=polling&t=PL7cKV2 HTTP/1.1" 200 -
127.0.0.1 - - [27/Feb/2025 21:29:42] "POST /socket.io/?EIO=4&transport=polling&t=PL7cKVc&sid=IYT6sUZFDo9kVtxHAAAB HTTP/1.1" 200 -
127.0.0.1 - - [27/Feb/2025 21:29:42] "GET /socket.io/?EIO=4&transport=polling&t=PL7cKVd&sid=IYT6sUZFDo9kVtxHAAAB HTTP/1.1" 200 -
127.0.0.1 - - [27/Feb/2025 21:29:42] "GET /socket.io/?EIO=4&transport=polling&t=PL7cKZE&sid=IYT6sUZFDo9kVtxHAAAB HTTP/1.1" 200 -

在瀏覽器窗口輸入:localhost:5000

在這里插入圖片描述


輸入用戶名 哪吒

在這里插入圖片描述
隨便聊一句:
在這里插入圖片描述
聊天室支持多人聊天,新開一個瀏覽器窗口輸入:localhost:5000
輸入用戶名:孫悟空,在所有用戶窗口會同步更新所有聊天消息。

在這里插入圖片描述

一個實際可用的多人AI聊天室就構建完成了,

用戶可以根據需要修改大模型資源接口和prompt以達到定制效果。

5. 擴展方向

5.1 對比 WebSocket 與其他實時通信技術

  • Server-Sent Events (SSE):僅支持服務器到客戶端的單向通信。
  • 長輪詢:模擬實時通信,但效率較低。

5.2 在微服務架構中使用 WebSocket

  • 將 WebSocket 服務獨立部署為一個微服務。
  • 使用消息隊列(如 RabbitMQ)解耦 WebSocket 服務與其他服務。

5.3 基于DEMO進行開發

  • 增加多方通訊的管理,利用大模型進行聊天邏輯和內容管控。
  • 完善聊天室的功能,比如表情包、圖片和語音文件的上傳。

下集預告

下一集我們將聚焦于 No8: 部署 Flask/Django 應用到云平臺(Aliyun)。你將學習如何將本地開發的應用部署到阿里云,包括容器化、數據庫配置、自動化部署等內容。


希望這篇博客對你有所幫助!如果需要進一步擴展或調整內容,請隨時告訴我。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/896669.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/896669.shtml
英文地址,請注明出處:http://en.pswp.cn/news/896669.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

輪式機器人在復雜地形中如何選擇合適的全局路徑規劃算法?

已思考完成 收起 嗯&#xff0c;用戶問的是輪式機器人在復雜地形中如何選擇合適的全局路徑規劃算法。首先&#xff0c;我需要理解復雜地形可能帶來的挑戰&#xff0c;比如崎嶇的路面、動態障礙物、非結構化環境等等。輪式機器人在這里的運動控制需要考慮地形通過性、穩定性&…

Mysql100道高頻面試題

一、基礎概念 1. 什么是數據庫&#xff1f;DBMS的作用是什么&#xff1f; 數據庫&#xff1a;是按照數據結構來組織、存儲和管理數據的倉庫。它允許用戶高效地訪問和管理數據。 DBMS&#xff08;數據庫管理系統&#xff09;&#xff1a;是一種軟件系統&#xff0c;用于創建和…

React底層原理詳解

React中Element&Fiber對象、WorkInProgress雙緩存、Reconcile&Render&Commit、第一次掛載過程詳解 在面試中介紹React底層原理時&#xff0c;需遵循邏輯清晰、層次分明、重點突出的原則&#xff0c;結合技術深度與實際應用場景。以下是結構化回答模板&#xff1a;…

qt5的中文亂碼問題,QString、QStringLiteral 為 UTF-16 編碼

qt5的中文亂碼問題一直沒有很明確的處理方案。 今天處理進程間通信時&#xff0c;也遇到了qt5亂碼問題&#xff0c;一邊是設置的GBK&#xff0c;一邊設置的是UTF8&#xff0c;單向通信約定采用UTF8。 發送端保證發的是UTF8字符串&#xff0c;因為UTF8在網絡數據包中沒有字節序…

解鎖瀏覽器內置API,助力跨標簽/跨頁面數據通信

1 BrodcastChanner 概念 BroadcastChannel接口表示給定源的任何瀏覽上下文都可以訂閱的命名頻道。它允許同源的不同瀏覽器窗口、標簽頁、frame 或者 iframe 下的不同文檔之間相互通信。消息通過message事件進行廣播&#xff0c;該事件在偵聽該頻道的所有BroadcastChannel對象上…

Mysql-如何理解事務?

一、事務是什么東西 有些場景中&#xff0c;某個操作需要多個sql配合完成&#xff1a; 例如&#xff1a; 李四這個月剩下的前不夠交房租了&#xff0c;找張三借1000元急用&#xff1a; &#xff08;1&#xff09;給張三的賬戶余額 減去1000元 updata 賬戶表 set money money -…

《deepseek FlashMLA :高效的 MLA 解碼內核》:此文為AI自動翻譯

FlashMLA GitHub - deepseek-ai/FlashMLA FlashMLA 是適用于 Hopper GPU 的高效 MLA 解碼內核&#xff0c;針對可變長度序列服務進行了優化。 當前發布&#xff1a; BF16、FP16塊大小為 64 的分頁 kvcache 快速開始 安裝 python setup.py install 基準 python tests/test_fl…

Windows對比MacOS

Windows對比MacOS 文章目錄 Windows對比MacOS1-環境變量1-Windows添加環境變量示例步驟 1&#xff1a;打開環境變量設置窗口步驟 2&#xff1a;添加系統環境變量 2-Mac 系統添加環境變量示例步驟 1&#xff1a;打開終端步驟 2&#xff1a;編輯環境變量配置文件步驟 3&#xff1…

藍橋杯 之 填空題-位運算與循環

文章目錄 循環握手問題門牌制作-循環小球反彈幸運數藝術與籃球跑步 位運算3個1美麗的2024 位運算 可以關注這個Lowbit(x) 如何判斷最低位是否是1&#xff1f; num&1 1就說明num最低位是1 循環 循環 握手問題 握手問題 思路分析&#xff1a; 可以直接計算出來&#xff…

Java進階——反射機制超全詳解

反射能在運行時動態操作類和對象的能力&#xff0c;極大地增強了程序的靈活性。但是反射的使用也伴隨著性能開銷和安全風險。本文將由博主帶你一起深入探討 Java 反射的核心概念、關鍵類和方法&#xff0c;以及在日常開發中的應用場景。 本文目錄 一、反射的核心概念1. 運行時類…

OAK相機的抗震性測試

在工業環境中&#xff0c;雙目視覺相機必須具備與工作環境同等的堅固性。鑒于部分客戶會將我們的相機應用于惡劣環境&#xff08;例如安裝在重型機械上&#xff09;&#xff0c;我們依據EN 60068-2-6:2008標準對相機進行了振動耐受性測試。 測試涉及的相機型號包括&#xff1a…

Express MVC

1. 安裝依賴 npm init -y npm install express npm install --save-dev typescript ts-node ejs types/node types/express tsc --init 2. 項目目錄結構如下&#xff0c;沒有的手動創建 /my-app/src/modelsuser.ts/viewsindex.ejsuserList.ejs/controllersuserController.ts…

apache-maven-3.2.1

MAVEN_HOME D:\apache-maven-3.2.1 PATH D:\apache-maven-3.2.1\bin cmd mvn -v <localRepository>d:\localRepository</localRepository> setting.xml <?xml version"1.0" encoding"UTF-8"?><!-- Licensed to the Apache Soft…

合并兩個有序鏈表:遞歸與迭代的實現分析

合并兩個有序鏈表&#xff1a;遞歸與迭代的實現分析 在算法與數據結構的世界里&#xff0c;鏈表作為一種基本的數據結構&#xff0c;經常被用來解決各種問題。特別是對于有序鏈表的合并&#xff0c;既是經典面試題&#xff0c;也是提高編程能力的重要練習之一。合并兩個有序鏈…

破解密碼防線:滲透測試中的密碼攻擊手法匯總

密碼是網絡安全中的一道重要防線&#xff0c;然而&#xff0c;若密碼策略不嚴密&#xff0c;往往會為攻擊者提供可乘之機。本文將簡要介紹滲透測試中關于密碼的幾種常見攻擊思路和手法。 1. 確認使用默認及常見的賬號密碼 在滲透測試的初期&#xff0c;攻擊者通常會嘗試使用系…

CSS Selectors

當然&#xff0c;理解純CSS選擇器&#xff08;CSS Selectors&#xff09;對于進行UI自動化測試非常重要。CSS選擇器允許您通過元素的屬性、層級關系、類名、ID等來精準定位頁面上的元素。下面我將詳細講解CSS選擇器的常見用法&#xff0c;并結合您的需求提供具體的示例。 1. 基…

【java】@Transactional導致@DS注解切換數據源失效

最近業務中出現了多商戶多租戶的邏輯&#xff0c;所以需要分庫&#xff0c;項目框架使用了mybatisplus所以我們自然而然的選擇了同是baomidou開發的dynamic.datasource來實現多數據源的切換。在使用初期程序運行都很好&#xff0c;但之后發現在調用com.baomidou.mybatisplus.ex…

淺入淺出Selenium DevTools

前言 在自動化測試領域&#xff0c;Selenium一直是主流工具之一。隨著前端技術的不斷發展&#xff0c;瀏覽器的功能也在不斷豐富。 Selenium 3版本前&#xff0c;一套通用的采集流程如上圖所示&#xff1a; 打開Charles&#xff0c;設置Session自動導出頻次及導出路徑Seleniu…

04 路由表的IP分組傳輸過程

目錄 1、路由表的核心結構 2、IP分組傳輸過程和數據包轉發過程 2.1、IP分組傳輸過程 2.2、數據包轉發過程 2.3、IP分組傳輸過程和數據包轉發的區別 3、數據包的變化 3.1、拓撲結構 3.2、傳輸過程詳解&#xff08;主機A → 主機B&#xff09; 3.2.1、主機A發送數據 3.2…

【子網掩碼計算器:Python + Tkinter 實現】

子網掩碼計算器&#xff1a;Python Tkinter 實現 引言代碼功能概述代碼實現思路1. 界面設計2. 功能實現3. 事件處理 子網掩碼計算器實現步驟1. 導入必要的庫2. 定義主窗口類 SubnetCalculatorApp3. 創建菜單欄4. 創建界面組件5. 判斷 IP 地址類別6. 計算子網信息7. 其他功能函…