Files
AIEC-new/AIEC-server/js/chat-manager.js

513 lines
16 KiB
JavaScript
Raw Permalink Normal View History

2025-10-17 09:31:28 +08:00
/**
* 对话管理器 - 负责管理聊天会话的保存加载和持久化
*/
class ChatManager {
constructor() {
this.currentChatId = null;
this.chats = new Map(); // 存储所有聊天会话
this.storageKey = 'yundage_chat_history';
this.currentUserKey = 'yundage_current_user';
this.initialized = false;
// 监听认证状态变化事件
window.addEventListener('authStatusChecked', () => {
if (!this.initialized) {
console.log('ChatManager 收到认证状态检查完成事件,开始初始化');
this.init();
this.initialized = true;
}
});
// 备用方案如果3秒内没有收到认证事件强制初始化
setTimeout(() => {
if (!this.initialized) {
console.log('ChatManager 超时初始化');
this.init();
this.initialized = true;
}
}, 3000);
}
/**
* 初始化
*/
init() {
this.loadFromStorage();
this.setupAutoSave();
}
/**
* 从本地存储加载聊天记录
*/
loadFromStorage() {
try {
// 清空当前聊天记录
this.chats.clear();
this.currentChatId = null;
const currentUser = this.getCurrentUser();
if (!currentUser) {
console.log('没有登录用户,跳过加载');
return;
}
const storageKey = `${this.storageKey}_${currentUser.id}`;
const currentChatKey = `${this.storageKey}_current_${currentUser.id}`;
console.log(`[ChatManager] 开始加载聊天记录...`);
console.log(`[ChatManager] 存储键: ${storageKey}`);
console.log(`[ChatManager] 当前聊天键: ${currentChatKey}`);
const savedChats = localStorage.getItem(storageKey);
const savedCurrentChatId = localStorage.getItem(currentChatKey);
console.log(`[ChatManager] localStorage中保存的当前聊天ID: ${savedCurrentChatId}`);
if (savedChats) {
const chatsData = JSON.parse(savedChats);
this.chats = new Map(chatsData.map(chat => [chat.id, chat]));
console.log(`[ChatManager] 成功加载了 ${this.chats.size} 个聊天会话`);
console.log(`[ChatManager] 聊天ID列表:`, Array.from(this.chats.keys()));
// 恢复当前聊天ID
if (savedCurrentChatId && this.chats.has(savedCurrentChatId)) {
this.currentChatId = savedCurrentChatId;
console.log(`[ChatManager] ✅ 成功恢复当前聊天: ${savedCurrentChatId}`);
} else if (savedCurrentChatId) {
console.log(`[ChatManager] ⚠️ 保存的聊天ID ${savedCurrentChatId} 不在聊天列表中`);
} else {
console.log(`[ChatManager] 没有保存的当前聊天ID`);
}
} else {
console.log(`[ChatManager] 未找到保存的聊天记录`);
}
console.log(`[ChatManager] 加载完成当前聊天ID: ${this.currentChatId}`);
} catch (error) {
console.error('[ChatManager] 加载聊天记录失败:', error);
}
}
/**
* 保存到本地存储
*/
saveToStorage() {
try {
const currentUser = this.getCurrentUser();
if (!currentUser) {
console.log('没有登录用户,跳过保存');
return;
}
const storageKey = `${this.storageKey}_${currentUser.id}`;
const chatsArray = Array.from(this.chats.values());
console.log(`正在保存 ${chatsArray.length} 个聊天到 localStorage键名: ${storageKey}`);
localStorage.setItem(storageKey, JSON.stringify(chatsArray));
console.log(`聊天记录已保存 (用户: ${currentUser.username}, ID: ${currentUser.id})`);
} catch (error) {
console.error('保存聊天记录失败:', error);
}
}
/**
* 获取当前用户
*/
getCurrentUser() {
const userStr = localStorage.getItem(this.currentUserKey);
return userStr ? JSON.parse(userStr) : null;
}
/**
* 设置自动保存
*/
setupAutoSave() {
// 每30秒自动保存一次
setInterval(() => {
if (this.currentChatId) {
this.saveToStorage();
}
}, 30000);
// 页面卸载时保存
window.addEventListener('beforeunload', () => {
this.saveToStorage();
});
}
/**
* 创建新的聊天会话
* @param {string} firstMessage - 第一条消息用于生成标题
* @returns {string} 聊天ID
*/
createChat(firstMessage = '') {
const chatId = `chat_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
const chat = {
id: chatId,
title: this.generateTitle(firstMessage),
messages: [],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
metadata: {
messageCount: 0,
lastActive: new Date().toISOString()
}
};
this.chats.set(chatId, chat);
this.currentChatId = chatId;
// 保存当前聊天ID
const currentUser = this.getCurrentUser();
if (currentUser) {
const currentChatKey = `${this.storageKey}_current_${currentUser.id}`;
localStorage.setItem(currentChatKey, chatId);
}
this.saveToStorage();
return chatId;
}
/**
* 生成聊天标题
* @param {string} firstMessage - 第一条消息
* @returns {string} 标题
*/
generateTitle(firstMessage) {
if (!firstMessage) return '新对话';
// 移除多余的空格和换行
const cleaned = firstMessage.trim().replace(/\s+/g, ' ');
// 如果消息太长截取前30个字符
if (cleaned.length > 30) {
return cleaned.substring(0, 30) + '...';
}
return cleaned || '新对话';
}
/**
* 添加消息到当前聊天
* @param {string} content - 消息内容
* @param {string} type - 消息类型 ('user' 'ai')
* @param {object} metadata - 额外的元数据
*/
addMessage(content, type, metadata = {}) {
if (!this.currentChatId) {
console.error('没有活动的聊天会话');
return;
}
const chat = this.chats.get(this.currentChatId);
if (!chat) {
console.error('聊天会话不存在');
return;
}
const message = {
id: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
content,
contentType: metadata.contentType || 'markdown', // 默认使用markdown
type,
timestamp: new Date().toISOString(),
status: type === 'user' ? 'sent' : 'complete',
metadata: {
deviceInfo: navigator.userAgent,
...metadata
}
};
chat.messages.push(message);
chat.updatedAt = new Date().toISOString();
chat.metadata.messageCount = chat.messages.length;
chat.metadata.lastActive = new Date().toISOString();
// 如果是第一条消息,更新标题
if (chat.messages.length === 1 && type === 'user') {
chat.title = this.generateTitle(content);
}
this.chats.set(this.currentChatId, chat);
// 触发消息添加事件
this.dispatchEvent('messageAdded', { chatId: this.currentChatId, message });
// 保存到本地存储
this.saveToStorage();
return message;
}
/**
* 获取聊天会话
* @param {string} chatId - 聊天ID
* @returns {object|null} 聊天会话
*/
getChat(chatId) {
return this.chats.get(chatId) || null;
}
/**
* 获取当前聊天会话
* @returns {object|null} 当前聊天会话
*/
getCurrentChat() {
return this.currentChatId ? this.getChat(this.currentChatId) : null;
}
/**
* 切换到指定聊天
* @param {string} chatId - 聊天ID
*/
switchToChat(chatId) {
if (this.chats.has(chatId)) {
this.currentChatId = chatId;
const chat = this.chats.get(chatId);
chat.metadata.lastActive = new Date().toISOString();
// 保存当前聊天ID
const currentUser = this.getCurrentUser();
if (currentUser) {
const currentChatKey = `${this.storageKey}_current_${currentUser.id}`;
localStorage.setItem(currentChatKey, chatId);
console.log(`保存当前聊天ID: ${chatId}`);
}
// 触发聊天切换事件
this.dispatchEvent('chatSwitched', { chatId, chat });
return true;
}
return false;
}
/**
* 删除聊天会话
* @param {string} chatId - 聊天ID
*/
deleteChat(chatId) {
if (this.chats.has(chatId)) {
this.chats.delete(chatId);
// 如果删除的是当前聊天清空当前聊天ID
if (this.currentChatId === chatId) {
this.currentChatId = null;
// 清除保存的当前聊天ID
const currentUser = this.getCurrentUser();
if (currentUser) {
const currentChatKey = `${this.storageKey}_current_${currentUser.id}`;
localStorage.removeItem(currentChatKey);
}
}
this.saveToStorage();
// 触发聊天删除事件
this.dispatchEvent('chatDeleted', { chatId });
return true;
}
return false;
}
/**
* 更新聊天标题
* @param {string} chatId - 聊天ID
* @param {string} newTitle - 新标题
*/
updateChatTitle(chatId, newTitle) {
const chat = this.chats.get(chatId);
if (chat) {
chat.title = newTitle;
chat.updatedAt = new Date().toISOString();
this.chats.set(chatId, chat);
this.saveToStorage();
// 触发标题更新事件
this.dispatchEvent('chatTitleUpdated', { chatId, title: newTitle });
return true;
}
return false;
}
/**
* 获取所有聊天列表
* @param {object} options - 选项
* @returns {array} 聊天列表
*/
getAllChats(options = {}) {
const { sortBy = 'updatedAt', order = 'desc', limit = null } = options;
let chatsArray = Array.from(this.chats.values());
// 排序
chatsArray.sort((a, b) => {
const aValue = a[sortBy];
const bValue = b[sortBy];
if (order === 'desc') {
return bValue > aValue ? 1 : -1;
} else {
return aValue > bValue ? 1 : -1;
}
});
// 限制数量
if (limit) {
chatsArray = chatsArray.slice(0, limit);
}
return chatsArray;
}
/**
* 搜索聊天记录
* @param {string} query - 搜索关键词
* @returns {array} 匹配的聊天列表
*/
searchChats(query) {
const lowerQuery = query.toLowerCase();
const results = [];
for (const chat of this.chats.values()) {
// 搜索标题
if (chat.title.toLowerCase().includes(lowerQuery)) {
results.push({
chat,
matchType: 'title'
});
continue;
}
// 搜索消息内容
const matchedMessages = chat.messages.filter(msg =>
msg.content.toLowerCase().includes(lowerQuery)
);
if (matchedMessages.length > 0) {
results.push({
chat,
matchType: 'content',
matchedMessages
});
}
}
return results;
}
/**
* 清空所有聊天记录
*/
clearAllChats() {
this.chats.clear();
this.currentChatId = null;
this.saveToStorage();
// 触发清空事件
this.dispatchEvent('allChatsCleared');
}
/**
* 导出聊天记录
* @param {string} chatId - 聊天ID如果不提供则导出所有
* @returns {string} JSON格式的聊天记录
*/
exportChats(chatId = null) {
if (chatId) {
const chat = this.chats.get(chatId);
return chat ? JSON.stringify(chat, null, 2) : null;
} else {
const allChats = Array.from(this.chats.values());
return JSON.stringify(allChats, null, 2);
}
}
/**
* 导入聊天记录
* @param {string} jsonData - JSON格式的聊天记录
*/
importChats(jsonData) {
try {
const data = JSON.parse(jsonData);
const chatsToImport = Array.isArray(data) ? data : [data];
for (const chat of chatsToImport) {
if (chat.id && chat.messages) {
this.chats.set(chat.id, chat);
}
}
this.saveToStorage();
// 触发导入事件
this.dispatchEvent('chatsImported', { count: chatsToImport.length });
return true;
} catch (error) {
console.error('导入聊天记录失败:', error);
return false;
}
}
/**
* 获取聊天统计信息
*/
getStatistics() {
const totalChats = this.chats.size;
let totalMessages = 0;
let userMessages = 0;
let aiMessages = 0;
for (const chat of this.chats.values()) {
totalMessages += chat.messages.length;
userMessages += chat.messages.filter(m => m.type === 'user').length;
aiMessages += chat.messages.filter(m => m.type === 'ai').length;
}
return {
totalChats,
totalMessages,
userMessages,
aiMessages,
averageMessagesPerChat: totalChats > 0 ? Math.round(totalMessages / totalChats) : 0
};
}
/**
* 触发自定义事件
* @param {string} eventName - 事件名称
* @param {object} detail - 事件详情
*/
dispatchEvent(eventName, detail = {}) {
const event = new CustomEvent(`chatManager:${eventName}`, { detail });
window.dispatchEvent(event);
}
/**
* 开始新的聊天会话
*/
startNewChat() {
this.currentChatId = null;
// 清除保存的当前聊天ID
const currentUser = this.getCurrentUser();
if (currentUser) {
const currentChatKey = `${this.storageKey}_current_${currentUser.id}`;
localStorage.removeItem(currentChatKey);
}
this.dispatchEvent('newChatStarted');
}
/**
* 用户登录后重新加载聊天记录
*/
reloadForUser() {
console.log('用户登录状态变化,重新加载聊天记录');
this.loadFromStorage();
this.dispatchEvent('userChanged');
}
}
// 创建全局实例
window.chatManager = new ChatManager();