import { differenceBy } from 'lodash-es';
|
import moment from 'moment';
|
import { onActivated, onDeactivated, unref, type Ref } from 'vue';
|
import { RoleEnum, type ChatMessage } from '../model/types';
|
import { QueryHistoryDetail } from '/@/api/ai/chat';
|
import { sseClient } from '/@/stores/global';
|
import { Logger } from '/@/model/logger/Logger';
|
import { ElNotification } from 'element-plus';
|
|
type UseSyncMsgOptions = {
|
updateLoadIndex: (addCount: number) => void;
|
msgList: Ref<ChatMessage[]>;
|
historyGroupId: string | Ref<string>;
|
checkCanSync: (data: any) => boolean;
|
loadReplyData: (data: any) => Promise<ChatMessage[]>;
|
scrollToBottom: () => void;
|
showTip: (data: any) => void;
|
};
|
|
export const useSyncMsg = (options: UseSyncMsgOptions) => {
|
const { updateLoadIndex, msgList, historyGroupId, checkCanSync, loadReplyData, scrollToBottom, showTip } = options;
|
|
const insertSyncMsg = (replayData: any[]) => {
|
const insertResult: { index: number; item: any }[] = [];
|
for (let i = replayData.length - 1; i >= 0; i--) {
|
const insertItem = replayData[i];
|
if (insertItem.role === RoleEnum.assistant) continue;
|
for (let j = msgList.value.length - 1; j >= 0; j--) {
|
const currentItem = msgList.value[j];
|
if (currentItem.role === RoleEnum.assistant) continue;
|
if (moment(insertItem.createTime).isAfter(currentItem.createTime)) {
|
const insertAssistantItem = replayData[i + 1];
|
insertResult.push({
|
index: j + 2,
|
item: [insertItem, insertAssistantItem],
|
});
|
break;
|
}
|
}
|
}
|
insertResult.forEach((resultItem) => {
|
msgList.value.splice(resultItem.index, 0, ...resultItem.item);
|
});
|
};
|
|
|
const historyUpdate = async (data: any) => {
|
if (!checkCanSync(data)) return;
|
if (!data) return;
|
|
if (data?.type === 'chat_start') {
|
const groupId = unref(historyGroupId);
|
const startGroupId = data?.history_group_id;
|
if (groupId !== startGroupId) return;
|
showTip(data);
|
}
|
if (data?.type === 'chat_history_id') {
|
const groupId = unref(historyGroupId);
|
if (!groupId) return;
|
const recentIds = data.id_list ?? [];
|
const recentGroupHistoryIds = recentIds.filter((item) => item.group_id === groupId);
|
if (recentGroupHistoryIds.length === 0) return;
|
const userHistoryIds = msgList.value
|
.filter((item) => item.role === RoleEnum.user)
|
.map((item) => ({ history_id: item.historyId, time: item.createTime }));
|
const tmpUnSyncedHistoryIds = differenceBy(recentGroupHistoryIds, userHistoryIds, 'history_id') as any[];
|
const latestUserHistory = userHistoryIds[userHistoryIds.length - 1];
|
let unSyncedHistoryIds = tmpUnSyncedHistoryIds;
|
// 太晚的不需要更新
|
if (latestUserHistory) {
|
unSyncedHistoryIds = tmpUnSyncedHistoryIds.filter((item) => moment(item.time).isAfter(latestUserHistory.time));
|
}
|
if (!unSyncedHistoryIds || unSyncedHistoryIds.length === 0) return;
|
const res = await QueryHistoryDetail({
|
history_group_id: groupId,
|
id_list: unSyncedHistoryIds.map((item) => item.history_id).join(','),
|
});
|
if (!checkCanSync(data)) return;
|
|
const result: ChatMessage[] = res.details ?? [];
|
if (!result || result.length === 0) return;
|
const replayData = await loadReplyData(res.details);
|
if (!checkCanSync(data)) return;
|
insertSyncMsg(replayData);
|
updateLoadIndex(unSyncedHistoryIds.length);
|
scrollToBottom();
|
}
|
|
};
|
|
onActivated(() => {
|
sseClient?.subscribe(historyUpdate);
|
});
|
|
onDeactivated(() => {
|
sseClient?.unsubscribe(historyUpdate);
|
});
|
|
// onUnmounted(() => {
|
// sseClient.disconnect();
|
// });
|
};
|