|
...
|
...
|
@@ -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();
|
|
|
|
}
|
|
|
|
};
|
...
|
...
|
|