You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

347 lines
11 KiB

import Vue from "vue";
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(
`<span class="stop-ws">| 已停止生成</span>`
);
$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;