File size: 5,140 Bytes
e7c953d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Conversation memory handler for DubAPI bot
class MemoryHandler {
    constructor(options = {}) {
        // Maximum number of messages to remember per user
        this.maxMessagesPerUser = options.maxMessagesPerUser || 50;
        // Maximum age of messages to keep (in milliseconds)
        this.maxMemoryAge = options.maxMemoryAge || 30 * 60 * 1000; // Default: 30 minutes
        // Memory storage: Map of username -> array of message objects
        this.memories = new Map();
        
        console.log(`Memory handler initialized (max ${this.maxMessagesPerUser} messages per user, ${this.maxMemoryAge/60000} minutes retention)`);
        
        // Set up periodic cleanup
        this.startCleanupInterval();
    }
    
    /**
     * Add a message to a user's conversation history
     * @param {string} username - The username of the person speaking
     * @param {string} message - The message content
     * @param {boolean} isBot - Whether this message was from the bot
     */
    addMessage(username, message, isBot = false) {
        // Normalize username to lowercase for consistent lookups
        const normalizedUsername = username.toLowerCase();
        
        // Get or create user's memory array
        if (!this.memories.has(normalizedUsername)) {
            this.memories.set(normalizedUsername, []);
        }
        
        const userMemory = this.memories.get(normalizedUsername);
        
        // Add new message with timestamp
        userMemory.push({
            timestamp: Date.now(),
            message: message,
            isBot: isBot
        });
        
        // Trim to max size if needed
        if (userMemory.length > this.maxMessagesPerUser) {
            userMemory.shift(); // Remove oldest message
        }
    }
    
    /**
     * Get conversation history for a user
     * @param {string} username - The username to get history for
     * @param {number} limit - Maximum number of messages to retrieve (defaults to all)
     * @returns {Array} - Array of conversation messages
     */
    getConversationHistory(username, limit = null) {
        const normalizedUsername = username.toLowerCase();
        
        if (!this.memories.has(normalizedUsername)) {
            return [];
        }
        
        const userMemory = this.memories.get(normalizedUsername);
        const result = limit ? userMemory.slice(-limit) : userMemory;
        
        return result;
    }
    
    /**
     * Format conversation history for use in AI prompt
     * @param {string} username - The username to get history for
     * @param {number} limit - Maximum number of messages to include
     * @returns {string} - Formatted conversation history
     */
    getFormattedHistory(username, limit = 5) {
        const history = this.getConversationHistory(username, limit);
        
        if (history.length === 0) {
            return "";
        }
        
        let formatted = "Previous conversation:\n";
        
        history.forEach(item => {
            const speaker = item.isBot ? "Bot" : username;
            formatted += `${speaker}: ${item.message}\n`;
        });
        
        return formatted;
    }
    
    /**
     * Remove old messages from memory that exceed the age limit
     */
    cleanupOldMessages() {
        const now = Date.now();
        const cutoffTime = now - this.maxMemoryAge;
        
        // Check each user's memory
        for (const [username, messages] of this.memories.entries()) {
            // Filter out old messages
            const freshMessages = messages.filter(msg => msg.timestamp >= cutoffTime);
            
            if (freshMessages.length === 0) {
                // Remove empty memory arrays
                this.memories.delete(username);
            } else if (freshMessages.length < messages.length) {
                // Update with only fresh messages
                this.memories.set(username, freshMessages);
            }
        }
    }
    
    /**
     * Start automatic cleanup interval
     */
    startCleanupInterval() {
        // Run cleanup every 5 minutes
        setInterval(() => {
            this.cleanupOldMessages();
        }, 5 * 60 * 1000);
    }
    
    /**
     * Get stats about the memory system
     * @returns {Object} - Stats about memory usage
     */
    getStats() {
        return {
            userCount: this.memories.size,
            totalMessages: Array.from(this.memories.values())
                .reduce((total, messages) => total + messages.length, 0),
            oldestMessage: this.getOldestMessageTime()
        };
    }
    
    /**
     * Get the timestamp of the oldest message in memory
     * @returns {number|null} - Timestamp or null if no messages
     */
    getOldestMessageTime() {
        let oldest = null;
        
        for (const messages of this.memories.values()) {
            for (const msg of messages) {
                if (oldest === null || msg.timestamp < oldest) {
                    oldest = msg.timestamp;
                }
            }
        }
        
        return oldest;
    }
}

module.exports = MemoryHandler;