| | |
| | | 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 { LOAD_CHAT_LIMIT } from '../constants'; |
| | | import { differenceBy } from 'lodash-es'; |
| | | |
| | | type UseSyncMsgOptions = { |
| | | updateLoadIndex: (addCount: number) => void; |
| | | msgList: Ref<ChatMessage[]>; |
| | | historyGroupId: string | Ref<string>; |
| | | checkCanSync: (data: any) => boolean; |
| | | loadReplyData: (data: any) => Promise<ChatMessage[]>; |
| | | scrollToBottom: () => void; |
| | | }; |
| | | |
| | | export const useSyncMsg = (options: UseSyncMsgOptions) => { |
| | | const { updateLoadIndex, msgList, historyGroupId } = options; |
| | | const { updateLoadIndex, msgList, historyGroupId, checkCanSync, loadReplyData, scrollToBottom } = options; |
| | | |
| | | // const loadRangeData = async (lastEnd = nextUserMsgEndIndex) => { |
| | | // const res = await QueryHistoryDetail({ |
| | | // history_group_id: unref(historyGroupId), |
| | | // last_end: lastEnd, |
| | | // last_count: LOAD_CHAT_LIMIT, |
| | | // }); |
| | | // const result: ChatMessage[] = res.details ?? []; |
| | | // if (result.length) { |
| | | // nextUserMsgEndIndex += result.length; |
| | | // const rangeMsgList = await loadReplyData(res.details); |
| | | // messageList.value.unshift(...rangeMsgList); |
| | | // } else { |
| | | // isNoMore = true; |
| | | // } |
| | | |
| | | // return result; |
| | | // }; |
| | | 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; |
| | | const groupId = unref(historyGroupId); |
| | | if (!groupId) return; |
| | | |
| | | 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) => ({ id: item.historyId, time: item.createTime })); |
| | | const unSyncedHistoryIds = differenceBy(recentIds, userHistoryIds, 'id'); |
| | | console.log('unSyncedHistoryIds', unSyncedHistoryIds); |
| | | } |
| | | .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 res = await QueryHistoryDetail({ |
| | | history_group_id: groupId, |
| | | last_end: 0, |
| | | last_count: LOAD_CHAT_LIMIT, |
| | | }); |
| | | console.log('historyUpdate', data, groupId); |
| | | 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(() => { |
| | | console.log('onActivated'); |
| | | sseClient.subscribe(historyUpdate); |
| | | sseClient?.subscribe(historyUpdate); |
| | | }); |
| | | |
| | | onDeactivated(() => { |
| | | console.log('onDeactivated'); |
| | | sseClient.unsubscribe(historyUpdate); |
| | | sseClient?.unsubscribe(historyUpdate); |
| | | }); |
| | | |
| | | // onUnmounted(() => { |