// Filename: frontend/js/pages/chat/SessionManager.js import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'; const LOCAL_STORAGE_KEY = 'gemini_chat_state'; /** * Manages the state and persistence of chat sessions. * This class handles loading from/saving to localStorage, * and all operations like creating, switching, and deleting sessions. */ export class SessionManager { constructor() { this.state = null; } /** * Initializes the manager by loading state from localStorage or creating a default state. */ init() { this._loadState(); } // --- Public API for state access --- getSessions() { return this.state.sessions; } getCurrentSessionId() { return this.state.currentSessionId; } getCurrentSession() { return this.state.sessions.find(s => s.id === this.state.currentSessionId); } // --- Public API for state mutation --- /** * Creates a new, empty session and sets it as the current one. */ createSession() { const newSessionId = nanoid(); const newSession = { id: newSessionId, name: '新会话', systemPrompt: '', messages: [], modelConfig: { model: 'gemini-2.0-flash-lite' }, params: { temperature: 0.7 } }; this.state.sessions.unshift(newSession); this.state.currentSessionId = newSessionId; this._saveState(); } /** * Switches the current session to the one with the given ID. * @param {string} sessionId The ID of the session to switch to. */ switchSession(sessionId) { if (this.state.currentSessionId === sessionId) return; this.state.currentSessionId = sessionId; this._saveState(); } /** * Deletes a session by its ID. * @param {string} sessionId The ID of the session to delete. */ deleteSession(sessionId) { this.state.sessions = this.state.sessions.filter(s => s.id !== sessionId); if (this.state.currentSessionId === sessionId) { this.state.currentSessionId = this.state.sessions[0]?.id || null; if (!this.state.currentSessionId) { this._createInitialState(); // Create a new one if all are deleted } } this._saveState(); } /** * [NEW] Clears all messages from the currently active session. */ clearCurrentSession() { const currentSession = this.getCurrentSession(); if (currentSession) { currentSession.messages = []; this._saveState(); } } /** * Adds a message to the current session and updates the session name if it's the first message. * @param {object} message The message object to add. * @returns {object} The session that was updated. */ addMessage(message) { const currentSession = this.getCurrentSession(); if (currentSession) { if (currentSession.messages.length === 0 && message.role === 'user') { currentSession.name = message.content.substring(0, 30); } currentSession.messages.push(message); this._saveState(); return currentSession; } return null; } deleteMessage(messageId) { const currentSession = this.getCurrentSession(); if (currentSession) { const messageIndex = currentSession.messages.findIndex(m => m.id === messageId); if (messageIndex > -1) { currentSession.messages.splice(messageIndex, 1); this._saveState(); console.log(`Message ${messageId} deleted.`); } } } truncateMessagesAfter(messageId) { const currentSession = this.getCurrentSession(); if (currentSession) { const messageIndex = currentSession.messages.findIndex(m => m.id === messageId); // Ensure the message exists and it's not already the last one if (messageIndex > -1 && messageIndex < currentSession.messages.length - 1) { currentSession.messages.splice(messageIndex + 1); this._saveState(); console.log(`Truncated messages after ${messageId}.`); } } } // --- Private persistence methods --- _saveState() { try { localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(this.state)); } catch (error) { console.error("Failed to save session state:", error); } } _loadState() { try { const stateString = localStorage.getItem(LOCAL_STORAGE_KEY); if (stateString) { this.state = JSON.parse(stateString); } else { this._createInitialState(); } } catch (error) { console.error("Failed to load session state, creating initial state:", error); this._createInitialState(); } } _createInitialState() { const initialSessionId = nanoid(); this.state = { sessions: [{ id: initialSessionId, name: '新会话', systemPrompt: '', messages: [], modelConfig: { model: 'gemini-2.0-flash-lite' }, params: { temperature: 0.7 } }], currentSessionId: initialSessionId, settings: {} }; this._saveState(); } }