From 24b9942110d3cb27a06e27b0033ceb2316c7dacb Mon Sep 17 00:00:00 2001 From: xlj <543978819@qq.com> Date: Wed, 10 Sep 2025 20:08:43 +0800 Subject: [PATCH] =?UTF-8?q?=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=AB=AF+=E6=9C=AC=E5=9C=B0=E6=B7=B7=E5=90=88?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/Scripts/chat18x/core/ChatAIService.ts | 67 +++---- .../chat18x/manager/ChatHistoryManager.ts | 166 ++++++++++++++++++ proto_cs | 2 +- xchat_cfg | 2 +- 4 files changed, 202 insertions(+), 35 deletions(-) diff --git a/assets/Scripts/chat18x/core/ChatAIService.ts b/assets/Scripts/chat18x/core/ChatAIService.ts index ba24a4b2..aa7e6537 100644 --- a/assets/Scripts/chat18x/core/ChatAIService.ts +++ b/assets/Scripts/chat18x/core/ChatAIService.ts @@ -9,7 +9,7 @@ import { EmotionAIService } from "./EmotionAIService"; import { ChatService } from "db://assets/Scripts/chat18x/network/services/ChatService"; import { DataManager, DataId } from "../data/DataManager"; import { GirlData } from "../data/GirlData"; -import proto from 'db://assets/Scripts/proto/proto.pb.js'; +import proto from "db://assets/Scripts/proto/proto.pb.js"; /** * AI聊天服务类 @@ -85,20 +85,9 @@ export class ChatAIService { const systemInstruction = RoleConfigLoader.getRoleInstruction(roleId); const config = ApiConfig.Instance.getAIConfig(); - // // 获取聊天数据 - // await this.reqGetChatMsg(roleId, 1, 20); - // const girlData = DataManager.I.getDataById(DataId.Girl); - // const category = girlData.getGrilCategoryById(roleId); - // const ids = girlData.getChatRecordIds(category.toString(), roleId); - // for (let id of ids) { - // let isAi = girlData.getChatRecordIsAi(category.toString(), roleId, id); - // let mgs = girlData.getChatRecordMsg(category.toString(), roleId, id); - // } - - - - // 从本地加载历史记录 - const savedHistory = ChatHistoryManager.Instance.loadHistory(roleId); + // 使用 ChatHistoryManager 的统一加载方法(优先本地,无则获取服务端) + const savedHistory = await ChatHistoryManager.Instance.loadChatHistory(roleId); + let chat; if (savedHistory && savedHistory.length > 0) { chat = this.ai.chats.create({ @@ -115,6 +104,9 @@ export class ChatAIService { }, history: savedHistory, }); + console.log( + `Loaded ${savedHistory.length} history messages for role ${roleId}` + ); } else { chat = this.ai.chats.create({ model: config.model, @@ -129,17 +121,10 @@ export class ChatAIService { ], }, }); + console.log(`Created new chat instance for role ${roleId}`); } this.chatInstances.set(roleId, chat); - - if (savedHistory.length > 0) { - console.log( - `Loaded ${savedHistory.length} history messages for role ${roleId}` - ); - } else { - console.log(`Created new chat instance for role ${roleId}`); - } } return this.chatInstances.get(roleId); } @@ -148,10 +133,10 @@ export class ChatAIService { * 设置当前活动的角色ID * @param roleId 角色ID */ - public setCurrentRole(roleId: number): void { + public async setCurrentRole(roleId: number): Promise { this.currentRoleId = roleId; // 预创建聊天实例 - this.createOrGetChat(roleId); + await this.createOrGetChat(roleId); // 预创建情绪聊天实例 EmotionAIService.Instance.ensureEmotionChatExists(roleId); } @@ -197,7 +182,7 @@ export class ChatAIService { } try { - const chat = this.createOrGetChat(roleId); + const chat = await this.createOrGetChat(roleId); const response = await chat.sendMessage({ message: message.trim(), }); @@ -228,7 +213,7 @@ export class ChatAIService { let aiData = { isAi: true, msg: response.text, - }; + }; msgList.push(aiData); this.reqChatMsg(roleId, msgList); @@ -237,7 +222,7 @@ export class ChatAIService { roleId, message, response.text - ).catch(emotionError => { + ).catch((emotionError) => { console.warn( `Failed to update emotion for role ${roleId}:`, emotionError @@ -337,8 +322,16 @@ export class ChatAIService { // 保存数据 const girlData = DataManager.I.getDataById(DataId.Girl); const category = girlData.getGrilCategoryById(girlId); - girlData.setChatTotalCount(category.toString(), girlId, resData.chatTotalCount); - girlData.setChatRemainCount(category.toString(), girlId, resData.chatRemainCount); + girlData.setChatTotalCount( + category.toString(), + girlId, + resData.chatTotalCount + ); + girlData.setChatRemainCount( + category.toString(), + girlId, + resData.chatRemainCount + ); } } @@ -361,10 +354,18 @@ export class ChatAIService { const girlData = DataManager.I.getDataById(DataId.Girl); const category = girlData.getGrilCategoryById(girlId); girlData.setChatRecord(category.toString(), girlId, resData.msgs); - girlData.setChatTotalCount(category.toString(), girlId, resData.chatTotalCount); - girlData.setChatRemainCount(category.toString(), girlId, resData.chatRemainCount); + girlData.setChatTotalCount( + category.toString(), + girlId, + resData.chatTotalCount + ); + girlData.setChatRemainCount( + category.toString(), + girlId, + resData.chatRemainCount + ); } - } + } } // 请求数据类型定义 diff --git a/assets/Scripts/chat18x/manager/ChatHistoryManager.ts b/assets/Scripts/chat18x/manager/ChatHistoryManager.ts index 69a7fed4..5844ffed 100644 --- a/assets/Scripts/chat18x/manager/ChatHistoryManager.ts +++ b/assets/Scripts/chat18x/manager/ChatHistoryManager.ts @@ -1,4 +1,8 @@ import { sys } from "cc"; +import { DataManager, DataId } from "../data/DataManager"; +import { GirlData } from "../data/GirlData"; +import proto from "db://assets/Scripts/proto/proto.pb.js"; +import { ChatService } from "../network/services/ChatService"; export interface ChatMessage { role: "user" | "model"; @@ -209,4 +213,166 @@ export class ChatHistoryManager { console.error(`Failed to sync from remote for role ${roleId}:`, error); } } + + /** + * 转换服务端聊天数据为本地格式 + * @param serverMessages 服务端聊天消息数组 + * @returns 本地格式的聊天消息数组 + */ + private convertServerDataToLocalFormat(serverMessages: proto.cs.IChatMsg[]): ChatMessage[] { + if (!serverMessages || serverMessages.length === 0) { + return []; + } + + const messages: ChatMessage[] = []; + for (const serverMsg of serverMessages) { + if (serverMsg.msg) { + const message: ChatMessage = { + role: serverMsg.isAi ? "model" : "user", + parts: [{ text: serverMsg.msg }], + timestamp: serverMsg.msgId || Date.now() + }; + messages.push(message); + } + } + + // 按时间戳排序,确保消息顺序正确 + messages.sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0)); + + console.log(`Converted ${serverMessages.length} server messages to ${messages.length} local messages`); + return messages; + } + + /** + * 从服务端获取聊天记录 + * @param roleId 角色ID + * @param page 页码 + * @param limit 每页数量 + * @returns 是否成功获取数据 + */ + private async fetchServerChatHistory(roleId: number, page: number = 1, limit: number = 20): Promise { + try { + const reqData = { + GirlId: roleId, + page, + limit, + }; + + console.log("获取服务端聊天记录:", reqData); + const res = await ChatService.I.reqGetChatMsg(reqData); + + if (res && res.code === proto.cs.EnmRetCode.SUCCESS) { + const resData = res.data; + // 保存到 GirlData + const girlData = DataManager.I.getDataById(DataId.Girl); + const category = girlData.getGrilCategoryById(roleId); + girlData.setChatRecord(category.toString(), roleId, resData.msgs); + girlData.setChatTotalCount(category.toString(), roleId, resData.chatTotalCount); + girlData.setChatRemainCount(category.toString(), roleId, resData.chatRemainCount); + + console.log(`成功从服务端获取聊天记录,roleId: ${roleId}, 消息数: ${resData.msgs?.length || 0}`); + return true; + } else { + console.warn(`从服务端获取聊天记录失败,roleId: ${roleId}, code: ${res?.code}`); + return false; + } + } catch (error) { + console.error(`获取服务端聊天记录异常,roleId: ${roleId}:`, error); + return false; + } + } + + /** + * 合并本地和服务端聊天记录 + * @param localMessages 本地消息 + * @param serverMessages 服务端消息 + * @returns 合并后的消息数组 + */ + private mergeHistories(localMessages: ChatMessage[], serverMessages: ChatMessage[]): ChatMessage[] { + if (!localMessages || localMessages.length === 0) { + return serverMessages || []; + } + + if (!serverMessages || serverMessages.length === 0) { + return localMessages; + } + + // 使用 Map 进行去重,以时间戳为键 + const messageMap = new Map(); + + // 先添加本地消息(优先级更高) + localMessages.forEach(msg => { + if (msg.timestamp) { + messageMap.set(msg.timestamp, msg); + } + }); + + // 添加服务端消息(如果时间戳不冲突) + serverMessages.forEach(msg => { + if (msg.timestamp && !messageMap.has(msg.timestamp)) { + messageMap.set(msg.timestamp, msg); + } + }); + + // 转换回数组并排序 + const mergedMessages = Array.from(messageMap.values()); + mergedMessages.sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0)); + + console.log(`合并聊天记录: 本地 ${localMessages.length} 条, 服务端 ${serverMessages.length} 条, 合并后 ${mergedMessages.length} 条`); + return mergedMessages; + } + + /** + * 整合的聊天记录加载方法:优先加载本地数据,如果本地没有再获取服务端数据 + * @param roleId 角色ID + * @returns 聊天消息数组 + */ + public async loadChatHistory(roleId: number): Promise { + // 1. 首先尝试从本地加载 + const localHistory = this.loadHistory(roleId); + + // 2. 如果本地有数据,直接返回 + if (localHistory && localHistory.length > 0) { + console.log(`使用本地聊天记录,roleId: ${roleId}, 消息数: ${localHistory.length}`); + return localHistory; + } + + // 3. 本地没有数据,尝试从服务端获取 + console.log(`本地无聊天记录,尝试从服务端获取,roleId: ${roleId}`); + const serverSuccess = await this.fetchServerChatHistory(roleId); + + if (!serverSuccess) { + console.log(`服务端获取失败,返回空记录,roleId: ${roleId}`); + return []; + } + + // 4. 从 GirlData 读取服务端数据并转换格式 + const girlData = DataManager.I.getDataById(DataId.Girl); + const category = girlData.getGrilCategoryById(roleId); + const serverMsgIds = girlData.getChatRecordIds(category.toString(), roleId); + + const serverMessages: proto.cs.IChatMsg[] = []; + for (const id of serverMsgIds) { + const isAi = girlData.getChatRecordIsAi(category.toString(), roleId, id); + const msg = girlData.getChatRecordMsg(category.toString(), roleId, id); + if (msg) { + serverMessages.push({ + msgId: id, + msg: msg, + isAi: isAi + }); + } + } + + // 5. 转换服务端数据格式 + const convertedMessages = this.convertServerDataToLocalFormat(serverMessages); + + // 6. 保存到本地存储 + if (convertedMessages.length > 0) { + this.saveHistory(roleId, convertedMessages); + console.log(`从服务端获取并保存聊天记录,roleId: ${roleId}, 消息数: ${convertedMessages.length}`); + } + + return convertedMessages; + } } \ No newline at end of file diff --git a/proto_cs b/proto_cs index 02474af6..f055100c 160000 --- a/proto_cs +++ b/proto_cs @@ -1 +1 @@ -Subproject commit 02474af62a6831a909fa28fefa83afa382cc86ee +Subproject commit f055100cf0f378ddd96d8e153655b5166c65e6e8 diff --git a/xchat_cfg b/xchat_cfg index 3bc76d7e..659dec1b 160000 --- a/xchat_cfg +++ b/xchat_cfg @@ -1 +1 @@ -Subproject commit 3bc76d7ecf80cc96707703c8ec458c001b03a61c +Subproject commit 659dec1b4cdc1f1a0001a17e49263924e6403a5f