【玩轉全棧】—— Django+vue3+訊飛星火API 實現前端頁面實時AI答復

技術棧:vue3 + element-plus + axios + pinia + router + Django5 + websocket + 訊飛星火API

本文將實現一個 AI 聊天對話功能,將前端用戶輸入問題以及之前對話發送給后端,通過 api 訪問大模型,返回前端實時對話數據。

調用?訊飛星火API 大家可以看這篇(文A):創作中心-CSDN

前端 vue3 +后端 Django5 連接可以看這篇(文B):【玩轉全棧】—— Django 連接 vue3 保姆級教程,前后端分離式項目2025年4月最新!!!_django vue3 前后端分離-CSDN博客

Django5 配置 websocket(文C):【全棧開發】---- 一文掌握 Websocket 原理,并用 Django 框架實現_django websocket-CSDN博客
【玩轉全棧】---- Django 基于 Websocket 實現群聊(解決channel連接不了)_django websocket聊天室-CSDN博客

目錄

效果預覽:

前期準備

代碼實現

后端

前端

資源獲取


效果預覽:

Django連接vue3,接入ai

前期準備

文A 已講解如何在 Django 調用免費的訊飛星火API 。

文B 已講解如何連接前端 vue3 、后端 Django5,配置 vite.config 文件代理,后端解決跨域等等。還有如何在前端獲取 token ,并在前端發送 Post 請求時以攜帶該 token 以越過安全驗證,使得后端 Django 能接收到數據,這里不過多贅述,結尾也有相關資源可以下載。

文C 以講解如何在 Django 中配置 websocket 環境,以及如何實現聊天室功能。

沒實現的可以先回去實現。

代碼實現

后端

Django 配置好 websocket? ,定義 AI 消費者及其路徑:

routings.py:

from django.urls import re_path
from . import consumerswebsocket_urlpatterns = [re_path(r'ws/chat/', consumers.ChatConsumer.as_asgi()),
]

consumers.py:

import json
import asyncio
import httpx
from channels.generic.websocket import AsyncWebsocketConsumer
import reclass ChatConsumer(AsyncWebsocketConsumer):async def connect(self):print("AI消費者已連接")await self.accept()async def disconnect(self, close_code):print("AI消費者已斷開")passasync def receive(self, text_data):print("獲取到的text_data:", text_data)try:text_data_json = json.loads(text_data)print("text_data_json:",text_data_json)if not text_data_json:await self.send(text_data=json.dumps({'error': '問題不能為空',}))returntry:async for chunk in self.call_spark_ai(text_data_json):if chunk == '[DONE]':await self.send(text_data=json.dumps({'done': True,}))else:# 將 AI 的答復推送給前端await self.send(text_data=json.dumps({'message': chunk,}))await asyncio.sleep(0.1)  # 增加延遲,降低推送頻率except Exception as e:await self.send(text_data=json.dumps({'error': f'調用 AI 接口失敗: {str(e)}',}))except json.JSONDecodeError:await self.send(text_data=json.dumps({'error': '無效的 JSON 數據',}))async def call_spark_ai(self, question):print("已調用 Spark_ai函數")# 訊飛星火 AI API 的 URL 和認證信息url = "https://spark-api-open.xf-yun.com/v1/chat/completions"headers = {"Authorization": "Bearer 你的密鑰","Content-Type": "application/json",}data = {"max_tokens": 4096,"top_k": 4,"temperature": 0.5,"messages": question,"model": "4.0Ultra","stream": True,}async with httpx.AsyncClient() as client:async with client.stream("POST", url, headers=headers, json=data) as response:if response.status_code != 200:raise Exception(f"AI 接口返回錯誤: {response.status_code} {await response.text()}")# 定義正則表達式pattern = r'"content":"(.*?)"'async for line in response.aiter_lines():print(line.strip())if line.strip():try:# 使用正則表達式提取 contentmatch = re.search(pattern, line)if match:content = match.group(1)print("content:", content)if content:yield content  # 只推送 content 部分except Exception as e:print(f"處理消息時出錯: {e}")continue

消費者涉及到的內容比較多,下面我將一一解釋:

首先注意!由于連的 websocket ,需要頻繁地接收客戶端發送的消息、向客戶端發送消息并保持連接狀態。這些操作本質上是 I/O 密集型任務,涉及到網絡請求和響應。如果使用同步代碼來處理這些任務,線程會阻塞,導致性能瓶頸。而異步代碼可以高效地處理大量并發連接,避免線程阻塞。

text_data_json 獲取到前端的對話數據,并添加空數據判斷。

定義?call_spark_ai() 函數,傳入參數是對話列表,通過調用訊飛星火 API ,得到流式數據,通過正則獲取到 content 數據,通過 yield 并發式返回。

然后在消費者中異步使用該函數,將返回值返回給前端。

記得在?headers 中添加自己的密鑰。

前端

新建一個 Ai_store 用于存儲對話數據:

// stores/Ai_store.js
import { defineStore } from 'pinia';export const useAiStore = defineStore('ai', {state: () => ({messages: [],}),actions: {// 添加對話addMessage(role, content) {this.messages.push({ "role":role, "content":content });},// 清空對話列表clearMessages() {this.messages = [];},},
});

定義了一個 messages 用于存儲對話,addMessage()?添加對話對話和內容,clearMessage() 使messages 清空,即新建對話。

導入、初始化 pinia ,并定義一些變量:

import { useAiStore } from '../stores/Ai_store';// 初始化 pinia store
const Ai_store = useAiStore();// 定義消息類型
type Message = {role: string;content: string;
};
const messages = ref<Message[]>([]); // 存儲當前一輪對話(用戶提問和 AI 回答)
const question = ref(''); // 用戶輸入的問題
const aiResponse = ref<string[]>([]); // AI 的響應數據
let csrfToken: string | null = null; // CSRF Token
let socket: WebSocket | null = null; // WebSocket 連接(全局變量)
let currentAiResponse = ''; // 當前問題的實時回復內容

初始化 websocket 連接:

function initWebSocket() {if (socket) {socket.close(); // 關閉之前的連接}socket = new WebSocket(`ws://localhost:8080/ws/chat/`);// 監聽 WebSocket 打開事件socket.onopen = () => {console.log("WebSocket connection opened");};// 監聽 WebSocket 消息事件socket.onmessage = (event: MessageEvent) => {console.log("到達websocket消息事件");const data = JSON.parse(event.data);console.log("data:", data);if (data.message) {// 將消息添加到當前響應中currentAiResponse += data.message;// 更新AI回復內容if (messages.value.length > 0) {messages.value[messages.value.length - 1].content = currentAiResponse;}} else if (data.error) {console.error("Error from backend:", data.error);}};// 監聽 WebSocket 關閉事件socket.onclose = () => {console.log("WebSocket connection closed");setTimeout(initWebSocket, 5000); // 自動重連,間隔 5 秒};}

socket 路徑?ws://localhost:8080/ws/chat/ 要和后端對應起來,保證連接順利。

onmessage 接受后端返回的消息流,將 message.data 動態加入到?currentAiResponse ,currentAiResponse 動態更新消息。

發送消息:

async function sendQuestion() {// csrfToken驗證if (!csrfToken) {console.error("CSRF Token is not available");return;}if (!question.value.trim()) {alert("請輸入有效的問題!");return;}try {// 如果有上一輪對話,將其存入 Ai_storeif (messages.value.length > 0) {console.log("messages:", messages);messages.value.forEach(msg => {Ai_store.addMessage(msg.role, msg.content);});}// 清空 messages 并存儲新的用戶問題messages.value = [];messages.value.push({ role: 'user', content: question.value });// 清空 AI 的響應數據和完整字符串currentAiResponse = "";// 通過 WebSocket 發送問題const join_messages = ref<Message[]>([]);join_messages.value = [...Ai_store.messages];join_messages.value.push({ role: "user", content: question.value })console.log("join_messages:", join_messages)const message = JSON.stringify(join_messages.value);if (socket) {socket.send(message);}console.log("Sent question to WebSocket:", message);// 清空問題輸入框question.value = '';// 初始化 AI 回復占位符messages.value.push({ role: 'system', content: '' });} catch (error) {console.error("Error sending question:", error.response?.data || error.message);}}

如何 messages 中有對話數據,則添加至 pinia 中,當作歷史對話數據,以在頁面上展示之前對話數據,通過?join_messages 構造歷史對話數據和當前對話數據,即當前對話中所有對話數據,然后傳給后端,后端解析后,傳給 訊飛星火,如此形成循環。

組件生命周期:

onMounted(() => {fetchCsrfToken();initWebSocket();});onUnmounted(() => {if (socket) {socket.close();}});

組件掛載則初始化,卸載則斷開 socket 連接。

新建對話:

// 新建對話函數function newConversation() {try {// 清空數據Ai_store.clearMessages();messages.value = [];currentAiResponse = '';// 清空用戶輸入框question.value = '';console.log("新建對話:所有數據已清空");} catch (error) {console.error("Error creating new conversation:", error.message);}}

用戶點擊按鈕調用此函數,所有數據清空,重新開始對話。

計算 html :

// 計算屬性:實時拼接并格式化對話記錄const formattedResponse = computed(() => {// 合并歷史記錄和當前問題的實時回復const allMessages = [...Ai_store.messages, ...messages.value];// 格式化消息const formattedMessages = allMessages.map(msg => {return `<strong style="color: ${msg.role === 'user' ? 'blue' : 'green'};">${msg.role === 'user' ? '您:' : 'AI:'}</strong><br>${String(msg.content || '').replace(/(\\n)+/g, '<br>').replace(/\t+/g, '&emsp;')}`;});// 拼接最終的HTML字符串return formattedMessages.join('<br><br>');});

合并所有對話數據,制造格式化消息,返回給頁面,用于展示。

頁面:

<el-drawerv-model="drawerVisible"direction="ltr":modal="true":close-on-click-modal="true"custom-class="custom-drawer":with-header="false"><div class="drawer-content"><div class="header-not"><h1>AI 對話界面</h1><button @click="newConversation">新建對話</button></div><!-- 輸入框 --><div class="fixed-container"><textarea v-model="question" placeholder="請輸入問題"></textarea><button @click="sendQuestion" class="send_button">發送問題</button></div><!-- 對話記錄 --><div class="response" v-html="formattedResponse"></div></div></el-drawer>

資源獲取

本次分享結束,源碼也已放入資源:

https://download.csdn.net/download/2403_83182682/90626683

感謝您的觀看!!!

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

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

相關文章

廣東廣州一家IPO資產重組疑點重重,信息披露真實性存疑

作者&#xff1a;Eric 來源&#xff1a;IPO魔女 4月18日&#xff0c;廣州瑞立科密汽車電子股份有限公司&#xff08;簡稱“瑞立科密”&#xff09;將接受深交所主板IPO上會審核。公司保薦機構為中信證券&#xff0c;擬募集資金為15.2162億元。 瑞立科密過往資產重組疑點重重&a…

銀河麒麟(Kylin) - V10 SP1桌面操作系統ARM64編譯QT-5.15.12版本

銀河麒麟(Kylin) - V10 SP1桌面操作系統ARM64編譯QT-5.15.12版本 原因 測試Kylin-Desktop-V10-SP1-General-Release-2303-arm64系統下&#xff0c;編譯QT-5.15.12版本已做測試。 測試環境 測試板配置 型號&#xff1a;LM-D2000-NONE-1w-V01-pc_A2150 CPU&#xff1a;飛騰D20…

查看前端項目依賴樹型結構關系圖的詳細方法,涵蓋 命令行工具 和 可視化工

以下是查看前端項目依賴樹型結構關系圖的詳細方法&#xff0c;涵蓋 命令行工具 和 可視化工具&#xff1a; 一、命令行工具生成依賴樹 1. npm # 查看項目依賴樹&#xff08;文本形式&#xff09; npm ls# 查看指定包的依賴樹 npm ls <package-name># 生成JSON格式的依…

Ollama高并發測試

本文主要來測試一下ollama的高并發能力。 具體配置如下&#xff1a; 一、Ollama默認參數執行 我們打開4個窗口&#xff0c;然后分別讓DeepSeek “給我講一個笑話” &#xff0c;看下不同窗口的答題順序。 通過答題順序可以看到&#xff0c;在不進行參數設置時&#xff0c;模…

資源管理與HPA:讓Kubernetes應用自動伸縮

引言&#xff1a;從“手動擋”到“自動駕駛” 想象我們駕駛一輛汽車&#xff0c;手動調節油門和換擋不僅費力&#xff0c;還難以應對突發狀況。我們的應用服務也一樣&#xff0c;在面對突然的流量增長&#xff0c;內存使用暴漲該如何應對。HPA&#xff08;Horizontal Pod Auto…

Windows 下 MongoDB ZIP 版本安裝指南

在開發和生產環境中&#xff0c;MongoDB 是一種非常流行的 NoSQL 數據庫&#xff0c;以其靈活性和高性能而受到開發者的青睞。對于 Windows 用戶來說&#xff0c;MongoDB 提供了多種安裝方式&#xff0c;其中 ZIP 版本因其靈活性和輕量級的特點&#xff0c;成為很多開發者的首選…

【Linux網絡與網絡編程】11.數據鏈路層mac幀協議ARP協議

前面在介紹網絡層時我們提出來過一個問題&#xff1a;主機是怎么把數據交給路由器的&#xff1f;那里我們說這是由數據鏈路層來做的。 網絡上的報文在物理結構上是以mac幀的形式流動的&#xff0c;但在邏輯上是以IP流動的&#xff0c;IP的流動是需要mac幀支持的。 數據鏈路層解…

多模態思維鏈AI醫療編程:從計算可持續性到開放域推理的系統性解決方案

多模態思維鏈AI醫療編程:從計算可持續性到開放域推理的系統性解決方案 醫療AI領域的多模態思維鏈技術正在重塑臨床決策支持、醫學影像分析和醫療流程優化的范式。本指南從計算可持續性、錯誤傳播控制、倫理安全防護和通用性擴展四大維度,系統解析醫療大模型落地落地的關鍵要…

代理模式深度解析

目錄 一 靜態代理 1.1 優點 1.2 缺點 1.3 適用場景 二 JDK動態代理 1 JDK動態代理的工作原理 1.1 創建代理類 1.2 加載代理類 1.3 實現方法調用 2. Proxy.newProxyInstance() 的核心工作流程 方法簽名 工作步驟 3. 代理類的生成與加載 3.1 代理類生成的關鍵方法 …

Spring Cache與Redis集成原理

一、核心架構圖解 #mermaid-svg-aiWGQLhmWx7kOfLz {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-aiWGQLhmWx7kOfLz .error-icon{fill:#552222;}#mermaid-svg-aiWGQLhmWx7kOfLz .error-text{fill:#552222;stroke:#5…

編程技能:調試02,設置斷點與刪除斷點

專欄導航 本節文章分別屬于《Win32 學習筆記》和《MFC 學習筆記》兩個專欄&#xff0c;故劃分為兩個專欄導航。讀者可以自行選擇前往哪個專欄。 &#xff08;一&#xff09;WIn32 專欄導航 上一篇&#xff1a;編程技能&#xff1a;調試01&#xff0c;調試介紹 回到目錄 下…

flink寫doris時的優化

1.概念 doris并不擅長高頻、小量數據的導入&#xff1b; 因為doris每一次數據導入都會在be節點上生成數據文件&#xff1b;如果高頻導入小量數據&#xff0c;就會在存儲層產生大量的小文件&#xff08;必然會影響到后續的查詢效率&#xff0c;也會對系統產生更多的compaction…

ElementNotInteractableException原因及解決辦法

在自動化測試中,ElementNotInteractableException是一個常見的異常,它通常發生在嘗試與網頁上的某個元素進行交互(例如點擊、輸入等操作)時,但由于該元素當前不可交互。這可能由多種原因引起,以下是一些常見的原因及其解決方法: 元素未完全加載 如果嘗試與頁面上的元素交…

如何從 GitHub 鏡像倉庫到極狐GitLab?

最近 GitHub 封禁中國用戶的事情鬧得沸沸揚揚,雖然官方發布的報道說中國用戶被限制登錄是因為配置錯誤導致,已經撤回了更新,中國用戶已經可以正常使用。但是這就像橫在國內開發者和企業頭上的“達摩克利斯之劍”。為了避免 GitHub 不可用而帶來的影響,國內開發者和企業可以…

服務器安裝nacos

1.下載依賴 docker pull nacos/nacos-server:v2.4.3安裝 docker run -d --name nacos-server -p 8848:8848 -e MODEstandalone nacos/nacos-server:v2.4.3把nacos中的data 文件和conf 文件copy到自己服務的文件夾 docker cp nacos-server:/home/nacos/data /home/admin1/…

Matter協議暗戰:蘋果、谷歌、亞馬遜的智能家居霸權爭奪

原文地址&#xff1a;Matter協議暗戰&#xff1a;蘋果、谷歌、亞馬遜的智能家居霸權爭奪 一、Matter 協議&#xff1a;巨頭聯手打造的 “智能家居聯合國” 1.1 從 CHIP 到 Matter&#xff1a;標準統一的十年長跑 智能家居發展多年&#xff0c;卻始終被 “孤島效應” 困擾。各…

軟件設計師2009-2022歷年真題與答案解析(附pdf下載)

軟考在即&#xff0c;現在給大家分享一下軟件設計師2009-2022真題與答案解析 pdf全套&#xff0c;文末提供大家免費下載&#xff0c;大家都知道在軟考備考過程中&#xff0c;擁有一套全面且實用的考試資料對于考生來說至關重要。目錄如下&#xff1a; 歷年真題及詳解2004-2019 …

基于EasyX庫開發的球球大作戰游戲

目錄 球球大作戰 一、開發環境 二、流程圖預覽 三、代碼邏輯 1、初始化時間 2、設置開始界面大小 3、設置開始界面 4、讓玩家選擇速度 5、設置玩家小球、人機小球、食物的屬性 6、一次性把圖繪制到界面里 7、進入死循環 8、移動玩家小球 9、移動人機 10、食物刷新…

aslist和list的區別

?Arrays.asList和List的主要區別在于它們的固定長度和不可變性、與原始數組的關系、性能以及使用場景。 一、固定長度和不可變性 ?Arrays.asList?&#xff1a;通過Arrays.asList方法創建的List是一個固定長度的List&#xff0c;其長度與原始數組相同。這意味著你不能通過添…

大模型預標注和自動化標注在OCR標注場景的應用

OCR&#xff0c;即光學字符識別&#xff0c;簡單來說就是利用光學設備去捕獲圖像并識別文字&#xff0c;最終將圖片中的文字轉換為可編輯和可搜索的文本。在數字化時代&#xff0c;OCR&#xff08;光學字符識別&#xff09;技術作為處理圖像中文字信息的關鍵手段&#xff0c;其…