Browse Source

修改在线聊天配置

ai_dev
zhouhaibin 5 months ago
parent
commit
7f2c6c53b8
  1. 396
      src/views/chat/index.vue
  2. 16
      src/views/chat/lib/ChatWindow.vue

396
src/views/chat/index.vue

@ -1,47 +1,55 @@
<template>
<ChatWindow
ref="chat"
height="850px"
:accepted-files="acceptedFiles"
show-audio="false"
:options-actions="JSON.stringify(optionsActions)"
:text-messages="JSON.stringify(textMessages)"
:current-user-id="currentUserId"
:rooms="JSON.stringify(rooms)"
:messages="roomMessages"
:menu-actions="JSON.stringify(menuActions)"
:message-selection-actions="JSON.stringify(messageSelectionActions)"
:loading-rooms="loadingRooms"
:rooms-loaded="messagesLoaded"
:room-id="roomId"
: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
<PageWrapper dense>
<ChatWindow
ref="chat"
id="window-id"
class="chat-window"
:accepted-files="acceptedFiles"
show-audio="false"
:height="divHeight"
:options-actions="JSON.stringify(optionsActions)"
:text-messages="JSON.stringify(textMessages)"
:current-user-id="currentUserId"
:rooms="JSON.stringify(rooms)"
:messages="roomMessages"
:menu-actions="JSON.stringify(menuActions)"
:message-selection-actions="JSON.stringify(messageSelectionActions)"
:loading-rooms="loadingRooms"
:rooms-loaded="messagesLoaded"
:room-id="roomId"
: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)"
@menu-action-handler="handleMenuAction($event)"
@add-room="addRoom($event)"
@fetch-messages="fetchMessages($event)"
@send-message="sendMessage($event)"
/>
<LayerVue
ref="layervueRef"
v-model:visible="visible"
:area="[width, height]"
@resizing="resizing"
@resize-end="resizeEnd"
:resize="resize"
title="监控窗口(可拖拽可缩放)"
:offset="offsetArr"
:move="moveLayer"
:move-out="moveOut"
:maxmin="[true, true]"
>
</LayerVue>
<div class="layer-demo-content-center" style="width: 100%; height: 100%" v-html="loggerInfo">
</div>
</LayerVue>
</PageWrapper>
</template>
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue';
import { PageWrapper } from '@/components/Page';
import { ref, onMounted, computed, onBeforeUnmount, watch } from 'vue';
import ChatWindow from './lib/ChatWindow.vue';
import { defHttp } from '@/utils/http/axios';
import { ContentTypeEnum } from '@/enums/httpEnum';
@ -54,10 +62,33 @@
import { mapState } from 'pinia';
import { message } from 'ant-design-vue';
import { LayerVue } from 'layer-vue';
import { v } from 'vxe-table';
const layervueRef = ref();
const offsetArr = ref<any>("rb");
const moveLayer = ref('.layer-demo-content-center');
const divHeight = ref('200px'); //
const width = ref(500);
const height = ref(800);
const height = ref(600);
const isResize = ref(false);
const moveOutList = ref([
{
label: '上',
value: false,
},
{
label: '右',
value: false,
},
{
label: '下',
value: false,
},
{
label: '左',
value: false,
},
]);
const moveOut: any = computed(() => moveOutList.value.map((v) => v.value));
const resizeList = ref([
{
label: '上',
@ -100,7 +131,7 @@ import { v } from 'vxe-table';
let visible = ref(false);
// Or if you used CDN import
// window['vue-advanced-chat'].register()
const acceptedFiles = '.docx';
const acceptedFiles = '.docx,.doc,.wps';
const optionsActions = [
{ name: 'all', title: '全功能文档分析' },
{ name: 'italic', title: '文档纠错' },
@ -108,7 +139,6 @@ import { v } from 'vxe-table';
{ name: 'bold', title: '文档公司名识别' },
{ name: 'color', title: '文档相似性检查' },
{ name: 'comment1', title: '文档结构检查' },
// { name: 'comment', title: '' },
];
//
@ -191,13 +221,52 @@ import { v } from 'vxe-table';
//
const roomActions = [{ name: 'deleteRoom', title: '删除会话' }];
//
const menuActions = [
{ name: 'inviteUser', title: '邀请用户' },
{ name: 'removeUser', title: '移除用户' },
{ name: 'deleteRoom', title: '清空会话' },
];
const menuActions = [{ name: 'openMonitorWindow', title: '打开关闭监控窗口' }];
const messageSelectionActions = [{ name: 'deleteMessages', title: 'Delete' }];
//.vben-layout-content 使
const getDivHeight = () => {
const divElement = document.querySelector('.vben-layout-content.full');
//
if (divElement) {
//
divHeight.value = String(divElement.offsetHeight) + 'px';
console.log('高度为:' + divHeight.value);
} else {
console.log('找不到指定的div元素');
}
};
//
watch(
() => layervueRef.value?.status,
(newStatus, oldStatus) => {
console.log('layervueRef.value.status changed:', newStatus);
if (newStatus && newStatus.top < 145 && newStatus.width != 0 && newStatus.height != 0) {
if (newStatus.left > 55) {
offsetArr.value = [145, newStatus.left];
layervueRef.value.resetOffset();
} else if (newStatus.left <= 55 && newStatus.top > 0) {
offsetArr.value = [145, 55];
layervueRef.value.resetOffset();
}
}
},
{ deep: true },
);
onMounted(() => {
getDivHeight(); //
//
window.addEventListener('resize', getDivHeight);
// let top = document.documentElement.clientHeight - newStatus.height;
// let left = document.documentElement.clientWidth - newStatus.width;
// console.log('top', top, 'left', left);
});
onBeforeUnmount(() => {
//
window.removeEventListener('resize', getDivHeight);
});
function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // getMonth() 0-11+1
@ -273,11 +342,11 @@ import { v } from 'vxe-table';
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`,
`${apiUrl}/productManagement/docAi/sse/checkPlaceName`,
`${apiUrl}/productManagement/docAi/sse/checkCompanyName`,
`${apiUrl}/productManagement/docAi/sse/checkDocumentError`,
`${apiUrl}/productManagement/docAi/sse/checkTitleName`,
`${apiUrl}/productManagement/docAi/sse/checkRepeatText`,
];
function getAnalysisUrl(i) {
return taskUrls[i];
@ -325,7 +394,13 @@ import { v } from 'vxe-table';
console.log('visible', visible.value);
}
}
function handleMenuAction({ action }) {
console.log('执行了' + action.name + '操作');
if (action.name === 'openMonitorWindow') {
visible.value = !visible.value;
console.log('visible', visible.value);
}
}
//
function handleSendMessage({ roomId, text, author }) {
const newMessage = {
@ -337,7 +412,7 @@ import { v } from 'vxe-table';
}
//
function fetchMessages({ room, options }) {
async function fetchMessages({ room, options }) {
messagesLoaded.value = false;
// $emit('show-demo-options', false);
if (options.reset) {
@ -371,44 +446,78 @@ import { v } from 'vxe-table';
//
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,
if (files) {
let getcontent = ref('文件上传中.....');
messagesLoaded.value = false;
if (
files[0].extension != 'docx' &&
files[0].extension != 'DOCX' &&
files[0].extension != 'doc' &&
files[0].extension != 'DOC' &&
files[0].extension != 'wps' &&
files[0].extension != 'WPS'
) {
// AI
const initialAIMessage = createAIMessage(
'文档格式错误,请上传docx、doc或WPS格式文件',
timestamp,
clientId,
ctrl,
);
roomMsgMap[roomId].push(initialAIMessage);
updateRoomMessages(roomId);
return;
}
// 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 uuid = buildUUID();
const filesstamp = Date.now();
let originalFilename = files[0].name + '_' + filesstamp + '.' + files[0].extension;
let fileName = files[0].name + '_' + filesstamp;
formData.append('originalFilename', originalFilename);
// let result = await uploadFile(formData); //
let result = false;
if (url.includes('/sse/documentEvaluate')) {
result = await xyuploadFile(formData);
} else {
result = await uploadFile(formData); //
}
if (result == true) {
const formData1 = createFormData(null, content);
formData1.append('originalFilename', fileName + '.' + 'docx');
if (url.includes('/sse/checkDocumentAll')) {
handleDocumentAnalysisBatches(
url,
formData1,
roomId,
getcontent,
timestamp,
clientId,
ctrl,
);
} else {
handleDocumentAnalysis(url, formData1, roomId, getcontent, timestamp, clientId, ctrl);
}
} else {
handleDocumentAnalysis(url, formData1, roomId, getcontent, timestamp, clientId, ctrl);
handleUploadError(roomId, timestamp, result);
}
// 3
setTimeout(() => {
getLog(ctrl);
}, 1500);
visible.value = true;
} else {
handleUploadError(roomId, timestamp);
// AI
const initialAIMessage = createAIMessage('请上传文档进行分析', timestamp);
roomMsgMap[roomId].push(initialAIMessage);
updateRoomMessages(roomId);
return;
}
//
getLog(ctrl);
visible.value = true
}
function createMessage(id, content, roomId, replyMessage, files) {
@ -432,9 +541,12 @@ import { v } from 'vxe-table';
if (files) {
message['files'] = formattedFiles(files);
message['content'] = message['content'] + '--' + files[0].name + '.' + files[0].extension;
fileInfo.value = new File([files[0].blob], files[0].name + '.' + files[0].extension, {
type: files[0].blob.type,
});
} else {
message['content'] = message['content'];
}
if (replyMessage) {
@ -483,42 +595,60 @@ import { v } from 'vxe-table';
function getUrlBasedOnContent(content, apiUrl) {
if (content.indexOf('地名检查') >= 0) {
return `${apiUrl}/productManagement/supplierInformation/sse/checkPlaceName`;
return `${apiUrl}/productManagement/docAi/sse/checkPlaceName`;
} else if (content.indexOf('文档公司名识别') >= 0) {
return `${apiUrl}/productManagement/supplierInformation/sse/checkCompanyName`;
return `${apiUrl}/productManagement/docAi/sse/checkCompanyName`;
} else if (content.indexOf('文档相似性检查') >= 0) {
return `${apiUrl}/productManagement/supplierInformation/sse/checkRepeatText`;
return `${apiUrl}/productManagement/docAi/sse/checkRepeatText`;
} else if (content.indexOf('文档纠错') >= 0) {
return `${apiUrl}/productManagement/supplierInformation/sse/checkDocumentError`;
return `${apiUrl}/productManagement/docAi/sse/checkDocumentError`;
} else if (content.indexOf('文档结构检查') >= 0) {
return `${apiUrl}/productManagement/supplierInformation/sse/checkTitleName`;
return `${apiUrl}/productManagement/docAi/sse/checkTitleName`;
} else if (content.indexOf('全功能文档分析') >= 0) {
return `${apiUrl}/sse/checkDocumentAll`;
} else if (content.indexOf('文档图文分析') >= 0) {
return `${apiUrl}/sse/checkDocumentGraphic`;
return `${apiUrl}/productManagement/docAi/sse/checkDocumentGraphic`;
}
return `${apiUrl}/productManagement/supplierInformation/sse-invoke`;
return `${apiUrl}/productManagement/docAi/sse/invoke`;
}
async function uploadFile(formData) {
try {
await defHttp.post({
url: '/productManagement/supplierInformation/upload',
let result = await defHttp.post({
url: '/productManagement/docAi/sse/upload',
data: formData,
headers: {
'Content-Type': ContentTypeEnum.FORM_DATA,
},
timeout: 10 * 60 * 1000,
});
console.log('上传成功:', result);
return true; //
} catch (error) {
console.error('请求失败:', error);
return false; //
return error; //
}
}
async function xyuploadFile(formData) {
try {
let result = await defHttp.post({
url: '/productManagement/docAi/xysse/upload',
data: formData,
headers: {
'Content-Type': ContentTypeEnum.FORM_DATA,
},
timeout: 10 * 60 * 1000,
});
console.log('上传成功:', result);
return true; //
} catch (error) {
console.error('请求失败:', error);
return error; //
}
}
function handleUploadError(roomId, timestamp) {
const errorMessage = createAIMessage('**文件上传失败,请联系管理员**', timestamp);
function handleUploadError(roomId, timestamp, errResult) {
const errorMessage = createAIMessage('**' + errResult + '**', timestamp);
roomMsgMap[roomId][roomMsgMap[roomId].length - 1] = errorMessage;
updateRoomMessages(roomId);
}
@ -540,33 +670,32 @@ import { v } from 'vxe-table';
}
return new Promise((resolve) => {
setTimeout(() => {
let analysisUrl = getAnalysisUrl(i);
fetchEventSource(analysisUrl, {
method: 'POST',
headers: {
Authorization: `Bearer ${getToken()}`,
clientId: clientId,
},
signal: ctrl.signal,
openWhenHidden: true,
body: formData,
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) {
handleError(roomId, timestamp, err, i);
ctrl.abort();
resolve('ok');
},
onclose() {
resolve('ok');
},
});
}, 1500);
let analysisUrl = getAnalysisUrl(i);
fetchEventSource(analysisUrl, {
method: 'POST',
headers: {
Authorization: `Bearer ${getToken()}`,
clientId: clientId,
},
signal: ctrl.signal,
openWhenHidden: true,
body: formData,
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) {
handleError(roomId, timestamp, err, i);
ctrl.abort();
throw err;
resolve('ok');
},
onclose() {
resolve('ok');
},
});
});
});
@ -597,7 +726,7 @@ import { v } from 'vxe-table';
});
}
function getLog(ctrl) {
fetchEventSource(`${apiUrl}/productManagement/supplierInformation/sse/getLog`, {
fetchEventSource(`${apiUrl}/productManagement/docAi/sse/getLog`, {
method: 'get',
headers: {
Authorization: `Bearer ${getToken()}`,
@ -606,12 +735,10 @@ import { v } from 'vxe-table';
signal: ctrl.signal,
openWhenHidden: true,
async onmessage(msg) {
let str = msg.data.replaceAll('<br>', '\n');
loggerInfo.value = loggerInfo.value + str + '\n';
let str = msg.data;
loggerInfo.value = loggerInfo.value + str + '<br>';
loggerInfo.value =
loggerInfo.value + '------------------------------------------------' + '\n';
loggerInfo.value =
loggerInfo.value + '------------------------------------------------' + '\n';
loggerInfo.value + '================================================' + '<br>';
},
onerror(err) {
ctrl.abort();
@ -659,10 +786,10 @@ import { v } from 'vxe-table';
function openFile({ file }) {
window.open(file.file.url, '_blank');
}
const showMonitorWindow =()=>{
const showMonitorWindow = () => {
visible.value = !visible.value;
console.log('visible', visible.value);
}
};
const resize: any = computed(() => {
return resizeList.value.map((item) => item.value);
});
@ -676,3 +803,4 @@ import { v } from 'vxe-table';
isResize.value = false;
};
</script>
<style scoped></style>

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

@ -1,5 +1,5 @@
<template>
<div class="vac-card-window" :style="[{ height }, cssVars]">
<div class="vac-card-window" :style="[{ height}, cssVars]">
<div class="vac-chat-container">
<rooms-list
v-if="!singleRoomCasted"
@ -13,7 +13,7 @@
:text-messages="t"
:show-search="showSearchCasted"
:show-add-room="showAddRoomCasted"
:show-rooms-list="showRoomsList && roomsListOpenedCasted"
:show-rooms-list="false"
:text-formatting="textFormattingCasted"
:link-options="linkOptionsCasted"
:is-mobile="isMobile"
@ -27,6 +27,8 @@
@room-action-handler="roomActionHandler"
@show-monitor-window="showMonitorWindow"
>
<!-- :show-rooms-list="showRoomsList && roomsListOpenedCasted" -->
<template v-for="el in slots" #[el.slot]="data">
<slot :name="el.slot" v-bind="data" />
</template>
@ -235,7 +237,7 @@
'search-room',
'room-action-handler',
'message-selection-action-handler',
"show-monitor-window",
'show-monitor-window',
],
data() {
@ -391,7 +393,7 @@
return this.castArray(this.optionsActions);
},
visibleMonitorWindowCasted() {
console.log(this.visibleMonitorWindow,this.castBoolean(this.visibleMonitorWindow))
console.log(this.visibleMonitorWindow, this.castBoolean(this.visibleMonitorWindow));
return this.castBoolean(this.visibleMonitorWindow);
},
},
@ -577,9 +579,9 @@
roomId: this.room.roomId,
});
},
showMonitorWindow(){
this.$emit('show-monitor-window')
}
showMonitorWindow() {
this.$emit('show-monitor-window');
},
},
};
</script>

Loading…
Cancel
Save