Chat相关表现&逻辑分离,新增ChatController
新增情绪机器人逻辑, 新增情绪切换视频逻辑
This commit is contained in:
@@ -60,6 +60,20 @@ export class ApiConfig {
|
||||
return { ...this.config };
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取情绪AI配置
|
||||
*/
|
||||
public getEmotionAIConfig(): AIConfig {
|
||||
const config = ConfigManager.tables.TbGlobalConfig;
|
||||
return {
|
||||
apiKey: config.emotionApiKey,
|
||||
model: config.Model,
|
||||
temperature: config.Temperature,
|
||||
maxTokens: config.MaxTokens,
|
||||
timeout: config.Timeout,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新生成参数
|
||||
* @param temperature 温度参数
|
||||
|
||||
@@ -5,6 +5,7 @@ import { RoleConfigLoader } from "./RoleConfigLoader";
|
||||
import { ChatHistoryManager } from "../manager/ChatHistoryManager";
|
||||
import { ApiConfig } from "./ApiConfigLoader";
|
||||
import { ErrorHandler, ErrorType } from "../utils/ErrorHandler";
|
||||
import { EmotionAIService } from "./EmotionAIService";
|
||||
|
||||
/**
|
||||
* AI聊天服务类
|
||||
@@ -123,6 +124,8 @@ export class ChatAIService {
|
||||
this.currentRoleId = roleId;
|
||||
// 预创建聊天实例
|
||||
this.createOrGetChat(roleId);
|
||||
// 预创建情绪聊天实例
|
||||
EmotionAIService.Instance.ensureEmotionChatExists(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,6 +189,14 @@ export class ChatAIService {
|
||||
role: "model",
|
||||
parts: [{ text: response.text }],
|
||||
});
|
||||
|
||||
// 更新情绪状态
|
||||
try {
|
||||
await EmotionAIService.Instance.updateEmotionFromChat(roleId, message, response.text);
|
||||
} catch (emotionError) {
|
||||
console.warn(`Failed to update emotion for role ${roleId}:`, emotionError);
|
||||
// 情绪更新失败不影响聊天功能
|
||||
}
|
||||
} catch (storageError) {
|
||||
ErrorHandler.Instance.handleError(
|
||||
storageError as Error,
|
||||
@@ -224,6 +235,8 @@ export class ChatAIService {
|
||||
if (this.chatInstances.has(roleId)) {
|
||||
this.chatInstances.delete(roleId);
|
||||
}
|
||||
// 清除情绪聊天历史
|
||||
EmotionAIService.Instance.clearEmotionHistory(roleId);
|
||||
// 清除本地存储的历史
|
||||
ChatHistoryManager.Instance.clearHistory(roleId);
|
||||
console.log(`Cleared chat history for role ${roleId}`);
|
||||
@@ -234,6 +247,8 @@ export class ChatAIService {
|
||||
*/
|
||||
public clearAllChatHistory(): void {
|
||||
this.chatInstances.clear();
|
||||
// 清除所有情绪聊天历史
|
||||
EmotionAIService.Instance.clearAllEmotionHistory();
|
||||
// 清除本地存储的所有历史
|
||||
ChatHistoryManager.Instance.clearAllHistory();
|
||||
console.log("Cleared all chat histories");
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
import { ChatAIService } from "./ChatAIService";
|
||||
import { EmotionAIService } from "./EmotionAIService";
|
||||
import { DialogManager } from "../manager/DialogManager";
|
||||
import { VideoEmotion } from "../../schema/schema";
|
||||
import ConfigManager from "../manager/ConfigManager";
|
||||
import { ErrorHandler, ErrorType } from "../utils/ErrorHandler";
|
||||
|
||||
/**
|
||||
* 聊天控制器接口 - 定义Panel和Controller之间的通信协议
|
||||
*/
|
||||
export interface IChatPanelCallback {
|
||||
/**
|
||||
* 消息发送开始回调
|
||||
* @param message 用户发送的消息
|
||||
*/
|
||||
onMessageSent(message: string): void;
|
||||
|
||||
/**
|
||||
* 接收到AI回复回调
|
||||
* @param response AI的回复内容
|
||||
*/
|
||||
onMessageReceived(response: string): void;
|
||||
|
||||
/**
|
||||
* 情绪状态更新回调
|
||||
* @param emotion 更新后的情绪状态
|
||||
*/
|
||||
onEmotionUpdated(emotion: VideoEmotion): void;
|
||||
|
||||
/**
|
||||
* 对话更新回调
|
||||
*/
|
||||
onDialogUpdated(): void;
|
||||
|
||||
/**
|
||||
* 错误处理回调
|
||||
* @param error 错误信息
|
||||
*/
|
||||
onError(error: Error): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 聊天控制器类
|
||||
*
|
||||
* 负责处理聊天相关的所有业务逻辑,包括:
|
||||
* - 角色数据管理
|
||||
* - 消息发送和接收
|
||||
* - 情绪状态管理
|
||||
* - 与AI服务的交互
|
||||
* - 对话历史管理
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const controller = new ChatController();
|
||||
* controller.initialize(10001, panelCallback);
|
||||
* const response = await controller.sendMessage("Hello");
|
||||
* ```
|
||||
*/
|
||||
export class ChatController {
|
||||
private roleId: number | null = null;
|
||||
private callback: IChatPanelCallback | null = null;
|
||||
private dialogManager: DialogManager | null = null;
|
||||
|
||||
/**
|
||||
* 初始化聊天控制器
|
||||
* @param roleId 角色ID
|
||||
* @param callback 回调接口实现
|
||||
*/
|
||||
public initialize(roleId: number, callback: IChatPanelCallback): void {
|
||||
this.roleId = roleId;
|
||||
this.callback = callback;
|
||||
this.dialogManager = DialogManager.getInstance();
|
||||
|
||||
// 设置当前聊天的角色ID
|
||||
if (roleId && roleId > 0) {
|
||||
ChatAIService.Instance.setCurrentRole(roleId);
|
||||
console.log(`ChatController initialized with role ${roleId}`);
|
||||
} else {
|
||||
const error = new Error(`Invalid roleId: ${roleId}`);
|
||||
this.handleError(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息给AI并处理回复
|
||||
* @param message 用户消息内容
|
||||
* @returns Promise<string | null> AI的回复,失败时返回null
|
||||
*/
|
||||
public async sendMessage(message: string): Promise<string | null> {
|
||||
if (!this.validateSendMessage(message)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// 通知界面消息发送开始
|
||||
this.callback?.onMessageSent(message);
|
||||
|
||||
// 更新对话显示 - 用户消息
|
||||
this.dialogManager?.updateDialog(true, message, true);
|
||||
this.callback?.onDialogUpdated();
|
||||
|
||||
console.log(`Sending message to role ${this.roleId}: ${message}`);
|
||||
|
||||
// 发送消息给AI服务
|
||||
const response = await ChatAIService.Instance.sendMessage(this.roleId!, message);
|
||||
|
||||
if (response) {
|
||||
// 更新对话显示 - AI回复
|
||||
this.dialogManager?.updateDialog(false, response);
|
||||
this.callback?.onDialogUpdated();
|
||||
|
||||
// 通知界面收到回复
|
||||
this.callback?.onMessageReceived(response);
|
||||
|
||||
// 获取更新后的情绪状态
|
||||
try {
|
||||
const currentEmotion = EmotionAIService.Instance.getCurrentEmotion(this.roleId!);
|
||||
console.log(`Current emotion for role ${this.roleId}: ${VideoEmotion[currentEmotion]}`);
|
||||
|
||||
// 通知界面情绪更新
|
||||
this.callback?.onEmotionUpdated(currentEmotion);
|
||||
} catch (emotionError) {
|
||||
console.warn("Failed to get current emotion:", emotionError);
|
||||
// 情绪获取失败不影响聊天功能
|
||||
}
|
||||
|
||||
console.log(`Response received from role ${this.roleId}: ${response}`);
|
||||
return response;
|
||||
} else {
|
||||
const error = new Error("AI返回了空响应");
|
||||
this.handleError(error);
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
ErrorHandler.Instance.handleApiError(error, "ChatController.sendMessage", {
|
||||
roleId: this.roleId,
|
||||
message: message.substring(0, 100) + "..."
|
||||
});
|
||||
this.handleError(error as Error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前角色的情绪状态
|
||||
* @returns VideoEmotion 当前情绪状态
|
||||
*/
|
||||
public getCurrentEmotion(): VideoEmotion {
|
||||
if (!this.roleId) {
|
||||
return VideoEmotion.calm_down;
|
||||
}
|
||||
return EmotionAIService.Instance.getCurrentEmotion(this.roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前角色数据
|
||||
* @returns 角色数据对象,失败时返回null
|
||||
*/
|
||||
public getRoleData(): any {
|
||||
if (!this.roleId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const roleData = ConfigManager.tables.TbGirls.get(this.roleId);
|
||||
const roleDetail = ConfigManager.tables.TbGirlsDetail.get(this.roleId);
|
||||
|
||||
return {
|
||||
basic: roleData,
|
||||
detail: roleDetail
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`Failed to get role data for ${this.roleId}:`, error);
|
||||
this.handleError(error as Error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除当前角色的聊天历史
|
||||
*/
|
||||
public clearChatHistory(): void {
|
||||
if (!this.roleId) {
|
||||
console.warn("Cannot clear history: roleId is null");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ChatAIService.Instance.clearChatHistory(this.roleId);
|
||||
console.log(`Chat history cleared for role ${this.roleId}`);
|
||||
} catch (error) {
|
||||
console.error("Failed to clear chat history:", error);
|
||||
this.handleError(error as Error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前角色ID
|
||||
* @returns 当前角色ID
|
||||
*/
|
||||
public getCurrentRoleId(): number | null {
|
||||
return this.roleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁控制器,清理资源
|
||||
*/
|
||||
public destroy(): void {
|
||||
this.roleId = null;
|
||||
this.callback = null;
|
||||
this.dialogManager = null;
|
||||
console.log("ChatController destroyed");
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证发送消息的参数
|
||||
* @param message 消息内容
|
||||
* @returns 验证是否通过
|
||||
*/
|
||||
private validateSendMessage(message: string): boolean {
|
||||
if (!this.roleId || this.roleId <= 0) {
|
||||
const error = new Error("角色ID无效");
|
||||
this.handleError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!message || message.trim() === "") {
|
||||
const error = new Error("消息内容不能为空");
|
||||
this.handleError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.callback) {
|
||||
const error = new Error("回调接口未设置");
|
||||
this.handleError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一错误处理
|
||||
* @param error 错误对象
|
||||
*/
|
||||
private handleError(error: Error): void {
|
||||
console.error("ChatController error:", error);
|
||||
this.callback?.onError(error);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "458edd93-5ff2-4c11-a573-f8985c48cc15",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -0,0 +1,418 @@
|
||||
// 首先加载 polyfills 以确保兼容性
|
||||
import "../utils/polyfills";
|
||||
import { GoogleGenAI } from "@google/genai";
|
||||
import { RoleConfigLoader } from "./RoleConfigLoader";
|
||||
import { ChatHistoryManager } from "../manager/ChatHistoryManager";
|
||||
import { ApiConfig } from "./ApiConfigLoader";
|
||||
import { ErrorHandler, ErrorType } from "../utils/ErrorHandler";
|
||||
import { VideoEmotion } from "../../schema/schema";
|
||||
import ConfigManager from "../manager/ConfigManager";
|
||||
import LanguageUtils, { LanguageType } from "../../Main/Common/LanguageUtils";
|
||||
import Utils from "../../Main/Common/Utils";
|
||||
import { InnerMsgCode } from "../../Main/Config/InnerMsgCode";
|
||||
|
||||
/**
|
||||
* AI情绪分析服务类
|
||||
*
|
||||
* 基于Google Gemini API实现的情绪分析系统,支持:
|
||||
* - 基于聊天历史的情绪状态分析
|
||||
* - 多角色独立的情绪聊天实例管理
|
||||
* - 返回标准的VideoEmotion枚举值
|
||||
* - 自动初始化历史情绪分析
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const emotionService = EmotionAIService.Instance;
|
||||
* const emotion = await emotionService.analyzeEmotionalState(10001);
|
||||
* console.log(VideoEmotion[emotion]); // "calm_down"
|
||||
* ```
|
||||
*
|
||||
* @author AI Chat System
|
||||
* @version 1.0.0
|
||||
*/
|
||||
export class EmotionAIService {
|
||||
private static _instance: EmotionAIService;
|
||||
private emotionAI: GoogleGenAI;
|
||||
private emotionChatInstances: Map<number, any> = new Map();
|
||||
private currentEmotions: Map<number, VideoEmotion> = new Map();
|
||||
|
||||
private constructor() {
|
||||
const emotionConfig = ApiConfig.Instance.getEmotionAIConfig();
|
||||
|
||||
try {
|
||||
this.emotionAI = new GoogleGenAI({ apiKey: emotionConfig.apiKey });
|
||||
} catch (error) {
|
||||
ErrorHandler.Instance.handleError(
|
||||
error as Error,
|
||||
ErrorType.API_ERROR,
|
||||
{ config: { ...emotionConfig, apiKey: "***" } }, // 隐藏API密钥
|
||||
true
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取EmotionAIService的单例实例
|
||||
*
|
||||
* @returns {EmotionAIService} 情绪分析服务实例
|
||||
* @static
|
||||
*/
|
||||
public static get Instance(): EmotionAIService {
|
||||
if (!this._instance) {
|
||||
this._instance = new EmotionAIService();
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建或获取指定角色的情绪聊天实例
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
private createOrGetEmotionChat(roleId: number): any {
|
||||
if (!this.emotionChatInstances.has(roleId)) {
|
||||
const systemInstruction = RoleConfigLoader.getEmotionInstruction(roleId);
|
||||
const config = ApiConfig.Instance.getEmotionAIConfig();
|
||||
|
||||
const chat = this.emotionAI.chats.create({
|
||||
model: config.model,
|
||||
config: {
|
||||
temperature: config.temperature,
|
||||
systemInstruction: systemInstruction,
|
||||
},
|
||||
});
|
||||
|
||||
this.emotionChatInstances.set(roleId, chat);
|
||||
console.log(`Created new emotion chat instance for role ${roleId}`);
|
||||
|
||||
// 异步分析历史情绪状态
|
||||
this.initializeEmotionAnalysis(roleId);
|
||||
}
|
||||
return this.emotionChatInstances.get(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化情绪分析(检查是否有历史记录并进行分析)
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
private async initializeEmotionAnalysis(roleId: number): Promise<void> {
|
||||
try {
|
||||
// 检查是否有聊天历史
|
||||
const messageCount = ChatHistoryManager.Instance.getMessageCount(roleId);
|
||||
|
||||
let emotionalState: VideoEmotion;
|
||||
|
||||
if (messageCount > 0) {
|
||||
console.log(
|
||||
`Analyzing emotional state for role ${roleId} based on ${messageCount} messages`
|
||||
);
|
||||
|
||||
// 分析历史情绪状态
|
||||
emotionalState = await this.analyzeEmotionalState(roleId);
|
||||
|
||||
console.log(
|
||||
`Initial emotional state for role ${roleId}: ${VideoEmotion[emotionalState]}`
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
`No history found for role ${roleId}, using default emotion: calm_down`
|
||||
);
|
||||
emotionalState = VideoEmotion.calm_down;
|
||||
}
|
||||
|
||||
// 发送情绪初始化完成事件
|
||||
Utils.sendInnerMsg(InnerMsgCode.Chat_EmotionInitialized, {
|
||||
roleId: roleId,
|
||||
emotion: emotionalState
|
||||
});
|
||||
|
||||
console.log(`Emotion initialization completed for role ${roleId}: ${VideoEmotion[emotionalState]}`);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Failed to initialize emotion analysis for role ${roleId}:`,
|
||||
error
|
||||
);
|
||||
|
||||
// 即使发生错误,也发送默认情绪状态
|
||||
Utils.sendInnerMsg(InnerMsgCode.Chat_EmotionInitialized, {
|
||||
roleId: roleId,
|
||||
emotion: VideoEmotion.calm_down
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化聊天历史用于情绪分析
|
||||
* @param messages 聊天消息数组
|
||||
* @returns 格式化后的分析提示
|
||||
*/
|
||||
private formatHistoryForEmotionAnalysis(messages: any[]): string {
|
||||
if (messages.length === 0) {
|
||||
return "没有聊天历史,请返回默认情绪状态:calm_down";
|
||||
}
|
||||
|
||||
let conversationText =
|
||||
"请分析以下对话的情绪状态,返回对应的VideoEmotion枚举值:\n\n";
|
||||
|
||||
messages.forEach((message, index) => {
|
||||
const speaker = message.role === "user" ? "用户" : "AI";
|
||||
const text = message.parts[0]?.text || "";
|
||||
conversationText += `${speaker}: ${text}\n`;
|
||||
});
|
||||
|
||||
conversationText +=
|
||||
"\n请返回以下枚举值之一:calm_down, arousal, desire, passion, orgasm";
|
||||
|
||||
return conversationText;
|
||||
}
|
||||
|
||||
/**
|
||||
* 向指定角色的情绪AI发送消息并获取分析回复,返回VideoEmotion枚举值
|
||||
* @param roleId 角色ID
|
||||
* @param message 用户发送的消息内容
|
||||
* @returns Promise<VideoEmotion> 情绪AI的分析结果,如果发生错误返回默认值calm_down
|
||||
*/
|
||||
public async sendEmotionMessage(
|
||||
roleId: number,
|
||||
message: string
|
||||
): Promise<VideoEmotion> {
|
||||
// 输入验证
|
||||
if (!roleId || roleId <= 0) {
|
||||
ErrorHandler.Instance.handleValidationError(
|
||||
"roleId",
|
||||
"角色ID必须是正整数",
|
||||
roleId
|
||||
);
|
||||
return VideoEmotion.calm_down;
|
||||
}
|
||||
|
||||
if (!message || message.trim() === "") {
|
||||
ErrorHandler.Instance.handleValidationError(
|
||||
"message",
|
||||
"消息内容不能为空",
|
||||
message
|
||||
);
|
||||
return VideoEmotion.calm_down;
|
||||
}
|
||||
|
||||
try {
|
||||
const emotionChat = this.createOrGetEmotionChat(roleId);
|
||||
const response = await emotionChat.sendMessage({
|
||||
message: message.trim(),
|
||||
});
|
||||
|
||||
if (response && response.text) {
|
||||
console.log(`Emotion analysis from role ${roleId}:`, response.text);
|
||||
return this.parseEmotionResponse(response.text);
|
||||
} else {
|
||||
const warningMsg = `情绪AI返回了空响应 (角色ID: ${roleId})`;
|
||||
ErrorHandler.Instance.handleError(
|
||||
new Error(warningMsg),
|
||||
ErrorType.API_ERROR,
|
||||
{ roleId, message, response },
|
||||
true
|
||||
);
|
||||
return VideoEmotion.calm_down;
|
||||
}
|
||||
} catch (error) {
|
||||
ErrorHandler.Instance.handleApiError(error, "sendEmotionMessage", {
|
||||
roleId,
|
||||
message: message.substring(0, 100) + "...",
|
||||
});
|
||||
return VideoEmotion.calm_down;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分析指定角色的情绪状态(基于最近10条聊天记录)
|
||||
* @param roleId 角色ID
|
||||
* @returns Promise<VideoEmotion> 情绪分析结果
|
||||
*/
|
||||
public async analyzeEmotionalState(roleId: number): Promise<VideoEmotion> {
|
||||
try {
|
||||
// 获取最近10条消息
|
||||
const recentMessages = ChatHistoryManager.Instance.getRecentMessages(
|
||||
roleId,
|
||||
10
|
||||
);
|
||||
|
||||
// 格式化历史记录用于分析
|
||||
const analysisPrompt =
|
||||
this.formatHistoryForEmotionAnalysis(recentMessages);
|
||||
|
||||
// 发送给情绪AI进行分析
|
||||
return await this.sendEmotionMessage(roleId, analysisPrompt);
|
||||
} catch (error) {
|
||||
ErrorHandler.Instance.handleError(
|
||||
error as Error,
|
||||
ErrorType.API_ERROR,
|
||||
{ roleId },
|
||||
false
|
||||
);
|
||||
return VideoEmotion.calm_down;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析情绪AI返回的文本为VideoEmotion枚举值
|
||||
* @param responseText AI返回的文本
|
||||
* @returns VideoEmotion枚举值
|
||||
*/
|
||||
private parseEmotionResponse(responseText: string): VideoEmotion {
|
||||
const text = responseText.toLowerCase().trim();
|
||||
|
||||
if (text.includes("arousal")) {
|
||||
return VideoEmotion.arousal;
|
||||
} else if (text.includes("desire")) {
|
||||
return VideoEmotion.desire;
|
||||
} else if (text.includes("passion")) {
|
||||
return VideoEmotion.passion;
|
||||
} else if (text.includes("orgasm")) {
|
||||
return VideoEmotion.orgasm;
|
||||
} else {
|
||||
return VideoEmotion.calm_down; // 默认值
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保指定角色的情绪聊天实例已创建
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
public ensureEmotionChatExists(roleId: number): void {
|
||||
this.createOrGetEmotionChat(roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除指定角色的情绪聊天历史
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
public clearEmotionHistory(roleId: number): void {
|
||||
if (this.emotionChatInstances.has(roleId)) {
|
||||
this.emotionChatInstances.delete(roleId);
|
||||
}
|
||||
console.log(`Cleared emotion chat history for role ${roleId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有情绪聊天历史
|
||||
*/
|
||||
public clearAllEmotionHistory(): void {
|
||||
this.emotionChatInstances.clear();
|
||||
console.log("Cleared all emotion chat histories");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前活跃的情绪聊天实例数量
|
||||
*/
|
||||
public getActiveEmotionChatCount(): number {
|
||||
return this.emotionChatInstances.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定角色的当前情绪状态
|
||||
* @param roleId 角色ID
|
||||
* @returns VideoEmotion 当前情绪状态
|
||||
*/
|
||||
public getCurrentEmotion(roleId: number): VideoEmotion {
|
||||
return this.currentEmotions.get(roleId) || VideoEmotion.calm_down;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置指定角色的情绪状态
|
||||
* @param roleId 角色ID
|
||||
* @param emotion 情绪状态
|
||||
*/
|
||||
private setCurrentEmotion(roleId: number, emotion: VideoEmotion): void {
|
||||
this.currentEmotions.set(roleId, emotion);
|
||||
console.log(`Updated emotion for role ${roleId}: ${VideoEmotion[emotion]}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色的英文名
|
||||
* @param roleId 角色ID
|
||||
* @returns 角色英文名,如果未找到返回"AI"
|
||||
*/
|
||||
private getRoleEnglishName(roleId: number): string {
|
||||
try {
|
||||
if (ConfigManager.tables && ConfigManager.tables.TbGirls) {
|
||||
const girlData = ConfigManager.tables.TbGirls.get(roleId);
|
||||
if (girlData && girlData.nameKey) {
|
||||
return (
|
||||
LanguageUtils.getTextByLanguage(
|
||||
girlData.nameKey,
|
||||
LanguageType.EN
|
||||
) || "AI"
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`Failed to get role name for ${roleId}:`, error);
|
||||
}
|
||||
return "AI";
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据聊天对话更新情绪状态
|
||||
* @param roleId 角色ID
|
||||
* @param userMessage 用户消息
|
||||
* @param aiResponse AI回复
|
||||
* @returns Promise<VideoEmotion> 更新后的情绪状态
|
||||
*/
|
||||
public async updateEmotionFromChat(
|
||||
roleId: number,
|
||||
userMessage: string,
|
||||
aiResponse: string
|
||||
): Promise<VideoEmotion> {
|
||||
try {
|
||||
// 构建情绪分析提示,包含当前情绪上下文
|
||||
const currentEmotion = this.getCurrentEmotion(roleId);
|
||||
const analysisPrompt = this.formatChatForEmotionAnalysis(
|
||||
roleId,
|
||||
userMessage,
|
||||
aiResponse,
|
||||
currentEmotion
|
||||
);
|
||||
|
||||
// 发送给情绪AI进行分析
|
||||
const newEmotion = await this.sendEmotionMessage(roleId, analysisPrompt);
|
||||
|
||||
// 更新并保存情绪状态
|
||||
this.setCurrentEmotion(roleId, newEmotion);
|
||||
|
||||
return newEmotion;
|
||||
} catch (error) {
|
||||
ErrorHandler.Instance.handleError(
|
||||
error as Error,
|
||||
ErrorType.API_ERROR,
|
||||
{ roleId, userMessage: userMessage.substring(0, 50) },
|
||||
false
|
||||
);
|
||||
return this.getCurrentEmotion(roleId); // 返回当前情绪状态
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化聊天对话用于情绪分析
|
||||
* @param roleId 角色ID
|
||||
* @param userMessage 用户消息
|
||||
* @param aiResponse AI回复
|
||||
* @param currentEmotion 当前情绪状态
|
||||
* @returns 格式化后的分析提示
|
||||
*/
|
||||
private formatChatForEmotionAnalysis(
|
||||
roleId: number,
|
||||
userMessage: string,
|
||||
aiResponse: string,
|
||||
currentEmotion: VideoEmotion
|
||||
): string {
|
||||
const roleName = this.getRoleEnglishName(roleId);
|
||||
|
||||
let analysisText = `当前情绪状态: ${VideoEmotion[currentEmotion]}\n\n`;
|
||||
analysisText += `请分析以下最新对话的情绪变化,返回对应的VideoEmotion枚举值:\n\n`;
|
||||
analysisText += `用户: ${userMessage}\n`;
|
||||
analysisText += `${roleName}: ${aiResponse}\n\n`;
|
||||
analysisText += `请基于对话内容和当前情绪状态,返回以下枚举值之一:calm_down, arousal, desire, passion, orgasm`;
|
||||
|
||||
return analysisText;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "624f6a81-539f-4347-aef1-d7c98c226a68",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -13,10 +13,26 @@ export class RoleConfigLoader {
|
||||
*/
|
||||
public static getRoleInstruction(roleId: number): string {
|
||||
const AiCharacter = ConfigManager.tables.TbAiCharacters.get(roleId);
|
||||
const globalPrompt = ConfigManager.tables.TbGlobalConfig.girlBasePrompt;
|
||||
const prompt =
|
||||
globalPrompt +
|
||||
"\n" +
|
||||
AiCharacter.basePrompt +
|
||||
"\n" +
|
||||
AiCharacter.additionPrompt;
|
||||
return prompt;
|
||||
}
|
||||
|
||||
return AiCharacter
|
||||
? AiCharacter.systemInstruction
|
||||
: ConfigManager.tables.TbAiCharacters.get(10001).systemInstruction;
|
||||
/**
|
||||
* 根据角色ID获取对应的情绪机器人prompt
|
||||
* @param roleId 角色ID
|
||||
* @returns System Instruction字符串,如果未找到则返回默认Role_1
|
||||
*/
|
||||
public static getEmotionInstruction(roleId: number): string {
|
||||
const AiCharacter = ConfigManager.tables.TbAiCharacters.get(roleId);
|
||||
const globalPrompt = ConfigManager.tables.TbGlobalConfig.EmotionRating;
|
||||
const prompt = globalPrompt + "\n" + AiCharacter.basePrompt;
|
||||
return prompt;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user