// ========================================== // MEEZAN - ميزان Memory System // Persistent memory across all conversations // ========================================== import * as fs from 'fs'; import * as path from 'path'; import { UserProfile, ConversationHistory, Message, Language } from '../types'; interface Database { users: Record; conversations: Record; version: string; } export class MemoryManager { private dbPath: string; private db: Database; constructor(dbPath: string = './data/memory.json') { this.dbPath = dbPath; this.db = this.load(); } private load(): Database { const dir = path.dirname(this.dbPath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } if (!fs.existsSync(this.dbPath)) { const initial: Database = { users: {}, conversations: {}, version: '1.0.0' }; this.save(initial); return initial; } try { const content = fs.readFileSync(this.dbPath, 'utf-8'); return JSON.parse(content); } catch { console.error('Memory database corrupted, starting fresh'); return { users: {}, conversations: {}, version: '1.0.0' }; } } private save(data?: Database): void { const toSave = data || this.db; fs.writeFileSync(this.dbPath, JSON.stringify(toSave, null, 2), 'utf-8'); } // ========================================== // User Profile Management // ========================================== getUser(userId: string): UserProfile | null { return this.db.users[userId] || null; } createUser(userId: string, language: Language = 'ar'): UserProfile { const profile: UserProfile = { id: userId, language, city: process.env.DEFAULT_CITY || 'Kuwait City', country: process.env.DEFAULT_COUNTRY || 'Kuwait', latitude: parseFloat(process.env.DEFAULT_LATITUDE || '29.3759'), longitude: parseFloat(process.env.DEFAULT_LONGITUDE || '47.9774'), createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }; this.db.users[userId] = profile; this.save(); return profile; } updateUser(userId: string, updates: Partial): UserProfile { const existing = this.getUser(userId) || this.createUser(userId); const updated = { ...existing, ...updates, updatedAt: new Date().toISOString() }; this.db.users[userId] = updated; this.save(); return updated; } getOrCreateUser(userId: string, language?: Language): UserProfile { return this.getUser(userId) || this.createUser(userId, language); } // ========================================== // Conversation History // ========================================== getHistory(userId: string): Message[] { const conv = this.db.conversations[userId]; if (!conv) return []; // Return last 20 messages for context window management return conv.messages.slice(-20); } addMessage(userId: string, message: Message): void { if (!this.db.conversations[userId]) { this.db.conversations[userId] = { userId, messages: [] }; } this.db.conversations[userId].messages.push(message); // Keep only last 100 messages per user to prevent DB bloat if (this.db.conversations[userId].messages.length > 100) { this.db.conversations[userId].messages = this.db.conversations[userId].messages.slice(-100); } this.save(); } clearHistory(userId: string): void { if (this.db.conversations[userId]) { this.db.conversations[userId].messages = []; this.save(); } } // ========================================== // User Context Helpers // ========================================== setUserCity(userId: string, city: string, country: string, lat: number, lng: number): void { this.updateUser(userId, { city, country, latitude: lat, longitude: lng }); } setUserName(userId: string, name: string): void { this.updateUser(userId, { name }); } setUserLanguage(userId: string, language: Language): void { this.updateUser(userId, { language }); } setUserMadhab(userId: string, madhab: UserProfile['madhab']): void { this.updateUser(userId, { madhab }); } // ========================================== // Stats // ========================================== getTotalUsers(): number { return Object.keys(this.db.users).length; } getTotalMessages(): number { return Object.values(this.db.conversations) .reduce((sum, conv) => sum + conv.messages.length, 0); } } export const memory = new MemoryManager(process.env.DB_PATH || './data/memory.json');