Browse Source

增加监控窗口弹窗

ai_dev
zhouhaibin 5 months ago
parent
commit
28ee8f43fd
  1. 508
      src/views/chat/index.vue
  2. 11
      src/views/chat/lib/ChatWindow.vue

508
src/views/chat/index.vue

@ -17,15 +17,31 @@
:room-message="roomMessage"
:messages-loaded="true"
:room-actions="JSON.stringify(roomActions)"
:visible-monitor-window="JSON.stringify(visible)"
@show-monitor-window="showMonitorWindow()"
@room-action-handler="handleRoomAction($event)"
@add-room="addRoom($event)"
@fetch-messages="fetchMessages($event)"
@send-message="sendMessage($event)"
/>
<LayerVue
v-model:visible="visible"
:area="[width, height]"
@resizing="resizing"
@resize-end="resizeEnd"
:resize="resize"
title="监控窗口(可拖拽可缩放)"
offset="rb"
>
<textarea ref="loggerTextarea" style="width: 100%;height: 100%;" disabled>
{{ loggerInfo }}
</textarea
>
</LayerVue>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { ref, onMounted, computed } from 'vue';
import ChatWindow from './lib/ChatWindow.vue';
import { defHttp } from '@/utils/http/axios';
import { ContentTypeEnum } from '@/enums/httpEnum';
@ -36,12 +52,52 @@
import { fetchEventSource } from '@microsoft/fetch-event-source';
import { useGlobSetting } from '@/hooks/setting';
import { mapState } from 'pinia';
import { message } from 'ant-design-vue';
import { LayerVue } from 'layer-vue';
import { v } from 'vxe-table';
const width = ref(500);
const height = ref(800);
const isResize = ref(false);
const resizeList = ref([
{
label: '上',
value: true,
},
{
label: '右上',
value: true,
},
{
label: '右',
value: true,
},
{
label: '右下',
value: true,
},
{
label: '下',
value: true,
},
{
label: '左下',
value: true,
},
{
label: '左',
value: true,
},
{
label: '左上',
value: true,
},
]);
// import { register } from './lib/index.js'
// import { register } from 'vue-advanced-chat'
// register()
let visible = ref(false);
// Or if you used CDN import
// window['vue-advanced-chat'].register()
const acceptedFiles = '.docx';
@ -52,7 +108,7 @@
{ name: 'bold', title: '文档公司名识别' },
{ name: 'color', title: '文档相似性检查' },
{ name: 'comment1', title: '文档结构检查' },
{ name: 'comment', title: '文档图文分析' },
// { name: 'comment', title: '' },
];
//
@ -76,7 +132,7 @@
ai: {
_id: '2',
username: 'ai',
avatar: icons[3],
avatar: icons[1],
status: {
// state: 'offline',
// lastChanged: '614, 20:00',
@ -155,7 +211,7 @@
{
_id: '1',
indexId: 1,
content: '欢迎使用国研大模型',
content: '欢迎使用AI辅助方案审核系统',
senderId: users['ai']._id,
username: users['ai'].username,
avatar: users['ai'].avatar,
@ -193,7 +249,7 @@
const bMsg = {
_id: '2',
indexId: 1,
content: '欢迎使用国研大模型',
content: '欢迎使用AI辅助方案审核系统',
senderId: users['ai']._id,
username: users['ai'].username,
avatar: users['ai'].avatar,
@ -211,10 +267,21 @@
let roomMsgMap = {
2: [aMsg],
1: [bMsg, aMsg],
1: [bMsg],
// 3: [cMsg],
};
const loggerInfo = ref('');
const { apiUrl, clientId } = useGlobSetting();
const taskUrls = [
`${apiUrl}/productManagement/supplierInformation/sse/checkPlaceName`,
`${apiUrl}/productManagement/supplierInformation/sse/checkCompanyName`,
`${apiUrl}/productManagement/supplierInformation/sse/checkDocumentError`,
`${apiUrl}/productManagement/supplierInformation/sse/checkTitleName`,
`${apiUrl}/productManagement/supplierInformation/sse/checkRepeatText`,
];
function getAnalysisUrl(i) {
return taskUrls[i];
}
//
function addRoom(event) {
roomIdCounter++;
@ -251,8 +318,11 @@
function handleRoomAction({ action, roomId }) {
console.log('执行了' + action + '操作,选中的会话是:' + roomId);
if (action.name === 'deleteRoom') {
const index = rooms.value.findIndex((r) => r.roomId === roomId);
rooms.value.splice(index, 1);
// const index = rooms.value.findIndex((r) => r.roomId === roomId);
// rooms.value.splice(index, 1);
message.error('无法删除最后一个会话');
visible.value = !visible.value;
console.log('visible', visible.value);
}
}
@ -285,15 +355,68 @@
//
async function sendMessage({ content, roomId, files, replyMessage }) {
loggerInfo.value = ''; //
console.log('当前发送消息到对话:' + roomId, replyMessage);
currentMsgSeq.value = currentMsgSeq.value + 1;
const u = users[currentUserId.value];
currentMsgSeq.value += 1;
const timestamp = formatDate(new Date());
const message = createMessage(
currentMsgSeq.value.toString(),
content,
roomId,
replyMessage,
files,
);
roomMsgMap[roomId].push(message);
//
updateRoomMessages(roomId);
let getcontent = ref('文件上传中.....');
messagesLoaded.value = false;
// AI
const initialAIMessage = createAIMessage(getcontent.value, timestamp);
roomMsgMap[roomId].push(initialAIMessage);
updateRoomMessages(roomId);
const ctrl = new AbortController();
const formData = createFormData(files, content);
const url = getUrlBasedOnContent(content, apiUrl);
let uuidfile = buildUUID() + '.' + files[0].extension;
formData.append('uuid', uuidfile);
if (await uploadFile(formData)) {
const formData1 = createFormData(null, content);
formData1.append('uuid', uuidfile);
if (url.includes('/sse/checkDocumentAll')) {
handleDocumentAnalysisBatches(
url,
formData1,
roomId,
getcontent,
timestamp,
clientId,
ctrl,
);
} else {
handleDocumentAnalysis(url, formData1, roomId, getcontent, timestamp, clientId, ctrl);
}
} else {
handleUploadError(roomId, timestamp);
}
//
getLog(ctrl);
visible.value = true
}
function createMessage(id, content, roomId, replyMessage, files) {
const message = {
_id: currentMsgSeq.value.toString(),
_id: id,
senderId: currentUserId.value,
username: u.username,
avatar: u.avatar,
username: users['my'].username,
avatar: users['my'].avatar,
content: content,
timestamp: formatDate(new Date()),
date: formatDate(new Date()),
@ -306,10 +429,9 @@
disableActions: false,
disableReactions: false,
};
fileInfo.value = null;
if (files) {
message['files'] = formattedFiles(files);
console.log(files);
fileInfo.value = new File([files[0].blob], files[0].name + '.' + files[0].extension, {
type: files[0].blob.type,
});
@ -320,32 +442,25 @@
_id: replyMessage._id,
content: replyMessage.content,
sender_id: replyMessage.senderId,
files: replyMessage.files || [],
};
if (replyMessage.files) {
message['replyMessage'].files = replyMessage.files;
}
return message;
}
const data = {
// file: file,
content: content,
};
roomMsgMap[roomId].push(message);
function updateRoomMessages(roomId) {
roomMessages.value = [...roomMsgMap[roomId]] as any;
}
let getcontent = ref('文件上传中.....');
messagesLoaded.value = false;
let nowDate = new Date();
const message1 = {
function createAIMessage(content, timestamp) {
return {
_id: currentMsgSeq.value.toString(),
senderId: '2',
username: users['ai'].username,
avatar: users['ai'].avatar,
content: getcontent.value,
timestamp: formatDate(nowDate),
date: formatDate(nowDate),
content: content,
timestamp: timestamp,
date: timestamp,
system: false,
saved: true,
distributed: true,
@ -355,35 +470,37 @@
disableActions: false,
disableReactions: false,
};
roomMsgMap[roomId].push(message1);
}
roomMessages.value = [...roomMsgMap[roomId]] as any;
//
//this.roomMessages = roomMsgMap[roomId]
// console.log(this.roomMessages);
messagesLoaded.value = true;
const { apiUrl, clientId } = useGlobSetting();
const ctrl = new AbortController();
const EventStreamContentType = 'text/event-stream; charset=utf-8';
function createFormData(files, content) {
let formData = new FormData();
if (files) {
formData.append('fileInfo', fileInfo.value);
}
formData.append('content', content);
//${apiUrl}/productManagement/supplierInformation/sse-invoke
let url = `${apiUrl}/productManagement/supplierInformation/sse-invoke`;
return formData;
}
function getUrlBasedOnContent(content, apiUrl) {
if (content.indexOf('地名检查') >= 0) {
url = `${apiUrl}/productManagement/supplierInformation/sse/checkPlaceName`;
return `${apiUrl}/productManagement/supplierInformation/sse/checkPlaceName`;
} else if (content.indexOf('文档公司名识别') >= 0) {
url = `${apiUrl}/productManagement/supplierInformation/sse/checkCompanyName`;
return `${apiUrl}/productManagement/supplierInformation/sse/checkCompanyName`;
} else if (content.indexOf('文档相似性检查') >= 0) {
url = `${apiUrl}/productManagement/supplierInformation/sse/checkRepeatText`;
return `${apiUrl}/productManagement/supplierInformation/sse/checkRepeatText`;
} else if (content.indexOf('文档纠错') >= 0) {
url = `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentError`;
return `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentError`;
} else if (content.indexOf('文档结构检查') >= 0) {
url = `${apiUrl}/productManagement/supplierInformation/sse/checkTitleName`;
return `${apiUrl}/productManagement/supplierInformation/sse/checkTitleName`;
} else if (content.indexOf('全功能文档分析') >= 0) {
url = `${apiUrl}/sse/checkDocumentAll`;
let uuid = buildUUID();
formData.append('uuid', uuid + '.' + files[0].extension);
return `${apiUrl}/sse/checkDocumentAll`;
} else if (content.indexOf('文档图文分析') >= 0) {
return `${apiUrl}/sse/checkDocumentGraphic`;
}
return `${apiUrl}/productManagement/supplierInformation/sse-invoke`;
}
async function uploadFile(formData) {
try {
await defHttp.post({
url: '/productManagement/supplierInformation/upload',
@ -393,248 +510,125 @@
},
timeout: 10 * 60 * 1000,
});
//
// fileRes
return true; //
} catch (error) {
//
console.error('请求失败:', error);
//
const message1 = {
_id: currentMsgSeq.value.toString(),
senderId: '2',
username: users['ai'].username,
avatar: users['ai'].avatar,
content: '**文件上传失败,请联系管理员**',
timestamp: formatDate(nowDate),
date: formatDate(nowDate),
system: false,
saved: true,
distributed: true,
seen: true,
deleted: false,
failure: false,
disableActions: false,
disableReactions: false,
};
roomMsgMap[roomId][roomMsgMap[roomId].length - 1] = message1;
roomMessages.value = [...roomMsgMap[roomId]] as any;
return;
return false; //
}
}
const fetchPromises = [];
for (let i = 0; i < 5; i++) {
if (i >= 1) {
let getcontent = ref('请稍等...');
messagesLoaded.value = false;
let nowDate = new Date();
const message1 = {
_id: currentMsgSeq.value.toString(),
senderId: '2',
username: users['ai'].username,
avatar: users['ai'].avatar,
content: getcontent.value,
timestamp: formatDate(nowDate),
date: formatDate(nowDate),
system: false,
saved: true,
distributed: true,
seen: true,
deleted: false,
failure: false,
disableActions: false,
disableReactions: false,
};
roomMsgMap[roomId].push(message1);
roomMessages.value = [...roomMsgMap[roomId]] as any;
function handleUploadError(roomId, timestamp) {
const errorMessage = createAIMessage('**文件上传失败,请联系管理员**', timestamp);
roomMsgMap[roomId][roomMsgMap[roomId].length - 1] = errorMessage;
updateRoomMessages(roomId);
}
let url;
if (i === 0) {
url = `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentAll/checkPlaceName`;
} else if (i === 1) {
url = `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentAll/checkCompanyName`;
} else if (i === 2) {
url = `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentAll/checkDocumentError`;
} else if (i === 3) {
url = `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentAll/checkTitleName`;
} else if (i === 4) {
url = `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentAll/checkRepeatText`;
function handleDocumentAnalysisBatches(
url,
formData,
roomId,
getcontent,
timestamp,
clientId,
ctrl,
) {
const fetchPromises = Array.from({ length: taskUrls.length }, (_, i) => {
if (i != 0) {
const message1 = createAIMessage(getcontent.value, timestamp);
roomMsgMap[roomId].push(message1);
updateRoomMessages(roomId);
}
// fetchEventSourcePromise
const fetchPromise = new Promise((resolve, reject) => {
return new Promise((resolve) => {
setTimeout(() => {
fetchEventSource(url, {
let analysisUrl = getAnalysisUrl(i);
fetchEventSource(analysisUrl, {
method: 'POST',
headers: {
// 'Content-Type': 'application/json;charset=utf-8',//multipart/form-data;charset=UTF-8//application/json;charset=utf-8
Authorization: `Bearer ${getToken()}`,
clientId: clientId,
},
signal: ctrl.signal,
openWhenHidden: true,
body: formData,
async onmessage(msg: { data: string; event: string }) {
// ev.data
//
// let obj = JSON.parse(msg.data);
// //
// getcontent.value +=msg.data.substring(getcontent.value.length);
getcontent.value = msg.data.replace('<br>', '\n');
console.log(getcontent.value);
const message1 = {
_id: currentMsgSeq.value.toString(),
senderId: '2',
username: users['ai'].username,
avatar: users['ai'].avatar,
content: getcontent.value,
timestamp: formatDate(nowDate),
date: formatDate(nowDate),
system: false,
saved: true,
distributed: true,
seen: true,
deleted: false,
failure: false,
disableActions: false,
disableReactions: false,
};
roomMsgMap[roomId][roomMsgMap[roomId].length - (5 - i)] = message1;
roomMessages.value = [...roomMsgMap[roomId]] as any;
// Unicode
},
//
onclose() {
//
async onmessage(msg) {
getcontent.value = msg.data.replaceAll('<br>', '\n');
const message1 = createAIMessage(getcontent.value, timestamp);
roomMsgMap[roomId][roomMsgMap[roomId].length - (taskUrls.length - i)] = message1;
updateRoomMessages(roomId);
},
onerror(err) {
console.log('onerror', err);
const message1 = {
_id: currentMsgSeq.value.toString(),
senderId: '2',
username: users['ai'].username,
avatar: users['ai'].avatar,
content: '**出现异常,请联系管理员**',
timestamp: formatDate(nowDate),
date: formatDate(nowDate),
system: false,
saved: true,
distributed: true,
seen: true,
deleted: false,
failure: false,
disableActions: false,
disableReactions: false,
};
roomMsgMap[roomId][roomMsgMap[roomId].length - (5 - i)] = message1;
roomMessages.value = [...roomMsgMap[roomId]] as any;
handleError(roomId, timestamp, err, i);
ctrl.abort();
throw err;
resolve('ok');
},
onclose() {
resolve('ok');
},
});
}, 1500);
});
});
fetchPromises.push(fetchPromise); // Promise
Promise.all(fetchPromises);
}
// 使Promise.all
Promise.all(fetchPromises)
.then(() => {
console.log('所有请求成功完成');
})
.catch((err) => {
console.error('处理过程中发生错误:', err);
});
return;
} else if (content.indexOf('文档图文分析') >= 0) {
url = `${apiUrl}/sse/checkDocumentGraphic`;
}
await fetchEventSource(url, {
function handleDocumentAnalysis(url, formData, roomId, getcontent, timestamp, clientId, ctrl) {
fetchEventSource(url, {
method: 'POST',
headers: {
// 'Content-Type': 'application/json;charset=utf-8',//multipart/form-data;charset=UTF-8//application/json;charset=utf-8
Authorization: `Bearer ${getToken()}`,
clientId: clientId,
},
signal: ctrl.signal,
openWhenHidden: true,
body: formData,
async onmessage(msg: { data: string; event: string }) {
// ev.data
//
// let obj = JSON.parse(msg.data);
// //
// getcontent.value +=msg.data.substring(getcontent.value.length);
async onmessage(msg) {
getcontent.value = msg.data.replaceAll('<br>', '\n');
console.log(getcontent.value);
const message1 = {
_id: currentMsgSeq.value.toString(),
senderId: '2',
username: users['ai'].username,
avatar: users['ai'].avatar,
content: getcontent.value,
timestamp: formatDate(nowDate),
date: formatDate(nowDate),
system: false,
saved: true,
distributed: true,
seen: true,
deleted: false,
failure: false,
disableActions: false,
disableReactions: false,
};
const message1 = createAIMessage(getcontent.value, timestamp);
roomMsgMap[roomId][roomMsgMap[roomId].length - 1] = message1;
roomMessages.value = [...roomMsgMap[roomId]] as any;
// Unicode
updateRoomMessages(roomId);
},
//
onclose() {
//
onerror(err) {
handleError(roomId, timestamp, err);
ctrl.abort();
throw err;
},
});
}
function getLog(ctrl) {
fetchEventSource(`${apiUrl}/productManagement/supplierInformation/sse/getLog`, {
method: 'get',
headers: {
Authorization: `Bearer ${getToken()}`,
clientId: clientId,
},
signal: ctrl.signal,
openWhenHidden: true,
async onmessage(msg) {
let str = msg.data.replaceAll('<br>', '\n');
loggerInfo.value = loggerInfo.value + str + '\n';
loggerInfo.value =
loggerInfo.value + '------------------------------------------------' + '\n';
loggerInfo.value =
loggerInfo.value + '------------------------------------------------' + '\n';
},
onerror(err) {
console.log('onerror', err);
const message1 = {
_id: currentMsgSeq.value.toString(),
senderId: '2',
username: users['ai'].username,
avatar: users['ai'].avatar,
content: '**出现异常,请联系管理员**',
timestamp: formatDate(nowDate),
date: formatDate(nowDate),
system: false,
saved: true,
distributed: true,
seen: true,
deleted: false,
failure: false,
disableActions: false,
disableReactions: false,
};
roomMsgMap[roomId][roomMsgMap[roomId].length - 1] = message1;
roomMessages.value = [...roomMsgMap[roomId]] as any;
ctrl.abort();
throw err;
},
});
}
// let getcontent = await defHttp.get({
// url: '/productManagement/supplierInformation/sse-invoke',
// data,
// // headers: {
// // 'Content-Type': ContentTypeEnum.FORM_DATA,
// // },
// timeout: 4 * 60 * 1000,
// });
function handleError(roomId, timestamp, err, index = null) {
console.log('onerror', err);
const errorMessage = createAIMessage('**出现异常,请联系管理员**', timestamp);
if (index !== null) {
roomMsgMap[roomId][roomMsgMap[roomId].length - (taskUrls.length - index)] = errorMessage;
} else {
roomMsgMap[roomId][roomMsgMap[roomId].length - 1] = errorMessage;
}
updateRoomMessages(roomId);
}
function formattedFiles(files) {
@ -665,4 +659,20 @@
function openFile({ file }) {
window.open(file.file.url, '_blank');
}
const showMonitorWindow =()=>{
visible.value = !visible.value;
console.log('visible', visible.value);
}
const resize: any = computed(() => {
return resizeList.value.map((item) => item.value);
});
const resizing = (el: HTMLElement | null, id: string | undefined, w: number, h: number) => {
width.value = w;
height.value = h;
isResize.value = true;
};
const resizeEnd = (el: HTMLElement | null, id: string | undefined, w: number, h: number) => {
isResize.value = false;
};
</script>

11
src/views/chat/lib/ChatWindow.vue

@ -18,12 +18,14 @@
:link-options="linkOptionsCasted"
:is-mobile="isMobile"
:scroll-distance="scrollDistance"
:visible-monitor-window="visibleMonitorWindowCasted"
@fetch-room="fetchRoom"
@fetch-more-rooms="fetchMoreRooms"
@loading-more-rooms="loadingMoreRooms = $event"
@add-room="addRoom"
@search-room="searchRoom"
@room-action-handler="roomActionHandler"
@show-monitor-window="showMonitorWindow"
>
<template v-for="el in slots" #[el.slot]="data">
<slot :name="el.slot" v-bind="data" />
@ -210,6 +212,7 @@
default: () => ({ minUsers: 3, currentUser: false }),
},
emojiDataSource: { type: String, default: undefined },
visibleMonitorWindow: { type: [Boolean, String], default: () => ({}) },
},
emits: [
@ -232,6 +235,7 @@
'search-room',
'room-action-handler',
'message-selection-action-handler',
"show-monitor-window",
],
data() {
@ -386,6 +390,10 @@
optionsActionsCasted() {
return this.castArray(this.optionsActions);
},
visibleMonitorWindowCasted() {
console.log(this.visibleMonitorWindow,this.castBoolean(this.visibleMonitorWindow))
return this.castBoolean(this.visibleMonitorWindow);
},
},
watch: {
@ -569,6 +577,9 @@
roomId: this.room.roomId,
});
},
showMonitorWindow(){
this.$emit('show-monitor-window')
}
},
};
</script>

Loading…
Cancel
Save