【Spring AI】基于SpringAI+Vue3+ElementPlus的QA系統實現(前端)

整理不易,請不要吝嗇你的贊和收藏。

1. 前言

這篇文章是 Spring AI Q&A 系統的前端實現。這篇文章將介紹如何快速搭建一個基于 vue3 + ElementPlus 的前端項目,vue3 項目的目錄結構介紹,如何在前端實現流式響應,如何高亮顯示代碼等。

效果展示:

2. 前提條件

  • 后端實現:

    【Spring AI】基于SpringAI+Vue3+ElementPlus的Q&A系統實現(后端)-CSDN博客文章瀏覽閱讀762次,點贊26次,收藏24次。這篇文章將介紹如何基于 RAG 技術,使用 SpringAI + Vue3 + ElementPlus 實現一個 Q&A 系統。本文使用 deepseek 的 DeepSeek-V3 作為聊天模型,使用阿里百煉的 text-embedding-v3 作為向量模型,使用 redis 作為向量庫。(PS:近期阿里百煉也上架了 DeepSeek-V3 和 DeepSeek-R1 模型供開發者調用,如果覺得 DeepSeek 官方 AP I比較慢的話,可以去試試)。 https://blog.csdn.net/u013176571/article/details/145368559
  • 已安裝 18.3 或更高版本的?Node.js ,未安裝進入 官網下載 ,LTS 為長期支持版,Current 為最新功能版。

3. 快速搭建 Elemenet-Plus 項目

我這里直接使用官網的快速搭建模板 element-plus-vite-starter ,其它方式參考 Element-Plus 官網 。

3.1 項目下載

# 下載模板
git clone https://github.com/element-plus/element-plus-vite-starter.git
# 進入項目,安裝依賴包
npm install

3.2 項目結構介紹

VS Code 中引入項目,項目結構如下:

項目結構介紹:

element-plus-vite-starter/
├── node_modules/            # 存放所有安裝的依賴包
├── public/                  # 靜態資源文件夾
│   └── favicon.svg          # 默認的站點圖標
├── src/                     # 源代碼文件夾
│   ├── assets/              # 靜態資源(如圖片、樣式等)
│   ├── components/          # Vue 組件文件夾
│   ├──── layouts/           
│   ├────── BaseHeader.vue   # 頂部導航欄布局
│   ├────── BaseSide.vue     # 側邊導航欄布局
│   ├── composables/         # Vue 3 Composition API 的邏輯復用文件夾,存放 useXXX 命名的函數
│   ├── pages/               # 頁面視圖文件夾
│   ├── styles/              # 樣式文件夾,存放全局樣式 css 類
│   ├──── element/           
│   ├────── index.scss       # 全局顏色主題配置文件           
│   ├── App.vue              # 根組件
│   ├── main.js              # 項目入口文件
│   ├── components.d.ts      # 組件的類型聲明文件
│   ├── env.d.ts             # 環境變量的類型聲明文件
│   ├── typed-router.d.ts    # 路由的類型聲明文件
│   └── types.ts             # 全局類型定義文件,用于定義 TypeScript 類型
├── .gitignore               
├── eslint.config.ts         # ESLint 配置文件,用于代碼質量檢查
├── index.html               # 項目入口 HTML 文件,Vite 會以此文件為模板進行開發和構建
├── babel.config.js          # Babel 配置文件(僅在 Vue CLI 項目中)
├── package-lock.json        # npm 生成的鎖定文件,確保依賴版本一致
├── package.json             # 項目依賴和配置信息
├── pnpm-lock.yaml           # pnpm 生成的鎖定文件,確保依賴版本一致
├── README.md                # 項目說明文檔
├── tsconfig.json            # TypeScript 配置文件,定義 TypeScript 編譯選項
├── uno.config.ts            # UnoCSS 配置文件,UnoCSS 是一個用于生成原子 CSS 的工具
└── vite.config.ts           # Vite 配置文件(僅在 Vite 項目中)

3.3 啟動項目

執行以下命令啟動:

# 啟動項目
npm run dev

瀏覽器訪問:http://localhost:5173/

4. 頁面開發

這篇文章不會提供所有前端代碼,我會在主要的卡點提供相應的代碼節選。

4.1 .vue 文件介紹

在 Vue3 中,我們通過創建一個 .vue 格式文件來創建頁面,一個 .vue 文件由以下幾個部分組成:

  • template:組件的模板部分,用于定義組件的 HTML 結構。Vue 會將模板編譯為渲染函數,用于生成最終的 DOM。

  • script:組件的邏輯部分,用于定義組件的數據、方法、生命周期鉤子等。

  • style:組件的樣式部分,用于定義組件的 CSS 樣式,支持 CSS、SCSS、Sass、Less 等。

樣例:

<template><div class = "m-container" ><h1 class = "m-title" >{{ title }}</h1><button @click = "handleClick" >@click 用來綁定點擊事件</button></div>
</template>// lang="ts" 表示標簽中的代碼是用 TypeScript 編寫的
<script lang="ts" setup>
import { onMounted, reactive, toRefs } from "vue";// 定義變量
const state = reactive({title: "頁面1",
});
// 用于將響應式對象中的屬性轉換為響應式引用(ref)
const { title } = toRefs(state)/*** 頁面加載事件*/
onMounted(() => {
});/*** 綁定事件*/
const handleClick = () => {// 變量賦值title.value = "頁面2"
}
</script>// lang="less" 表示使用 less 語法,scoped 用來限制作用域,只對當前組件模板生效
<style lang="less" scoped>
.m-container{.m-title{            }
}
</style>

4.2 網絡請求工具類

在 src 目錄下創建一個 utils 文件夾,然后創建一個 api.ts 文件,用于發起網絡請求。

4.2.1 代碼

import axios from 'axios';
import { ElMessage } from 'element-plus';// 創建一個 axios 實例
const baseURL = 'http://127.0.0.1:8082/your_service_name';
const apiClient = axios.create({baseURL: baseURL,timeout: 200000, // 請求超時時間headers: {'Content-Type': 'application/json',},
});const err = (error) => {console.log('error', error)if (axios.isCancel(error)) {return}if (!error.response) {ElMessage.error({message: '請求超時請檢查網絡鏈接!',offset: 80,})return Promise.reject(error)}const data = error.response.dataif (!data || data.code !== 200) {ElMessage.error(data.message || "發生未知錯誤,請稍后再試!")}return Promise.reject(error)
}// 請求攔截器
apiClient.interceptors.request.use((config) => {// 在發送請求之前做些什么,例如添加 tokenconst token = localStorage.getItem('token'); if (token) {config.headers['Authorization'] = `Bearer ${token}`;}return config;},err
);// 響應攔截器
apiClient.interceptors.response.use((response) => {// 對響應數據做點什么return response.data;},err
);// 定義 API 請求方法
const api = {getBaseUrl() {return baseURL;},get(url, params) {return apiClient.get(url, { params });},post(url, params, config) {return apiClient.post(url, params, config);},
};
export default api;

4.2.2 如何引用?

在需要引用的頁面的 script 標簽中 或 .ts 文件下鍵入:

import api from '@/utils/api';

4.2.3 如何調用?

const param = {};
const config = {headers: {'Content-Type': 'multipart/form-data',},
};
api.post("/ai/chat/fileUploadWithRag",param).then((response) => {console.log("Response received:", response);}).catch((error) => {// 處理錯誤console.error("請求失敗:", error);});

4.3 如何接收 SSE 響應式消息

SSE (Server-Sent Events)是一種允許服務器向客戶端推送數據的技術,屬于 HTML5 的一部分。它支持服務器向客戶端的單向通信,客戶端通過一次長連接持續接收服務器推送的數據。響應式編程(Reactive Programming)非常適合實現 SSE,因為它允許以非阻塞的方式持續推送數據,不會阻塞服務器資源。在 SpringBoot 中可以使用 Spring WebFlux 框架來實現 SSE。在 Web 端實現 SSE 通常使用 EventSource?對象。

4.3.1 代碼

同樣在 utils 目錄下,創建一個 sse.ts 的工具類。

class SSE {private eventSource: EventSource | null = null;/*** 連接 SSE* @param url* @param onMessage * @param onError */public connect(url: string, onMessage: (event: MessageEvent) => void, onError?: (event: Event) => void): void {this.eventSource = new EventSource(url);// 監聽消息事件this.eventSource.onmessage = onMessage;// 監聽錯誤事件if (onError) {this.eventSource.onerror = onError;}}/*** 關閉 SSE 連接*/public close(): void {if (this.eventSource) {this.eventSource.close();this.eventSource = null;}}}export default SSE;

4.3.2 如何引用?

import SSE from "@/utils/sse";

4.3.3 如何調用

需要注意的是,SSE 僅支持 GET 調用。

const state = reactive({sse: new SSE(),
});
const { sse } = toRefs(state);// 接收消息的回調函數
const handleMessage = (event: MessageEvent) => {eventMessage = eventMessage.concat(event.data);
};
// 錯誤處理的回調函數
const handleError = (event: Event) => {stopGenerate();console.log('SSE 連接錯誤:', event);
};
const url = "接口地址?param1=param1&param2=param2"
sse.value.connect(url, handleMessage, handleError);

4.4 對話組件

template 中主要代碼節選,通過 message.sender 的值加載用戶和AI消息的樣式。

<el-scrollbar ref="scrollbar" class="message-list" always @scroll="handleScroll"><div v-for="message in messages" :key="message.id" class="message-wrapper" :class="{'user-message': message.sender === 'user','bot-message': message.sender === 'bot',}"><div class="message-bubble"><div class="message-content" v-html="message.content"></div></div></div>
</el-scrollbar>

script 中主要代碼節選:

// 定義一個 Message 接口
interface Message {id: number;content: string;sender: "user" | "bot";timestamp: number;
}// 定義變量
const state = reactive({messages: [] as Message[],
});
const { messages } = toRefs(state);

4.5 如何加載 Markdown 內容

由于大模型返回的流一般為 Markdown 格式,我們使用第三方庫 markdown-it 來加載內容。

4.5.1 安裝 markdown-it

由于我需要支持代碼高亮、數學公式、流程圖等,所以我安裝了額外的插件來擴展 MarkdownIt 的功能。

npm install markdown-it highlight.js katex mermaid markdown-it-sub markdown-it-sup markdown-it-emoji markdown-it-task-lists markdown-it-footnote markdown-it-deflist markdown-it-abbr markdown-it-ins markdown-it-mark

4.5.2 如何使用

template 中代碼節選:

<template><div class="message-content" v-html="message.content"></div>
</template>

script 中代碼節選:

// 引入 markdown-it
import MarkdownIt from "markdown-it";
// 定義MarkdownIt對象
const md = new MarkdownIt();// SSE 接收消息的回調函數
const handleMessage = (event: MessageEvent) => {eventMessage = eventMessage.concat(event.data);botMessage.content = computed(() => {return md.value.render(eventMessage);});// 設置nextTick(() => {scrollToBottom();});
};

4.6 其它

4.6.1 上傳組件

使用 ElementPlus 的 upload 組件。

4.6.2 使用 Alt + Enter 鍵換行

Input 默認的換行快捷鍵為 Shift + Enter,不符合我們平時的使用習慣。

const handleKeyDown = (event: KeyboardEvent) => {if (event.key === "Enter") {// 按下 Alt + Enter 鍵時,插入換行符if (event.altKey) {const cursorPosition = event.target.selectionStart;const textBeforeCursor = inputMessage.value.slice(0, cursorPosition);const textAfterCursor = inputMessage.value.slice(cursorPosition);inputMessage.value = textBeforeCursor + '\n' + textAfterCursor;event.target.selectionStart = cursorPosition + 1;event.target.selectionEnd = cursorPosition + 1;return;}event.preventDefault();sendMessage();}
};

4.6.3 消息自動滾動到最下方

代碼節選:

 // 定義變量
const state = reactive({autoScroll: true,scrollbar: {} as any,
});
const { autoScroll, scrollbar } = toRefs(state);/*** 消息滾動事件監聽*/
const handleScroll = ({ scrollTop }: { scrollTop: number }) => {const scrollHeight = scrollbar.value.wrapRef?.scrollHeight || 0;const clientHeight = scrollbar.value.wrapRef?.clientHeight || 0;autoScroll.value = scrollTop + clientHeight >= scrollHeight - 10;
};/*** 滾動到最下方*/
const scrollToBottom = () => {if (autoScroll.value) {nextTick(() => {scrollbar.value?.setScrollTop(scrollbar.value.wrapRef?.scrollHeight);});}
};

5. 參考文檔

  • Vue3 文檔
  • Element Plus 文檔
  • markdown-it 文檔

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

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

相關文章

企業級API集成方案:基于阿里云函數計算調用DeepSeek全解析

解決方案鏈接&#xff1a;https://www.aliyun.com/solution/tech-solution/deepseek-r1-for-platforms?utm_contentg_1000401616 何為DeepSeek R1 DeepSeek R1模型有諸多技術優勢。高效架構設計使其能更高效提取特征&#xff0c;減少冗余計算&#xff0c;提升數據處理速度、…

K8s學習總結

文章目錄 介紹Kubernetes 核心組件k8s安裝環境安裝組件 常用命令測試1. 創建一個測試應用程序2. 檢查 Pod 是否運行 3. 暴露應用讓外部訪問4. 查看服務的暴露端口5. 訪問 nginx 服務6. 驗證節點調度 如有錯誤&#xff0c;敬請指針&#xff0c;謝謝! 介紹 Kubernetes&#xff0…

前端為什么要使用new Promise包裹一個函數

在前端開發中&#xff0c;使用 new Promise 包裹一個函數主要是為了將原本不支持 Promise 規范的操作轉化為支持 Promise 規范的操作&#xff0c;從而可以更好地處理異步操作&#xff0c;提升代碼的可讀性和可維護性。下面詳細介紹這么做的常見原因和應用場景&#xff1a; 1. …

說下JVM中一次完整的GC流程?

大家好&#xff0c;我是鋒哥。今天分享關于【說下JVM中一次完整的GC流程?】面試題。希望對大家有幫助&#xff1b; 說下JVM中一次完整的GC流程? 1000道 互聯網大廠Java工程師 精選面試題-Java資源分享網 JVM中的一次完整的垃圾回收&#xff08;GC&#xff09;流程可以概括為…

dnslog+sqlmap外帶數據

目錄 爆庫 爆表 爆列 爆數據 sqlmapDNSlog 外帶參數 –dns-domain參數注入 –dns-domain參數為dnslog平臺的域名&#xff08;我們也可以使用本地&#xff09; 爆庫 python sqlmap.py -u "http://127.0.0.1/sqli/less-8/index.php/?id1" -techniqueB -dns-dom…

提升顧客轉化率:融合2+1鏈動模式AI智能名片與S2B2C商城小程序的創新策略

摘要&#xff1a;在數字化轉型的背景下&#xff0c;零售商面臨著提升顧客轉化率的巨大挑戰。本文旨在探討如何通過整合顧客行為數據、21鏈動模式、AI智能名片及S2B2C商城小程序等新興技術與商業模式&#xff0c;來精準定位顧客需求&#xff0c;優化營銷策略&#xff0c;從而提高…

以若依移動端版為基礎,實現uniapp的flowable流程管理

1.前言 此代碼是若依移動端版為基礎&#xff0c;實現flowable流程管理&#xff0c;支持H5、APP和微信小程序三端。其中&#xff0c;APP是在安卓在雷電模擬器環境下完成的&#xff0c;其他環境未測試&#xff0c;此文章中所提及的APP均指上述環境。移動端是需要配合若依前后端分…

《全球網絡安全政策法律發展研究報告 (2024) 》

全球視野&#xff0c;深度剖析 報告以全球視野為出發點&#xff0c;深度剖析了2024年各國在網絡安全政策法律方面的最新進展。從局部區域沖突延宕到關鍵信息基礎設施(關基)安全保護規則的持續細化&#xff0c;從數據安全政策立法的蓬勃發展到個人信息保護立法的不斷完善&#…

細說STM32F407單片機RTC的備份寄存器原理及使用方法

目錄 一、備份寄存器的功能 二、示例功能 三、項目設置 1、晶振、DEBUG、CodeGenerator、USART6 2、RTC 3、NVIC 4、GPIO 及KEYLED 四、軟件設計 1、main.h 2、main.c 3、rtc.c 4、keyled.c、keyled.h 五、運行調試 本實例旨在介紹備份寄存器的作用。本實例繼續使…

建筑行業安全技能競賽流程方案

一、比賽時間&#xff1a; 6月23日8&#xff1a;30分準時到場&#xff1b;9&#xff1a;00&#xff0d;10&#xff1a;00理論考試&#xff1b;10&#xff1a;10-12:00現場隱患答疑&#xff1b;12:00-13&#xff1a;30午餐&#xff1b;下午13&#xff1a;30-15&#xff1a;30現場…

解鎖機器學習核心算法 | 線性回歸:機器學習的基石

在機器學習的眾多算法中&#xff0c;線性回歸宛如一塊基石&#xff0c;看似質樸無華&#xff0c;卻穩穩支撐起諸多復雜模型的架構。它是我們初涉機器學習領域時便會邂逅的算法之一&#xff0c;其原理與應用廣泛滲透于各個領域。無論是預測房價走勢、剖析股票市場波動&#xff0…

JAVA生產環境(IDEA)排查死鎖

使用 IntelliJ IDEA 排查死鎖 IntelliJ IDEA 提供了強大的工具來幫助開發者排查死鎖問題。以下是具體的排查步驟&#xff1a; 1. 編寫并運行代碼 首先&#xff0c;我們編寫一個可能導致死鎖的示例代碼&#xff1a; public class DeadlockExample {private static final Obj…

解決DeepSeek服務器繁忙問題

目錄 解決DeepSeek服務器繁忙問題 一、用戶端即時優化方案 二、高級技術方案 三、替代方案與平替工具&#xff08;最推薦簡單好用&#xff09; 四、系統層建議與官方動態 用加速器本地部署DeepSeek 使用加速器本地部署DeepSeek的完整指南 一、核心原理與工具選擇 二、…

機器學習 - 大數定律、可能近似正確學習理論

一、大數定律&#xff1a; 大數定律是概率論中的一個基本定理&#xff0c;其核心思想是&#xff1a;當獨立重復的隨機試驗次數足夠大時&#xff0c;樣本的平均值會趨近于該隨機變量的期望值。下面從直觀和數學兩個角度來說明這一概念&#xff1a; 1. 直觀理解 重復試驗的穩定…

【觸想智能】工業顯示器和普通顯示器的區別以及工業顯示器的主要應用領域分析

在現代工業中&#xff0c;工業顯示器被廣泛應用于各種場景&#xff0c;從監控系統到生產控制&#xff0c;它們在實時數據顯示、操作界面和信息傳遞方面發揮著重要作用。與普通顯示器相比&#xff0c;工業顯示器在耐用性、可靠性和適應特殊環境的能力上有著顯著的差異。 觸想工業…

PyCharm2024使用Python3.12在Debug時,F8步進時如同死機狀態

在使用時PyCharm2024&#xff0b;Python3.12&#xff0c;在程序進行調試時&#xff0c;按F8步進時如同死機狀態。 1、相同的程序在PyCharm2023&#xff0b;Python3.9時是沒有問題的&#xff0c;因此決定重裝PyCharm2023&#xff0b;Python3.9&#xff0c;進行調試——調試OK。 …

LLaMA-Factory DeepSeek-R1 模型 微調基礎教程

LLaMA-Factory 模型 微調基礎教程 LLaMA-FactoryLLaMA-Factory 下載 AnacondaAnaconda 環境創建軟硬件依賴 詳情LLaMA-Factory 依賴安裝CUDA 安裝量化 BitsAndBytes 安裝可視化微調啟動 數據集準備所需工具下載使用教程所需數據合并數據集預處理 DeepSeek-R1 可視化微調數據集處…

STM32 如何使用DMA和獲取ADC

目錄 背景 ?搖桿的原理 程序 端口配置 ADC 配置 DMA配置 背景 DMA是一種計算機技術&#xff0c;允許某些硬件子系統直接訪問系統內存&#xff0c;而不需要中央處理器&#xff08;CPU&#xff09;的介入&#xff0c;從而減輕CPU的負擔。我們可以通過DMA來從外設&#xf…

【ISO 14229-1:2023 UDS診斷全量測試用例清單系列:第十六節】

ISO 14229-1:2023 UDS診斷服務測試用例全解析&#xff08;LinkControl_0x87服務&#xff09; 作者&#xff1a;車端域控測試工程師 更新日期&#xff1a;2025年02月14日 關鍵詞&#xff1a;UDS協議、0x87服務、鏈路控制、ISO 14229-1:2023、ECU測試 一、服務功能概述 0x87服務…

DeepSeek與醫院電子病歷的深度融合路徑:本地化和上云差異化分析

一、引言 1.1 研究背景與意義 在醫療信息化快速發展的當下,電子病歷系統已成為醫院信息管理的核心構成。電子病歷(EMR)系統,是指醫務人員在醫療活動過程中,使用醫療機構信息系統生成的文字、符號、圖標、圖形、數據、影像等數字化信息,并能實現存儲、管理、傳輸和重現的…