/** * 文本|语音聊天框 */ import { create } from "zustand"; import { generateUUID } from '@/utils/index' import { getMessageHistories, type TGetMessageHistoriesParams, } from '@/service/bot' import { EChatRole, TAnyMessage, TRobotMessage, TMessage } from "@/types/bot"; type TRobotMessageWithOptionalId = Omit & { msgUk?: string; // 将 messageId 设置为可选 reasoningContent?: string; // 添加 reasoningContent }; const INIT_CURRENT_ROBOT_MSG_UK = '' export interface TextChat { currentRobotMsgUk: string; // 当前正在说话的 AI 机器人 id, 可用于控制是否继续输出文本至当前 message 框内 scrollTop: number; // 控制聊天内容变化后滚动至最底部 autoScroll: boolean list: TAnyMessage[]; questions: string[]; //推荐问题 sessionId: string|null // 显示聊天历史 setAutoScroll: (b: boolean) => void // 是否自动滚动 genSessionId: () => void // 进入聊天界面后,本次的 sessionId setQuestions: (q:string[]) => void // 设置推荐问题 setScrollTop: () => void // 将机器人气泡框推入聊天框 pushRobotMessage: (message: TRobotMessageWithOptionalId) => string; // 将自己发出的气泡框推入聊天框 pushMessage: (content: string) => {msgUk: string, sessionId: string}; // 更新自己发出的气泡框 updateMessage: (content: string, msgUk: string) => string; // 更新机器人汽泡框内的内容实现 gpt 的效果 updateRobotMessage: (content: string, body?: Record, saveStatus?: number) => void; updateRobotReasoningMessage: (msgUk: string, reasoningContent: string, body?:Record) => void; getCurrentRobotMessage:() => TRobotMessage|undefined deleteMessage: (msgUk: string) => void; // 清空 destroy: () => void; fetchMessageHistories: (data: TGetMessageHistoriesParams) => void } // 新messageId 为 index 加 1 const generateUk = () => { return generateUUID(); } export const useTextChat = create((set, get) => ({ currentRobotMsgUk: INIT_CURRENT_ROBOT_MSG_UK, scrollTop: 999999, autoScroll: true, list: [], sessionId: null, questions: [], setAutoScroll: (b)=> { set({autoScroll: b}) }, setQuestions: (q:string[])=> { set({questions: q}) }, genSessionId: ()=> { const sessionId = generateUUID(); set({ sessionId }) }, // 重置 destroy: () => { set({ list: [], questions: [], currentRobotMsgUk: INIT_CURRENT_ROBOT_MSG_UK, scrollTop: 9999, sessionId: null, }); }, pushRobotMessage: (message) => { const msgUk = generateUk() set((state) => { const newRobotMessage = { ...message, msgUk, role: EChatRole.Assistant } as TRobotMessage return { list: [...state.list, newRobotMessage], currentRobotMsgUk: msgUk, scrollTop: state.scrollTop + 1, }; }); setTimeout(()=> { set((state) => { return { scrollTop: state.scrollTop + 1, }; }); }, 100) return msgUk }, setScrollTop: ()=> { set((state) => { return { scrollTop: state.scrollTop + 1, }; }); }, pushMessage: (content: string) => { const msgUk = generateUk(); const newMessage:TMessage ={ msgUk, content: content, role: EChatRole.User, saveStatus: 0 } set((state) => { return { list: [...state.list, newMessage], scrollTop: state.scrollTop + 1, }; }); setTimeout(()=> { set((state) => { return { scrollTop: state.scrollTop + 1, }; }); }, 100) return {msgUk, sessionId: get().sessionId ?? ''} }, updateMessage: (content, msgUk) => { set((state) => { const updatedList = state.list.map((message) => { if (message.msgUk === msgUk) { return { ...message, content: message.content + content, saveStatus: 0 }; // 更新 content } return message; // 返回未修改的 message }); return { list: updatedList, scrollTop: state.scrollTop + 1 }; // 返回新的状态 }); return msgUk }, updateRobotMessage: (content, body={}, saveStatus: number = 0) => { set((state) => { const updatedList = state.list.map((message) => { if (message.msgUk === state.currentRobotMsgUk) { // 更新消息后, saveStatus 变为 0,说明又需要上报此消息 return { ...message, content: message.content + content, body, saveStatus: saveStatus } as TRobotMessage // 更新 content } return message; // 返回未修改的 message }); return { list: updatedList, scrollTop: state.autoScroll ? state.scrollTop + 1 : state.scrollTop}; // 返回新的状态 }); }, getCurrentRobotMessage: ()=> { const state = get() const currentMessage = state.list.find((message)=> message.msgUk === state.currentRobotMsgUk) as TRobotMessage return currentMessage }, updateRobotReasoningMessage: (msgUk, reasoningContent, body={}) => { set((state) => { // 由于 currentRobotMsgUk 可能发生变化, 所以需要传递 msgUk // console.log(state.currentRobotMsgUk, msgUk) const updatedList = state.list.map((message) => { if (message.msgUk === msgUk) { //@ts-ignore return { ...message, body, reasoningContent: message.reasoningContent + reasoningContent } as TRobotMessage // 更新 reasoningContent } return message; // 返回未修改的 message }); return { list: updatedList, scrollTop: state.autoScroll ? state.scrollTop + 1 : state.scrollTop}; // 返回新的状态 }); }, deleteMessage: (msgUk)=> { set((state) => { // 如果对话框是空的,则删除 const filtered = state.list.filter((message) => { const isEmptyContent = message.content.length <= 0 return (message.msgUk !== msgUk && isEmptyContent) }); return { list: filtered, scrollTop: state.scrollTop + 1 }; // 返回新的状态 }); }, // 停止当前机器人说话输出框输出 stopCurrentRobotMessaging: ()=> { set({currentRobotMsgUk: INIT_CURRENT_ROBOT_MSG_UK}) }, fetchMessageHistories: async (data: TGetMessageHistoriesParams) => { const response = await getMessageHistories(data) console.log(response) if(response.status){ } } }));