import { MESSAGE_TYPE } from "./chat_constant"; import { getQueryVariable, generateRequestId, arrayUnique } from "./util"; import { v4 as uuidv4 } from "uuid"; import GLOBAL from "./global"; import Observer from "./observer"; const $e = Observer; // const $s = this.$s; let cache = null; // 缓存 let timeoutTasks = {}; // 超时任务管理 const msgSendTimeout = 2 * 60 * 1000; // 发送消息超时ms,此处超时默认为2min class ClientData { constructor(option) { cache = { session_id: "", // 会话ID configInfo: null, // 配置信息 chatsContent: [], // 会话聊天内容 systemEvents: [], // 系统事件栈 transferInfo: { transferStatus: false, transferAvatar: "", }, // 当前转人工状态 }; this.$s = null } init() { // 获取基础配置 this.queryConfigInfo(); } setAttr(options) { this.$s =options.socketObj } // 获取基础配置 async queryConfigInfo() { try { const seatBizId = ''// getQueryVariable("seat_biz_id"); console.log("seatBizId", seatBizId); const sessionInfo = await this.createSession(); console.log("createsession, res", sessionInfo); if (sessionInfo.code === 0) { cache.seat_biz_id = seatBizId; cache.session_id = sessionInfo.data.session_id; } else { uni.showModal({ title: "获取会话ID失败,请重试", icon: "none", }); } // 接着获取机器人基础信息 const botInfo = { code: 0, data: { name: "测试机器人", avatar: "https://qbot-1251316161.cos.ap-nanjing.myqcloud.com/avatar.png", is_available: true, bot_biz_id: "1664519736704069632", }, }; if (botInfo.data) { cache.configInfo = botInfo.data; cache.configInfo.session_id = sessionInfo.data.session_id; $e.$emit("client_configChange", cache.configInfo); } else { uni.showModal({ title: "获取机器人信息失败", icon: "none", }); } } catch (e) { console.log("获取机器人信息失败", e); uni.showModal({ title: "获取会话信息失败,请刷新页面重试", icon: "none", }); } } async createSession() { const session_id = uuidv4(); return { code: 0, data: { session_id: session_id } }; } // 消息上行事件(用户端) triggerSendMsg =async (msg, type='text', status= true) => { console.log("[triggerSendMsg]", msg, wx); if (!cache.configInfo || !cache.configInfo.session_id) { await this.queryConfigInfo(); } const requestId = generateRequestId(); const params = { request_id: requestId, session_id: cache.configInfo ? cache.configInfo.session_id : 0, is_msg_status: status }; if (type == "text") { params.content = msg; } else if (type == "img") { params.content = `![](${msg})`; params.realContent = msg; } this.$s.emit("send", params, type); } // 监听token用量和详情事件 listenTokenStat() { this.$s.on("token_stat", (data) => { $e.$emit("token_state_change", data); if (data.session_id !== cache.session_id) return; // 若新消息不属于当前机器人时,则不做处理 let loadingMsg = cache.chatsContent.find((el) => el.loading_message); let loadingText = "思考中"; if (loadingMsg) { if (data.procedures && data.procedures.length > 0) { loadingText = data.procedures[data.procedures.length - 1].title || "思考中"; } let currentList = cache.chatsContent; currentList.forEach((el) => { if (el.loading_message) { el.text = loadingText; el.record_id = data.record_id; el.tokens_msg = data; // 只有标准模式加这个 if (GLOBAL.webimToken[0].pattern === "standard") { el.is_final = false; } } }); $e.$emit("client_msgContentChange", { chatsContent: cache.chatsContent, type: MESSAGE_TYPE.ANSWER, }); } else { let findedMsg = cache.chatsContent.find( (el) => el.record_id === data.record_id ); if (!findedMsg) return; findedMsg.tokens_msg = data; $e.$emit("client_msgContentChange", { chatsContent: cache.chatsContent, type: MESSAGE_TYPE.ANSWER, }); } }); } // 组装消息队列数据 // 问题确认消息:根据request_id关联覆盖(服务端收到问题后的确认消息) // 答案消息:倒序遍历插入(服务端答案消息) assembleMsgContent(msgList, type) { console.log("assembleMsgContent", msgList, type); let newMsg = msgList; if (type === MESSAGE_TYPE.QUESTION) { // 发送的问题消息由前端临时插入消息队列 cache.chatsContent.push(newMsg); } else if (type === MESSAGE_TYPE.ANSWER) { if (cache.chatsContent.length < 1) { cache.chatsContent.push(newMsg); } else { let currentList = cache.chatsContent; timeoutTasks[newMsg.request_id] && clearTimeout(timeoutTasks[newMsg.request_id]); if (currentList.length === 2 && newMsg.can_rating) { currentList[0].transferRobot = true; } if (newMsg.transfer && newMsg.loading_message) { currentList.pop(); currentList[currentList.length - 1].loading_message = false; currentList[currentList.length - 1] = { ...newMsg, ...currentList[currentList.length - 1], transfer: true, transferRobot: false, }; } else { for (let i = currentList.length - 1; i >= 0; i--) { const { transfer, quit, transferRobot } = currentList[i]; let tmp = { ...newMsg, transfer, quit, transferRobot, }; // 保留tokens_msg,防止覆盖 if (currentList[i].tokens_msg) { tmp = { ...tmp, tokens_msg: currentList[i].tokens_msg }; } // 保留thought 放置被覆盖 if (currentList[i].agent_thought) { tmp = { ...tmp, agent_thought: currentList[i].agent_thought }; } // 保留reference if (currentList[i].references) { tmp = { ...tmp, references: currentList[i].references }; } // 答案消息流式输出覆盖(record_id) if (newMsg.record_id === currentList[i].record_id) { currentList[i] = tmp; break; } // 服务端问题消息确认数据,覆盖前端插入的临时问题消息数据(request_id匹配 & 自己发出的问题消息) if ( newMsg.request_id && newMsg.request_id === currentList[i].request_id && newMsg.is_from_self ) { newMsg.is_loading = false; // 服务端确认收到问题消息,则去除”发送中“状态 currentList[i] = tmp; // 非人工状态时, 并且用户发送的不是敏感消息。插入临时[正在思考中...]消息 if (!newMsg.is_evil && !cache.transferInfo.transferStatus) { currentList.push({ loading_message: true, is_from_self: false, content: "", from_avatar: cache.configInfo.avatar, timestamp: Number(currentList[i].timestamp), // 精确到秒 }); } break; } // 插入最新答案消息 if (Number(newMsg.timestamp) >= Number(currentList[i].timestamp)) { if (currentList[i].loading_message) { // 删除原来的[正在思考中...]消息 currentList[currentList.length - 1] = newMsg; } else { currentList.splice(i + 1, 0, newMsg); } break; } if ( i === 0 && Number(newMsg.timestamp) < Number(currentList[i].timestamp) ) { currentList.splice(0, 0, newMsg); } } } } } else if (type === MESSAGE_TYPE.HISTORY) { let currentList = cache.chatsContent; // 历史数据打上标签,无需展示”重新生成“和”停止生成“操作 msgList = msgList.map((r) => { return { ...r, is_history: true, is_final: true, }; }); if (currentList.length === 0) { // 若消息队列为空(用户端,初始拉取历史记录,用做判断欢迎页展示场景) cache.chatsContent = [].concat(msgList); } else { // 若消息队列不为空 let oldMsgCurrent = currentList[0]; let newMsgHistory = msgList[msgList.length - 1]; // 将历史数据拼装到消息队列中(按照时间戳重排数据) if (Number(newMsgHistory.timestamp) < Number(oldMsgCurrent.timestamp)) { cache.chatsContent = [].concat(msgList).concat(cache.chatsContent); } else { msgList.reverse().forEach((msg) => { for (let i = 0; i < cache.chatsContent.length; i++) { if (msg.record_id === cache.chatsContent[i].record_id) { // 重复覆盖 cache.chatsContent[i] = msg; break; } else if ( Number(msg.timestamp) <= Number(cache.chatsContent[i].timestamp) ) { cache.chatsContent.splice(i, 0, msg); break; } else if ( i === cache.chatsContent.length - 1 && Number(msg.timestamp) > Number(cache.chatsContent[i].timestamp) ) { cache.chatsContent.splice(i + 1, 0, msg); } } }); } } } // 消息去重。同一record_id取最新,同时保留消息最早的时间戳 cache.chatsContent = arrayUnique( cache.chatsContent, "record_id", "timestamp" ); // 消息队列变更通知事件 $e.$emit("client_msgContentChange", { chatsContent: cache.chatsContent, type, }); } // 修改指定msgId的消息内容 modifyMsgContent(msgId) { const findedMsg = this.getMsgById(msgId); if (findedMsg) { findedMsg.is_final = true; findedMsg.content = findedMsg.content.concat( `| 已停止生成` ); $e.$emit("client_msgContentChange", { chatsContent: cache.chatsContent, type: MESSAGE_TYPE.STOP, // ”停止生成“事件 }); } } // 根据msgId获取消息 getMsgById(msgId) { const findedMsg = cache.chatsContent.find((r) => r.record_id === msgId); return findedMsg; } // 根据msgId获取其关联问题消息 getQmsgById(msgId) { let findedQmsg = null; const findedMsg = this.getMsgById(msgId); if (findedMsg) { findedQmsg = cache.chatsContent.find( (r) => r.record_id === findedMsg.related_record_id ); } return findedQmsg; } releaseCache() {} destroy() { // be careful to clear the cache to avoid errors this.releaseCache(); } } export default ClientData;