代码整理,ai相关配置转luban,聊天气泡缓存
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* API配置管理
|
||||
* 统一管理所有API相关的配置信息
|
||||
*/
|
||||
|
||||
import ConfigManager from "../manager/ConfigManager";
|
||||
|
||||
export interface AIConfig {
|
||||
/** API密钥 */
|
||||
apiKey: string;
|
||||
/** 模型名称 */
|
||||
model: string;
|
||||
/** 生成温度参数 */
|
||||
temperature: number;
|
||||
/** 最大令牌数 */
|
||||
maxTokens?: number;
|
||||
/** 请求超时时间(毫秒) */
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* API配置管理器
|
||||
*/
|
||||
export class ApiConfig {
|
||||
private static _instance: ApiConfig;
|
||||
private config: AIConfig;
|
||||
|
||||
private constructor() {
|
||||
this.initConfig();
|
||||
}
|
||||
|
||||
public static get Instance(): ApiConfig {
|
||||
if (!this._instance) {
|
||||
this._instance = new ApiConfig();
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化配置
|
||||
* TODO: 应该从环境变量或安全配置文件中读取
|
||||
*/
|
||||
private initConfig(): void {
|
||||
const config = ConfigManager.tables.TbGlobalConfig;
|
||||
this.config = {
|
||||
// 警告: API密钥不应该硬编码在代码中
|
||||
// 生产环境中应该从环境变量或安全配置文件中读取
|
||||
apiKey: config.ApiKey,
|
||||
model: config.Model,
|
||||
temperature: config.Temperature,
|
||||
maxTokens: config.MaxTokens,
|
||||
timeout: config.Timeout, // 30秒
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取AI配置
|
||||
*/
|
||||
public getAIConfig(): AIConfig {
|
||||
return { ...this.config };
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新生成参数
|
||||
* @param temperature 温度参数
|
||||
*/
|
||||
public updateTemperature(temperature: number): void {
|
||||
if (temperature >= 0 && temperature <= 2) {
|
||||
this.config.temperature = temperature;
|
||||
} else {
|
||||
console.warn("Temperature should be between 0 and 2");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证配置是否有效
|
||||
*/
|
||||
public validateConfig(): boolean {
|
||||
if (!this.config.apiKey || this.config.apiKey.trim() === "") {
|
||||
console.error("API key is missing");
|
||||
return false;
|
||||
}
|
||||
if (!this.config.model || this.config.model.trim() === "") {
|
||||
console.error("Model name is missing");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "ef7e0614-de5a-4407-b6bf-35a8854324b8",
|
||||
"uuid": "e7ea0d42-895c-4a18-a177-782ddb6ddefe",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
@@ -1,269 +1,269 @@
|
||||
// 首先加载 polyfills 以确保兼容性
|
||||
import "../utils/polyfills";
|
||||
import { GoogleGenAI } from "@google/genai";
|
||||
import { RoleConfig } from "./RoleConfig";
|
||||
import { ChatHistoryManager } from "./ChatHistoryManager";
|
||||
import { ApiConfig } from "../config/ApiConfig";
|
||||
import { RoleConfigLoader } from "./RoleConfigLoader";
|
||||
import { ChatHistoryManager } from "../manager/ChatHistoryManager";
|
||||
import { ApiConfig } from "./ApiConfigLoader";
|
||||
import { ErrorHandler, ErrorType } from "../utils/ErrorHandler";
|
||||
|
||||
/**
|
||||
* AI聊天服务类
|
||||
*
|
||||
*
|
||||
* 基于Google Gemini API实现的多角色聊天系统,支持:
|
||||
* - 多个独立的聊天实例管理
|
||||
* - 每个角色拥有独立的对话上下文和历史记录
|
||||
* - 本地聊天历史存储和加载
|
||||
* - 动态角色配置和切换
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const chatService = ChatAIService.Instance;
|
||||
* chatService.setCurrentRole(10001);
|
||||
* const response = await chatService.sendMessage(10001, "Hello");
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* @author AI Chat System
|
||||
* @version 2.0.0
|
||||
*/
|
||||
export class ChatAIService {
|
||||
private static _instance: ChatAIService;
|
||||
private ai: GoogleGenAI;
|
||||
private chatInstances: Map<number, any> = new Map();
|
||||
private currentRoleId: number | null = null;
|
||||
private static _instance: ChatAIService;
|
||||
private ai: GoogleGenAI;
|
||||
private chatInstances: Map<number, any> = new Map();
|
||||
private currentRoleId: number | null = null;
|
||||
|
||||
private constructor() {
|
||||
const config = ApiConfig.Instance.getAIConfig();
|
||||
|
||||
// 验证配置
|
||||
if (!ApiConfig.Instance.validateConfig()) {
|
||||
ErrorHandler.Instance.handleError(
|
||||
new Error("AI配置验证失败"),
|
||||
ErrorType.CONFIG_ERROR,
|
||||
{ config },
|
||||
true
|
||||
);
|
||||
throw new Error("AI服务初始化失败:配置无效");
|
||||
}
|
||||
|
||||
try {
|
||||
this.ai = new GoogleGenAI({ apiKey: config.apiKey });
|
||||
} catch (error) {
|
||||
ErrorHandler.Instance.handleError(
|
||||
error as Error,
|
||||
ErrorType.API_ERROR,
|
||||
{ config: { ...config, apiKey: "***" } }, // 隐藏API密钥
|
||||
true
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
private constructor() {
|
||||
const config = ApiConfig.Instance.getAIConfig();
|
||||
|
||||
// 验证配置
|
||||
if (!ApiConfig.Instance.validateConfig()) {
|
||||
ErrorHandler.Instance.handleError(
|
||||
new Error("AI配置验证失败"),
|
||||
ErrorType.CONFIG_ERROR,
|
||||
{ config },
|
||||
true
|
||||
);
|
||||
throw new Error("AI服务初始化失败:配置无效");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ChatAIService的单例实例
|
||||
*
|
||||
* @returns {ChatAIService} 聊天服务实例
|
||||
* @static
|
||||
*/
|
||||
public static get Instance(): ChatAIService {
|
||||
if (!this._instance) {
|
||||
this._instance = new ChatAIService();
|
||||
}
|
||||
return this._instance;
|
||||
try {
|
||||
this.ai = new GoogleGenAI({ apiKey: config.apiKey });
|
||||
} catch (error) {
|
||||
ErrorHandler.Instance.handleError(
|
||||
error as Error,
|
||||
ErrorType.API_ERROR,
|
||||
{ config: { ...config, apiKey: "***" } }, // 隐藏API密钥
|
||||
true
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ChatAIService的单例实例
|
||||
*
|
||||
* @returns {ChatAIService} 聊天服务实例
|
||||
* @static
|
||||
*/
|
||||
public static get Instance(): ChatAIService {
|
||||
if (!this._instance) {
|
||||
this._instance = new ChatAIService();
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建或获取指定角色的聊天实例
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
private createOrGetChat(roleId: number): any {
|
||||
if (!this.chatInstances.has(roleId)) {
|
||||
const systemInstruction = RoleConfigLoader.getRoleInstruction(roleId);
|
||||
const config = ApiConfig.Instance.getAIConfig();
|
||||
|
||||
// 从本地加载历史记录
|
||||
const savedHistory = ChatHistoryManager.Instance.loadHistory(roleId);
|
||||
let chat;
|
||||
if (savedHistory && savedHistory.length > 0) {
|
||||
chat = this.ai.chats.create({
|
||||
model: config.model,
|
||||
config: {
|
||||
temperature: config.temperature,
|
||||
systemInstruction: systemInstruction,
|
||||
},
|
||||
history: savedHistory,
|
||||
});
|
||||
} else {
|
||||
chat = this.ai.chats.create({
|
||||
model: config.model,
|
||||
config: {
|
||||
temperature: config.temperature,
|
||||
systemInstruction: systemInstruction,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前活动的角色ID
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
public setCurrentRole(roleId: number): void {
|
||||
this.currentRoleId = roleId;
|
||||
// 预创建聊天实例
|
||||
this.createOrGetChat(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前角色ID
|
||||
*/
|
||||
public getCurrentRoleId(): number | null {
|
||||
return this.currentRoleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 向指定角色发送消息并获取AI回复
|
||||
*
|
||||
* @param {number} roleId - 角色ID,用于区分不同的聊天实例
|
||||
* @param {string} message - 用户发送的消息内容
|
||||
* @returns {Promise<string>} AI的回复消息,如果发生错误返回null
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const response = await chatService.sendMessage(10001, "你好");
|
||||
* console.log(response); // AI的回复
|
||||
* ```
|
||||
*/
|
||||
public async sendMessage(roleId: number, message: string): Promise<string> {
|
||||
// 输入验证
|
||||
if (!roleId || roleId <= 0) {
|
||||
ErrorHandler.Instance.handleValidationError(
|
||||
"roleId",
|
||||
"角色ID必须是正整数",
|
||||
roleId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建或获取指定角色的聊天实例
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
private createOrGetChat(roleId: number): any {
|
||||
if (!this.chatInstances.has(roleId)) {
|
||||
const systemInstruction = RoleConfig.getRoleInstruction(roleId);
|
||||
const config = ApiConfig.Instance.getAIConfig();
|
||||
|
||||
// 从本地加载历史记录
|
||||
const savedHistory = ChatHistoryManager.Instance.loadHistory(roleId);
|
||||
let chat;
|
||||
if(savedHistory && savedHistory.length > 0) {
|
||||
chat = this.ai.chats.create({
|
||||
model: config.model,
|
||||
config: {
|
||||
temperature: config.temperature,
|
||||
systemInstruction: systemInstruction
|
||||
},
|
||||
history: savedHistory
|
||||
});
|
||||
}else{
|
||||
chat = this.ai.chats.create({
|
||||
model: config.model,
|
||||
config: {
|
||||
temperature: config.temperature,
|
||||
systemInstruction: systemInstruction
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
if (!message || message.trim() === "") {
|
||||
ErrorHandler.Instance.handleValidationError(
|
||||
"message",
|
||||
"消息内容不能为空",
|
||||
message
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前活动的角色ID
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
public setCurrentRole(roleId: number): void {
|
||||
this.currentRoleId = roleId;
|
||||
// 预创建聊天实例
|
||||
this.createOrGetChat(roleId);
|
||||
}
|
||||
try {
|
||||
const chat = this.createOrGetChat(roleId);
|
||||
const response = await chat.sendMessage({
|
||||
message: message.trim(),
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取当前角色ID
|
||||
*/
|
||||
public getCurrentRoleId(): number | null {
|
||||
return this.currentRoleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 向指定角色发送消息并获取AI回复
|
||||
*
|
||||
* @param {number} roleId - 角色ID,用于区分不同的聊天实例
|
||||
* @param {string} message - 用户发送的消息内容
|
||||
* @returns {Promise<string>} AI的回复消息,如果发生错误返回null
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const response = await chatService.sendMessage(10001, "你好");
|
||||
* console.log(response); // AI的回复
|
||||
* ```
|
||||
*/
|
||||
public async sendMessage(roleId: number, message: string): Promise<string> {
|
||||
// 输入验证
|
||||
if (!roleId || roleId <= 0) {
|
||||
ErrorHandler.Instance.handleValidationError(
|
||||
"roleId",
|
||||
"角色ID必须是正整数",
|
||||
roleId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!message || message.trim() === "") {
|
||||
ErrorHandler.Instance.handleValidationError(
|
||||
"message",
|
||||
"消息内容不能为空",
|
||||
message
|
||||
);
|
||||
return null;
|
||||
}
|
||||
if (response && response.text) {
|
||||
console.log(`Response from role ${roleId}:`, response.text);
|
||||
|
||||
try {
|
||||
const chat = this.createOrGetChat(roleId);
|
||||
const response = await chat.sendMessage({
|
||||
message: message.trim()
|
||||
});
|
||||
// 保存用户消息
|
||||
ChatHistoryManager.Instance.appendMessage(roleId, {
|
||||
role: "user",
|
||||
parts: [{ text: message }],
|
||||
});
|
||||
|
||||
if (response && response.text) {
|
||||
console.log(`Response from role ${roleId}:`, response.text);
|
||||
|
||||
try {
|
||||
// 保存用户消息
|
||||
ChatHistoryManager.Instance.appendMessage(roleId, {
|
||||
role: "user",
|
||||
parts: [{ text: message }]
|
||||
});
|
||||
|
||||
// 保存AI回复
|
||||
ChatHistoryManager.Instance.appendMessage(roleId, {
|
||||
role: "model",
|
||||
parts: [{ text: response.text }]
|
||||
});
|
||||
} catch (storageError) {
|
||||
ErrorHandler.Instance.handleError(
|
||||
storageError as Error,
|
||||
ErrorType.STORAGE_ERROR,
|
||||
{ roleId, message: message.substring(0, 100) },
|
||||
false
|
||||
);
|
||||
// 即使存储失败,也返回AI回复
|
||||
}
|
||||
|
||||
return response.text;
|
||||
} else {
|
||||
const warningMsg = `AI返回了空响应 (角色ID: ${roleId})`;
|
||||
ErrorHandler.Instance.handleError(
|
||||
new Error(warningMsg),
|
||||
ErrorType.API_ERROR,
|
||||
{ roleId, message, response },
|
||||
true
|
||||
);
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
ErrorHandler.Instance.handleApiError(
|
||||
error,
|
||||
"sendMessage",
|
||||
{ roleId, message: message.substring(0, 100) + "..." }
|
||||
);
|
||||
return null;
|
||||
// 保存AI回复
|
||||
ChatHistoryManager.Instance.appendMessage(roleId, {
|
||||
role: "model",
|
||||
parts: [{ text: response.text }],
|
||||
});
|
||||
} catch (storageError) {
|
||||
ErrorHandler.Instance.handleError(
|
||||
storageError as Error,
|
||||
ErrorType.STORAGE_ERROR,
|
||||
{ roleId, message: message.substring(0, 100) },
|
||||
false
|
||||
);
|
||||
// 即使存储失败,也返回AI回复
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除指定角色的聊天历史
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
public clearChatHistory(roleId: number): void {
|
||||
if (this.chatInstances.has(roleId)) {
|
||||
this.chatInstances.delete(roleId);
|
||||
}
|
||||
// 清除本地存储的历史
|
||||
ChatHistoryManager.Instance.clearHistory(roleId);
|
||||
console.log(`Cleared chat history for role ${roleId}`);
|
||||
return response.text;
|
||||
} else {
|
||||
const warningMsg = `AI返回了空响应 (角色ID: ${roleId})`;
|
||||
ErrorHandler.Instance.handleError(
|
||||
new Error(warningMsg),
|
||||
ErrorType.API_ERROR,
|
||||
{ roleId, message, response },
|
||||
true
|
||||
);
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
ErrorHandler.Instance.handleApiError(error, "sendMessage", {
|
||||
roleId,
|
||||
message: message.substring(0, 100) + "...",
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有聊天历史
|
||||
*/
|
||||
public clearAllChatHistory(): void {
|
||||
this.chatInstances.clear();
|
||||
// 清除本地存储的所有历史
|
||||
ChatHistoryManager.Instance.clearAllHistory();
|
||||
console.log("Cleared all chat histories");
|
||||
/**
|
||||
* 清除指定角色的聊天历史
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
public clearChatHistory(roleId: number): void {
|
||||
if (this.chatInstances.has(roleId)) {
|
||||
this.chatInstances.delete(roleId);
|
||||
}
|
||||
// 清除本地存储的历史
|
||||
ChatHistoryManager.Instance.clearHistory(roleId);
|
||||
console.log(`Cleared chat history for role ${roleId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前活跃的聊天实例数量
|
||||
*/
|
||||
public getActiveChatCount(): number {
|
||||
return this.chatInstances.size;
|
||||
}
|
||||
/**
|
||||
* 清除所有聊天历史
|
||||
*/
|
||||
public clearAllChatHistory(): void {
|
||||
this.chatInstances.clear();
|
||||
// 清除本地存储的所有历史
|
||||
ChatHistoryManager.Instance.clearAllHistory();
|
||||
console.log("Cleared all chat histories");
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容旧接口的Post方法
|
||||
* @deprecated 请使用sendMessage方法,此方法将在下个版本中移除
|
||||
*/
|
||||
public async Post(data: GPTRequest): Promise<string> {
|
||||
console.warn("Post方法已废弃,请使用sendMessage方法");
|
||||
const roleId = this.currentRoleId || 10001; // 默认使用第一个角色
|
||||
const message = data.messages[0]?.content || "";
|
||||
return this.sendMessage(roleId, message);
|
||||
}
|
||||
/**
|
||||
* 获取当前活跃的聊天实例数量
|
||||
*/
|
||||
public getActiveChatCount(): number {
|
||||
return this.chatInstances.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容旧接口的Post方法
|
||||
* @deprecated 请使用sendMessage方法,此方法将在下个版本中移除
|
||||
*/
|
||||
public async Post(data: GPTRequest): Promise<string> {
|
||||
console.warn("Post方法已废弃,请使用sendMessage方法");
|
||||
const roleId = this.currentRoleId || 10001; // 默认使用第一个角色
|
||||
const message = data.messages[0]?.content || "";
|
||||
return this.sendMessage(roleId, message);
|
||||
}
|
||||
}
|
||||
|
||||
// 请求数据类型定义
|
||||
export interface GPTRequest {
|
||||
model: string;
|
||||
messages: { role: string; content: string }[];
|
||||
temperature: number;
|
||||
id: string;
|
||||
model: string;
|
||||
messages: { role: string; content: string }[];
|
||||
temperature: number;
|
||||
id: string;
|
||||
}
|
||||
|
||||
// 兼容旧名称(已废弃,建议使用 GPTRequest)
|
||||
@@ -273,21 +273,21 @@ export type GPTResquest = GPTRequest;
|
||||
// 响应数据类型定义(当前未使用,预留用于未来API调用统计)
|
||||
/** @deprecated 当前未使用,考虑移除或实现API统计功能时使用 */
|
||||
export interface GPTResult {
|
||||
id: string;
|
||||
object: string;
|
||||
created: number;
|
||||
model: string;
|
||||
usage: {
|
||||
prompt_tokens: number;
|
||||
completion_tokens: number;
|
||||
total_tokens: number;
|
||||
id: string;
|
||||
object: string;
|
||||
created: number;
|
||||
model: string;
|
||||
usage: {
|
||||
prompt_tokens: number;
|
||||
completion_tokens: number;
|
||||
total_tokens: number;
|
||||
};
|
||||
choices: {
|
||||
message: {
|
||||
role: string;
|
||||
content: string;
|
||||
};
|
||||
choices: {
|
||||
message: {
|
||||
role: string;
|
||||
content: string;
|
||||
};
|
||||
finish_reason: string;
|
||||
index: number;
|
||||
}[];
|
||||
}
|
||||
finish_reason: string;
|
||||
index: number;
|
||||
}[];
|
||||
}
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
import { sys } from "cc";
|
||||
|
||||
export interface ChatMessage {
|
||||
role: "user" | "model";
|
||||
parts: { text: string }[];
|
||||
timestamp?: number;
|
||||
}
|
||||
|
||||
export interface ChatHistory {
|
||||
roleId: number;
|
||||
messages: ChatMessage[];
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 聊天历史管理器
|
||||
* 负责聊天记录的本地存储、加载和管理
|
||||
*/
|
||||
export class ChatHistoryManager {
|
||||
private static _instance: ChatHistoryManager;
|
||||
|
||||
public static get Instance(): ChatHistoryManager {
|
||||
if (!this._instance) {
|
||||
this._instance = new ChatHistoryManager();
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
private constructor() {}
|
||||
|
||||
/**
|
||||
* 保存聊天历史到本地
|
||||
* @param roleId 角色ID
|
||||
* @param messages 消息列表
|
||||
*/
|
||||
public saveHistory(roleId: number, messages: ChatMessage[]): void {
|
||||
const key = `chat_history_${roleId}`;
|
||||
try {
|
||||
const history: ChatHistory = {
|
||||
roleId: roleId,
|
||||
messages: messages,
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now()
|
||||
};
|
||||
|
||||
sys.localStorage.setItem(key, JSON.stringify(history));
|
||||
console.log(`Saved chat history for role ${roleId}, ${messages.length} messages`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to save chat history for role ${roleId}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从本地加载聊天历史
|
||||
* @param roleId 角色ID
|
||||
* @returns 消息列表,如果没有历史记录则返回空数组
|
||||
*/
|
||||
public loadHistory(roleId: number): ChatMessage[] {
|
||||
const key = `chat_history_${roleId}`;
|
||||
try {
|
||||
const data = sys.localStorage.getItem(key);
|
||||
if (data) {
|
||||
const history: ChatHistory = JSON.parse(data);
|
||||
console.log(`Loaded chat history for role ${roleId}: ${history.messages.length} messages`);
|
||||
return history.messages;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to load chat history for role ${roleId}:`, error);
|
||||
// 如果数据损坏,清除错误的数据
|
||||
this.clearHistory(roleId);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除指定角色的聊天历史
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
public clearHistory(roleId: number): void {
|
||||
const key = `chat_history_${roleId}`;
|
||||
sys.localStorage.removeItem(key);
|
||||
console.log(`Cleared chat history for role ${roleId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加消息到历史记录
|
||||
* @param roleId 角色ID
|
||||
* @param message 消息对象
|
||||
*/
|
||||
public appendMessage(roleId: number, message: ChatMessage): void {
|
||||
const history = this.loadHistory(roleId);
|
||||
|
||||
// 添加时间戳
|
||||
message.timestamp = Date.now();
|
||||
history.push(message);
|
||||
|
||||
// 限制历史长度,保留最近100条消息
|
||||
if (history.length > 100) {
|
||||
history.splice(0, history.length - 100);
|
||||
console.log(`Trimmed chat history for role ${roleId} to 100 messages`);
|
||||
}
|
||||
|
||||
this.saveHistory(roleId, history);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定角色的消息数量
|
||||
* @param roleId 角色ID
|
||||
* @returns 消息数量
|
||||
*/
|
||||
public getMessageCount(roleId: number): number {
|
||||
const history = this.loadHistory(roleId);
|
||||
return history.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最近的N条消息
|
||||
* @param roleId 角色ID
|
||||
* @param count 消息数量
|
||||
* @returns 最近的消息列表
|
||||
*/
|
||||
public getRecentMessages(roleId: number, count: number = 10): ChatMessage[] {
|
||||
const history = this.loadHistory(roleId);
|
||||
return history.slice(-count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有聊天历史
|
||||
*/
|
||||
public clearAllHistory(): void {
|
||||
// 查找所有chat_history_开头的key
|
||||
const keysToRemove: string[] = [];
|
||||
for (let i = 0; i < sys.localStorage.length; i++) {
|
||||
const key = sys.localStorage.key(i);
|
||||
if (key && key.startsWith('chat_history_')) {
|
||||
keysToRemove.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
// 删除找到的所有聊天历史
|
||||
keysToRemove.forEach(key => {
|
||||
sys.localStorage.removeItem(key);
|
||||
});
|
||||
|
||||
console.log(`Cleared all chat histories, ${keysToRemove.length} records removed`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有有历史记录的角色ID列表
|
||||
* @returns 角色ID数组
|
||||
*/
|
||||
public getAllHistoryRoleIds(): number[] {
|
||||
const roleIds: number[] = [];
|
||||
for (let i = 0; i < sys.localStorage.length; i++) {
|
||||
const key = sys.localStorage.key(i);
|
||||
if (key && key.startsWith('chat_history_')) {
|
||||
const roleId = parseInt(key.replace('chat_history_', ''));
|
||||
if (!isNaN(roleId)) {
|
||||
roleIds.push(roleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return roleIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 准备上传到远程服务器(预留接口)
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
public async syncToRemote(roleId: number): Promise<void> {
|
||||
const history = this.loadHistory(roleId);
|
||||
if (history.length === 0) {
|
||||
console.log(`No history to sync for role ${roleId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO: 调用 HttpUnit.ins.api 上传到服务器
|
||||
// await HttpUnit.ins.api("chat/save_history", {
|
||||
// role_id: roleId,
|
||||
// messages: history
|
||||
// }, "POST");
|
||||
|
||||
console.log(`Ready to sync ${history.length} messages for role ${roleId} to remote server`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to sync history for role ${roleId}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从远程服务器下载历史(预留接口)
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
public async syncFromRemote(roleId: number): Promise<void> {
|
||||
try {
|
||||
// TODO: 调用 HttpUnit.ins.api 从服务器获取历史
|
||||
// const response = await HttpUnit.ins.api("chat/get_history", {
|
||||
// role_id: roleId
|
||||
// }, "GET");
|
||||
|
||||
// if (response && response.messages) {
|
||||
// this.saveHistory(roleId, response.messages);
|
||||
// console.log(`Synced ${response.messages.length} messages from remote for role ${roleId}`);
|
||||
// }
|
||||
|
||||
console.log(`Ready to sync history from remote server for role ${roleId}`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to sync from remote for role ${roleId}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import System_Instruction from "../config/SystemPrompts";
|
||||
|
||||
/**
|
||||
* 角色配置映射
|
||||
* 将角色ID映射到对应的System Instruction
|
||||
*/
|
||||
export class RoleConfig {
|
||||
private static roleMap: Map<number, string> = new Map([
|
||||
[10001, System_Instruction.Role_1], // Anaya Kapoor - 成熟魅惑型
|
||||
[10002, System_Instruction.Role_2], // Meher Joshi - 猫咪性格
|
||||
[10003, System_Instruction.Role_3], // Sana Reddy - 小狗性格
|
||||
]);
|
||||
|
||||
/**
|
||||
* 根据角色ID获取对应的System Instruction
|
||||
* @param roleId 角色ID
|
||||
* @returns System Instruction字符串,如果未找到则返回默认Role_1
|
||||
*/
|
||||
public static getRoleInstruction(roleId: number): string {
|
||||
return this.roleMap.get(roleId) || System_Instruction.Role_1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加或更新角色配置
|
||||
* @param roleId 角色ID
|
||||
* @param instruction System Instruction内容
|
||||
*/
|
||||
public static setRoleInstruction(roleId: number, instruction: string): void {
|
||||
this.roleMap.set(roleId, instruction);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查角色是否存在配置
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
public static hasRole(roleId: number): boolean {
|
||||
return this.roleMap.has(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有配置的角色ID
|
||||
*/
|
||||
public static getAllRoleIds(): number[] {
|
||||
return Array.from(this.roleMap.keys());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { AiCharacter } from "../../schema/schema";
|
||||
import ConfigManager from "../manager/ConfigManager";
|
||||
|
||||
/**
|
||||
* 角色配置映射
|
||||
* 将角色ID映射到对应的System Instruction
|
||||
*/
|
||||
export class RoleConfigLoader {
|
||||
/**
|
||||
* 根据角色ID获取对应的System Instruction
|
||||
* @param roleId 角色ID
|
||||
* @returns System Instruction字符串,如果未找到则返回默认Role_1
|
||||
*/
|
||||
public static getRoleInstruction(roleId: number): string {
|
||||
const AiCharacter = ConfigManager.tables.TbAiCharacters.get(roleId);
|
||||
|
||||
return AiCharacter
|
||||
? AiCharacter.systemInstruction
|
||||
: ConfigManager.tables.TbAiCharacters.get(10001).systemInstruction;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查角色是否存在配置
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
public static hasRole(roleId: number): boolean {
|
||||
return ConfigManager.tables.TbAiCharacters.get(roleId) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有配置的角色ID
|
||||
*/
|
||||
public static getAllRoles(): AiCharacter[] {
|
||||
return ConfigManager.tables.TbAiCharacters.getDataList();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "635087af-dfed-4857-bb82-9f7b296b3ee1",
|
||||
"uuid": "93d02d5d-af10-49ca-98ce-7d9e09568de7",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
Reference in New Issue
Block a user