作者 lixiang

智能助手

import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import { useUserStore } from '@/store/modules/user';
const { createMessage } = useMessage();
... ... @@ -12,14 +13,22 @@ enum Api {
* 发送消息(流式处理)
* @param params
*/
export const sendMessage = async (params: { questionText: string }) => {
export const sendMessage = async (params: { questionText: string; code: string; codeType: number }) => {
try {
const userStore = useUserStore();
console.log("userStore",userStore.getUserInfo.username)
const token = userStore.getToken;
// 拼接参数
const query = new URLSearchParams({
questionText: params.questionText,
code: params.code,
codeType: String(params.codeType),
user: userStore.getUserInfo.username
}).toString();
const response = await fetch(
`/jeecgboot/airag/zdyRag/multiStageStream?questionText=${encodeURIComponent(params.questionText)}`,
`/jeecgboot/airag/zdyRag/sendStream?${query}`,
{
method: 'GET',
headers: {
... ... @@ -34,7 +43,6 @@ export const sendMessage = async (params: { questionText: string }) => {
throw new Error(`请求失败: ${response.status} ${response.statusText}`);
}
// 返回异步生成器函数
return (async function* () {
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
... ... @@ -71,9 +79,10 @@ export const sendMessage = async (params: { questionText: string }) => {
} catch (error) {
console.error('Error sending message:', error);
createMessage.error('发送消息失败');
throw error; // 抛出错误让调用方处理
throw error;
}
};
export const getButtonList = async () => {
const res = await defHttp.get({
url: Api.buttonList,
... ...
... ... @@ -16,13 +16,14 @@
</div>
</div>
</div>
<!-- 流式响应时显示的临时消息 -->
<div v-if="streamingMessage" class="message assistant">
<div class="message-content">
<div class="message-text" style="white-space: pre-wrap;">{{ streamingMessage }}</div>
</div>
</div>
<div v-if="loading" class="message assistant">
<div v-if="loading && !streamingMessage" class="message assistant">
<div class="message-content">
<div class="message-text">思考中...</div>
</div>
... ... @@ -38,12 +39,7 @@
<DownloadOutlined />
<span class="btn-text">下载</span>
</a-button>
<a-button
type="text"
@click="closePreview"
class="close-btn"
title="关闭预览"
>
<a-button type="text" @click="closePreview" class="close-btn" title="关闭预览">
<CloseOutlined />
</a-button>
</div>
... ... @@ -70,7 +66,8 @@
v-for="(btn, index) in buttonList"
:key="index"
class="action-button"
@click="sendButtonMessage(btn.buttonValues)"
@click="sendButtonMessage(btn)"
:disabled="buttonDisabled || loading"
>
{{ btn.buttonName }}
</a-button>
... ... @@ -100,10 +97,8 @@
<script lang="ts" name="zdy-rag-chat" setup>
import { ref, reactive, nextTick, onMounted, onBeforeUnmount } from 'vue';
import { sendMessage as apiSendMessage, getButtonList } from './ZdyRag.api';
import { useMessage } from '/@/hooks/web/useMessage';
import { CloseOutlined, DownloadOutlined } from '@ant-design/icons-vue';
import * as pdfjsLib from 'pdfjs-dist';
import * as mammoth from 'mammoth';
import { renderAsync } from 'docx-preview';
// 设置PDF.js worker路径
... ... @@ -134,7 +129,8 @@ const messages = reactive([
const inputMessage = ref('');
const loading = ref(false);
const streamingMessage = ref(''); // 流式响应消息
const buttonDisabled = ref(false);
const streamingMessage = ref('');
const messagesContainer = ref<HTMLElement>();
const previewContent = ref('');
const previewType = ref('');
... ... @@ -143,12 +139,10 @@ const currentFile = ref<any>(null);
const pdfPreview = ref<HTMLElement>();
const docxPreview = ref<HTMLElement>();
// 发送消息
const sendMessage = async () => {
const text = inputMessage.value.trim();
if (!text || loading.value) return;
// 添加用户消息
messages.push({
type: 'user',
text: text,
... ... @@ -164,7 +158,6 @@ const sendMessage = async () => {
scrollToBottom();
try {
// 创建最终消息对象
const newMessage = {
type: 'assistant',
text: '',
... ... @@ -173,15 +166,15 @@ const sendMessage = async () => {
fileName: ''
};
// 调用API获取异步生成器
const streamGenerator = await apiSendMessage({ questionText: text });
// 🚩调用API携带正确参数
const streamGenerator = await apiSendMessage({
questionText: text,
code: 'INPUT_SEND',
codeType: 0
});
// 遍历异步生成器
for await (const chunk of streamGenerator) {
if (chunk.token) {
if (!streamingMessage.value){
loading.value = false;
}
streamingMessage.value += chunk.token;
newMessage.text += chunk.token;
scrollToBottom();
... ... @@ -192,10 +185,8 @@ const sendMessage = async () => {
}
}
// 将流式消息添加到消息列表
messages.push(newMessage);
streamingMessage.value = '';
} catch (error: any) {
console.error('发送消息失败:', error);
messages.push({
... ... @@ -211,25 +202,25 @@ const sendMessage = async () => {
}
};
const sendButtonMessage = async (buttonValue: string) => {
if (loading.value) return;
const sendButtonMessage = async (btn: any) => {
if (loading.value || buttonDisabled.value) return;
// 添加用户消息
messages.push({
type: 'user',
text: buttonValue,
text: btn.buttonValues, // 🚩使用 buttonValues 作为显示内容
similarity: null,
fileBase64: null,
fileName: null
});
loading.value = true;
buttonDisabled.value = true;
streamingMessage.value = '';
closePreview();
scrollToBottom();
try {
// 创建最终消息对象
const newMessage = {
type: 'assistant',
text: '',
... ... @@ -238,15 +229,15 @@ const sendButtonMessage = async (buttonValue: string) => {
fileName: ''
};
// 调用API获取异步生成器
const streamGenerator = await apiSendMessage({ questionText: buttonValue });
// 🚩调用API携带正确参数
const streamGenerator = await apiSendMessage({
questionText: btn.buttonValues,
code: btn.code,
codeType: 1
});
// 遍历异步生成器
for await (const chunk of streamGenerator) {
if (chunk.token) {
if (!streamingMessage.value){
loading.value = false;
}
streamingMessage.value += chunk.token;
newMessage.text += chunk.token;
scrollToBottom();
... ... @@ -257,10 +248,8 @@ const sendButtonMessage = async (buttonValue: string) => {
}
}
// 将流式消息添加到消息列表
messages.push(newMessage);
streamingMessage.value = '';
} catch (error: any) {
console.error('发送按钮消息失败:', error);
messages.push({
... ... @@ -272,6 +261,7 @@ const sendButtonMessage = async (buttonValue: string) => {
});
} finally {
loading.value = false;
buttonDisabled.value = false;
scrollToBottom();
}
};
... ...