fix chatmodel

This commit is contained in:
2025-09-10 16:43:46 +08:00
parent e4ee688dc8
commit 07bd9923fc
8 changed files with 244 additions and 503 deletions
+122 -304
View File
@@ -1,22 +1,18 @@
import { VideoEmotion, purchase } from "../../schema/schema";
import { Dialog } from "./DialogData";
import { ConfigManager } from "../manager/ConfigManager";
import { DataId, DataManager } from "./DataManager";
import { GirlData } from "./GirlData";
/**
* 单个角色的聊天数据结构
*/
export interface RoleChatData {
roleId: number;
roleData: any;
roleDetail: any;
categoryId: string;
girlId: number;
dialogs: Dialog[];
currentEmotion: VideoEmotion;
commercialVideos: purchase.CommercialVideo[];
nameKey: string;
lastActiveTime: Date;
isInitialized: boolean;
chatCount: number;
maxChatCount: number;
}
/**
@@ -36,93 +32,99 @@ export class ChatModel {
private rolesData: Map<number, RoleChatData> = new Map();
// 当前活跃的角色ID
private currentRoleId: number | null = null;
private currentGirlId: number | null = null;
// 最大缓存角色数量(内存管理)
private maxCachedRoles: number = 10;
/**
* 初始化或切换到指定角色
* @param roleId 角色ID
* @param girlId 角色ID
* @returns 是否成功
*/
public initializeRole(roleId: number): boolean {
if (roleId <= 0) {
public initializeRole(categoryId: string, girlId: number): boolean {
if (girlId <= 0) {
console.error("ChatModel: Invalid roleId provided");
return false;
}
// 如果角色数据已存在,直接切换
if (this.rolesData.has(roleId)) {
this.currentRoleId = roleId;
this.updateLastActiveTime(roleId);
console.log(`ChatModel: Switched to existing role ${roleId}`);
if (this.rolesData.has(girlId)) {
this.currentGirlId = girlId;
this.updateLastActiveTime(girlId);
console.log(`ChatModel: Switched to existing role ${girlId}`);
return true;
}
// 创建新的角色数据
const newRoleData = this.createRoleData(roleId);
const newRoleData = this.createRoleData(categoryId, girlId);
if (newRoleData) {
// 内存管理:如果超过最大缓存数量,清理最久未使用的角色
this.manageMemory();
this.rolesData.set(roleId, newRoleData);
this.currentRoleId = roleId;
console.log(`ChatModel: Initialized new role ${roleId}`);
this.rolesData.set(girlId, newRoleData);
this.currentGirlId = girlId;
console.log(`ChatModel: Initialized new role ${girlId}`);
return true;
}
return false;
}
/**
* 检查是否有指定角色的数据
* @param roleId 角色ID
*/
public hasRoleData(roleId: number): boolean {
return this.rolesData.has(roleId);
}
/**
* 切换到指定角色(不存在则初始化)
* @param roleId 角色ID
* @returns 是否成功
*/
public switchToRole(roleId: number): boolean {
return this.initializeRole(roleId);
public switchToRole(categoryId: string, roleId: number): boolean {
return this.initializeRole(categoryId, roleId);
}
/**
* 创建新的角色数据
* @param roleId 角色ID
* @param girlId 角色ID
* @returns 角色数据对象
*/
private createRoleData(roleId: number): RoleChatData | null {
private createRoleData(
categoryId: string,
girlId: number
): RoleChatData | null {
try {
// 加载角色基础数据
const roleData = ConfigManager.tables.TbGirls.get(roleId);
const roleDetail = ConfigManager.tables.TbGirlsDetail.get(roleId);
if (!roleData) {
console.error(`ChatModel: Role data not found for roleId ${roleId}`);
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
const chatTotalCount = girlData.getChatTotalCount(categoryId, girlId);
//const roleData = ConfigManager.tables.TbGirls.get(roleId);
//const roleDetail = ConfigManager.tables.TbGirlsDetail.get(roleId);
if (!girlData) {
console.error(`ChatModel: Role data not found for roleId ${girlId}`);
return null;
}
//Todo:未接入后端数据 待补充
// 创建角色数据对象
const newRoleData: RoleChatData = {
roleId: roleId,
roleData: roleData,
roleDetail: roleDetail,
nameKey: roleData.nameKey || "",
girlId: girlId,
categoryId: categoryId,
dialogs: [],
currentEmotion: VideoEmotion.calm_down,
commercialVideos:
roleDetail && roleDetail.commercialVideos
? roleDetail.commercialVideos
: [],
lastActiveTime: new Date(),
isInitialized: true,
chatCount: 0,
maxChatCount: this.getDefaultChatLimit(),
};
return newRoleData;
} catch (error) {
console.error(
`ChatModel: Failed to create role data for ${roleId}:`,
`ChatModel: Failed to create role data for ${girlId}:`,
error
);
return null;
@@ -169,67 +171,17 @@ export class ChatModel {
* 获取当前活跃角色ID
*/
public getCurrentRoleId(): number | null {
return this.currentRoleId;
return this.currentGirlId;
}
/**
* 获取当前角色数据
*/
public getCurrentRoleData(): RoleChatData | null {
if (!this.currentRoleId) {
if (!this.currentGirlId) {
return null;
}
return this.rolesData.get(this.currentRoleId) || null;
}
/**
* 获取指定角色数据
* @param roleId 角色ID,不传则使用当前角色
*/
public getRoleData(roleId?: number): any {
const targetRoleId = roleId || this.currentRoleId;
if (!targetRoleId) {
return null;
}
const roleData = this.rolesData.get(targetRoleId);
return roleData ? roleData.roleData : null;
}
/**
* 获取指定角色详细数据
* @param roleId 角色ID,不传则使用当前角色
*/
public getRoleDetail(roleId?: number): any {
const targetRoleId = roleId || this.currentRoleId;
if (!targetRoleId) {
return null;
}
const roleData = this.rolesData.get(targetRoleId);
return roleData ? roleData.roleDetail : null;
}
/**
* 获取角色名称键值
* @param roleId 角色ID,不传则使用当前角色
*/
public getNameKey(roleId?: number): string {
const targetRoleId = roleId || this.currentRoleId;
if (!targetRoleId) {
return "";
}
const roleData = this.rolesData.get(targetRoleId);
return roleData ? roleData.nameKey : "";
}
/**
* 检查是否有指定角色的数据
* @param roleId 角色ID
*/
public hasRoleData(roleId: number): boolean {
return this.rolesData.has(roleId);
return this.rolesData.get(this.currentGirlId) || null;
}
/**
@@ -237,7 +189,7 @@ export class ChatModel {
* @param roleId 角色ID,不传则使用当前角色
*/
public getDialogs(roleId?: number): Dialog[] {
const targetRoleId = roleId || this.currentRoleId;
const targetRoleId = roleId || this.currentGirlId;
if (!targetRoleId) {
return [];
}
@@ -253,7 +205,7 @@ export class ChatModel {
* @param roleId 角色ID,不传则使用当前角色
*/
public addDialog(isPlayer: boolean, content: string, roleId?: number): void {
const targetRoleId = roleId || this.currentRoleId;
const targetRoleId = roleId || this.currentGirlId;
if (!targetRoleId) {
console.warn("ChatModel: Cannot add dialog - no active role");
return;
@@ -287,7 +239,7 @@ export class ChatModel {
* @param roleId 角色ID,不传则使用当前角色
*/
public clearDialogs(roleId?: number): void {
const targetRoleId = roleId || this.currentRoleId;
const targetRoleId = roleId || this.currentGirlId;
if (!targetRoleId) {
console.warn("ChatModel: Cannot clear dialogs - no active role");
return;
@@ -306,7 +258,7 @@ export class ChatModel {
* @param roleId 角色ID,不传则使用当前角色
*/
public getCurrentEmotion(roleId?: number): VideoEmotion {
const targetRoleId = roleId || this.currentRoleId;
const targetRoleId = roleId || this.currentGirlId;
if (!targetRoleId) {
return VideoEmotion.calm_down;
}
@@ -321,7 +273,7 @@ export class ChatModel {
* @param roleId 角色ID,不传则使用当前角色
*/
public setCurrentEmotion(emotion: VideoEmotion, roleId?: number): void {
const targetRoleId = roleId || this.currentRoleId;
const targetRoleId = roleId || this.currentGirlId;
if (!targetRoleId) {
console.warn("ChatModel: Cannot set emotion - no active role");
return;
@@ -343,31 +295,14 @@ export class ChatModel {
}
}
/**
* 获取商业视频配置
* @param roleId 角色ID,不传则使用当前角色
*/
public getCommercialVideos(roleId?: number): purchase.CommercialVideo[] {
const targetRoleId = roleId || this.currentRoleId;
if (!targetRoleId) {
return [];
}
const roleData = this.rolesData.get(targetRoleId);
return roleData ? [...roleData.commercialVideos] : []; // 返回副本避免外部修改
}
/**
* 根据情绪获取对应的视频(如果有多个视频,随机返回一个)
* @param emotion 目标情绪
* @param roleId 角色ID,不传则使用当前角色
* @returns 匹配的视频对象,没找到则返回null
* @returns 匹配的视频url
*/
public getVideoByEmotion(
emotion: VideoEmotion,
roleId?: number
): purchase.CommercialVideo | null {
const targetRoleId = roleId || this.currentRoleId;
public getVideoByEmotion(emotion: VideoEmotion, roleId?: number): string {
const targetRoleId = roleId || this.currentGirlId;
if (!targetRoleId) {
return null;
}
@@ -376,46 +311,81 @@ export class ChatModel {
if (!roleData) {
return null;
}
// 获取所有匹配该情绪的视频
const matchingVideos = roleData.commercialVideos.filter(
(video) => video.emotion === emotion
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
const allvideoIDs = girlData.getAllDisplayGrilVideoId(
roleData.categoryId,
roleData.girlId
);
let targetIds: number[] = [];
for (let i = 0; i < allvideoIDs.length; i++) {
const element = allvideoIDs[i];
if (
girlData.getGrilVideoEmotion(
roleData.categoryId,
roleData.girlId,
element
) === emotion
) {
targetIds.push(allvideoIDs[i]);
}
}
if (matchingVideos.length === 0) {
if (targetIds.length === 0) {
return null;
}
// 如果只有一个匹配的视频,直接返回
if (matchingVideos.length === 1) {
return matchingVideos[0];
if (targetIds.length === 1) {
return girlData.getGrilVideoPath(
roleData.categoryId,
roleData.girlId,
targetIds[0]
);
}
// 如果有多个匹配的视频,随机选择一个
const randomIndex = Math.floor(Math.random() * matchingVideos.length);
return matchingVideos[randomIndex];
const randomIndex = Math.floor(Math.random() * targetIds.length);
return girlData.getGrilVideoPath(
roleData.categoryId,
roleData.girlId,
targetIds[randomIndex]
);
}
/**
* 获取默认视频(第一个视频或平静状态视频)
* @param roleId 角色ID,不传则使用当前角色
* @param girlId 角色ID,不传则使用当前角色
*/
public getDefaultVideo(roleId?: number): purchase.CommercialVideo | null {
const targetRoleId = roleId || this.currentRoleId;
if (!targetRoleId) {
return null;
}
public getDefaultVideo(): string {
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
const roleData = this.rolesData.get(this.currentGirlId);
const roleData = this.rolesData.get(targetRoleId);
if (!roleData || roleData.commercialVideos.length === 0) {
return null;
}
// 优先返回平静状态的视频
const calmVideo = roleData.commercialVideos.find(
(video) => video.emotion === VideoEmotion.calm_down
const allvideoIDs = girlData.getAllDisplayGrilVideoId(
roleData.categoryId,
roleData.girlId
);
return calmVideo || roleData.commercialVideos[0];
let targetId: number = -1;
for (let i = 0; i < allvideoIDs.length; i++) {
const element = allvideoIDs[i];
if (
girlData.getGrilVideoEmotion(
roleData.categoryId,
roleData.girlId,
element
) === VideoEmotion.calm_down
) {
targetId = element;
}
}
if (targetId == -1) {
return null;
} else {
return girlData.getGrilVideoPath(
roleData.categoryId,
roleData.girlId,
targetId
);
}
}
/**
@@ -423,7 +393,7 @@ export class ChatModel {
* @param roleId 角色ID,不传则使用当前角色
*/
public getDialogCount(roleId?: number): number {
const targetRoleId = roleId || this.currentRoleId;
const targetRoleId = roleId || this.currentGirlId;
if (!targetRoleId) {
return 0;
}
@@ -437,7 +407,7 @@ export class ChatModel {
* @param roleId 角色ID,不传则使用当前角色
*/
public getLastDialog(roleId?: number): Dialog | null {
const targetRoleId = roleId || this.currentRoleId;
const targetRoleId = roleId || this.currentGirlId;
if (!targetRoleId) {
return null;
}
@@ -450,26 +420,12 @@ export class ChatModel {
return roleData.dialogs[roleData.dialogs.length - 1];
}
/**
* 检查当前角色是否已初始化
* @param roleId 角色ID,不传则使用当前角色
*/
public isInitialized(roleId?: number): boolean {
const targetRoleId = roleId || this.currentRoleId;
if (!targetRoleId) {
return false;
}
const roleData = this.rolesData.get(targetRoleId);
return roleData ? roleData.isInitialized : false;
}
/**
* 重置所有数据到初始状态
*/
public reset(): void {
this.rolesData.clear();
this.currentRoleId = null;
this.currentGirlId = null;
console.log(
"ChatModel: All role data cleared and model reset to initial state"
);
@@ -484,8 +440,8 @@ export class ChatModel {
this.rolesData.delete(roleId);
// 如果删除的是当前角色,清空当前角色ID
if (this.currentRoleId === roleId) {
this.currentRoleId = null;
if (this.currentGirlId === roleId) {
this.currentGirlId = null;
}
console.log(`ChatModel: Role ${roleId} data cleared`);
@@ -497,7 +453,7 @@ export class ChatModel {
* @param roleId 角色ID,不传则使用当前角色
*/
public validate(roleId?: number): boolean {
const targetRoleId = roleId || this.currentRoleId;
const targetRoleId = roleId || this.currentGirlId;
if (!targetRoleId) {
console.error("ChatModel: No active role");
return false;
@@ -508,17 +464,6 @@ export class ChatModel {
console.error(`ChatModel: Role data not found for ${targetRoleId}`);
return false;
}
if (!roleData.isInitialized) {
console.error(`ChatModel: Role ${targetRoleId} not initialized`);
return false;
}
if (!roleData.roleData) {
console.error(`ChatModel: Role ${targetRoleId} data not loaded`);
return false;
}
return true;
}
@@ -565,45 +510,6 @@ export class ChatModel {
}
}
/**
* 获取模型状态摘要(用于调试)
* @param roleId 角色ID,不传则返回当前角色摘要
*/
public getStateSummary(roleId?: number): any {
const targetRoleId = roleId || this.currentRoleId;
if (!targetRoleId) {
return {
currentRoleId: null,
totalCachedRoles: this.rolesData.size,
maxCachedRoles: this.maxCachedRoles,
allRoleIds: this.getAllRoleIds(),
};
}
const roleData = this.rolesData.get(targetRoleId);
if (!roleData) {
return {
roleId: targetRoleId,
error: "Role data not found",
};
}
return {
roleId: targetRoleId,
nameKey: roleData.nameKey,
dialogCount: roleData.dialogs.length,
currentEmotion: VideoEmotion[roleData.currentEmotion],
videoCount: roleData.commercialVideos.length,
lastActiveTime: roleData.lastActiveTime,
isInitialized: roleData.isInitialized,
chatCount: roleData.chatCount,
maxChatCount: roleData.maxChatCount,
remainingChats: roleData.maxChatCount - roleData.chatCount,
totalCachedRoles: this.rolesData.size,
};
}
/**
* 获取默认聊天次数限制
* TODO: 以后从后端获取,目前默认返回10
@@ -613,105 +519,17 @@ export class ChatModel {
return 1;
}
/**
* 获取角色的聊天次数限制
* @param roleId 角色ID,不传则使用当前角色
* @returns 聊天次数限制,未找到角色则返回0
*/
public getRoleChatLimit(roleId?: number): number {
const targetRoleId = roleId || this.currentRoleId;
if (!targetRoleId) {
return 0;
}
const roleData = this.rolesData.get(targetRoleId);
return roleData ? roleData.maxChatCount : 0;
}
/**
* 获取角色已使用的聊天次数
* @param roleId 角色ID,不传则使用当前角色
* @returns 已使用的聊天次数
*/
public getRoleChatCount(roleId?: number): number {
const targetRoleId = roleId || this.currentRoleId;
if (!targetRoleId) {
return 0;
}
const roleData = this.rolesData.get(targetRoleId);
return roleData ? roleData.chatCount : 0;
}
/**
* 获取角色剩余聊天次数
* @param roleId 角色ID,不传则使用当前角色
* @returns 剩余聊天次数
*/
public getRemainingChatCount(roleId?: number): number {
const targetRoleId = roleId || this.currentRoleId;
if (!targetRoleId) {
return 0;
}
const roleData = this.rolesData.get(targetRoleId);
return roleData
? Math.max(0, roleData.maxChatCount - roleData.chatCount)
: 0;
}
/**
* 检查角色是否还有剩余聊天次数
* @param roleId 角色ID,不传则使用当前角色
* @returns 是否可以继续聊天
*/
public canChat(roleId?: number): boolean {
return this.getRemainingChatCount(roleId) > 0;
}
const girlData = DataManager.I.getDataById<GirlData>(DataId.Girl);
const roleData = this.rolesData.get(this.currentGirlId);
/**
* 增加角色聊天次数计数
* @param roleId 角色ID,不传则使用当前角色
*/
public incrementChatCount(roleId?: number): void {
const targetRoleId = roleId || this.currentRoleId;
if (!targetRoleId) {
console.warn("ChatModel: Cannot increment chat count - no active role");
return;
}
const roleData = this.rolesData.get(targetRoleId);
if (!roleData) {
console.warn(`ChatModel: Role data not found for roleId ${targetRoleId}`);
return;
}
roleData.chatCount++;
this.updateLastActiveTime(targetRoleId);
console.log(
`ChatModel: Chat count incremented for role ${targetRoleId}, current: ${roleData.chatCount}/${roleData.maxChatCount}`
return (
girlData.getChatRemainCount(roleData.categoryId, roleData.girlId) > 0
);
}
/**
* 重置角色聊天次数
* @param roleId 角色ID,不传则使用当前角色
*/
public resetChatCount(roleId?: number): void {
const targetRoleId = roleId || this.currentRoleId;
if (!targetRoleId) {
console.warn("ChatModel: Cannot reset chat count - no active role");
return;
}
const roleData = this.rolesData.get(targetRoleId);
if (!roleData) {
console.warn(`ChatModel: Role data not found for roleId ${targetRoleId}`);
return;
}
roleData.chatCount = 0;
this.updateLastActiveTime(targetRoleId);
console.log(`ChatModel: Chat count reset for role ${targetRoleId}`);
}
}