guanghulab/conversation-manager.js

140 lines
3.9 KiB
JavaScript
Raw Normal View History

// 对话上下文管理器 · conversation-manager.js · v1.0
// HoloLake · M-DINGTALK Phase 8
// DEV-004 之之 × 秋秋
// 功能:对话历史存储 · 上下文窗口管理 · 多用户隔离
//
var fs = require('fs');
var path = require('path');
// 对话存储目录
var CONVERSATION_DIR = path.join(__dirname, 'conversations');
if (!fs.existsSync(CONVERSATION_DIR)) {
fs.mkdirSync(CONVERSATION_DIR, { recursive: true });
}
// 配置
var MAX_HISTORY = 20; // 每个用户最多保留20轮对话
var MAX_CONTEXT_TOKENS = 3000; // 上下文窗口大小(估算字符数)
var EXPIRE_HOURS = 24; // 对话24小时后过期
// ===== 获取用户对话文件路径 =====
function getConversationPath(userId) {
var safeId = (userId || 'anonymous').replace(/[^a-zA-Z0-9_-]/g, '_');
return path.join(CONVERSATION_DIR, safeId + '.json');
}
// ===== 加载对话历史 =====
function loadHistory(userId) {
var filePath = getConversationPath(userId);
try {
if (!fs.existsSync(filePath)) return [];
var data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
// 过滤过期消息
var now = Date.now();
var expireMs = EXPIRE_HOURS * 60 * 60 * 1000;
var valid = (data.messages || []).filter(function(msg) {
return (now - msg.timestamp) < expireMs;
});
return valid;
} catch (err) {
console.error('[ConvMgr] 加载历史失败:', err.message);
return [];
}
}
// ===== 保存对话历史 =====
function saveHistory(userId, messages) {
var filePath = getConversationPath(userId);
try {
// 只保留最近N轮
var trimmed = messages.slice(-MAX_HISTORY * 2);
fs.writeFileSync(filePath, JSON.stringify({
userid: userId,
updatedAt: new Date().toISOString(),
messages: trimmed
}, null, 2), 'utf8');
} catch (err) {
console.error('[ConvMgr] 保存历史失败:', err.message);
}
}
// ====== 添加消息 ======
function addMessage(userId, role, content) {
var messages = loadHistory(userId);
messages.push({
role: role,
content: content,
timestamp: Date.now()
});
saveHistory(userId, messages);
return messages;
}
// ====== 构建上下文窗口给LLM用 ======
function buildContext(userId, currentMessage) {
var history = loadHistory(userId);
var contextMessages = [];
var totalChars = 0;
// 从最新的开始往回取,直到超过上下文窗口
for (var i = history.length - 1; i >= 0; i--) {
var msg = history[i];
var msgChars = (msg.content || '').length;
if (totalChars + msgChars > MAX_CONTEXT_TOKENS) break;
contextMessages.unshift({
role: msg.role,
content: msg.content
});
totalChars += msgChars;
}
// 添加当前消息
contextMessages.push({
role: 'user',
content: currentMessage
});
return contextMessages;
}
// ===== 清除用户对话历史 =====
function clearHistory(userId) {
var filePath = getConversationPath(userId);
try {
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath);
}
return true;
} catch (err) {
return false;
}
}
// ===== 获取活跃对话统计 =====
function getStats() {
try {
var files = fs.readdirSync(CONVERSATION_DIR).filter(function(f) {
return f.endsWith('.json');
});
return {
activeUsers: files.length,
conversationDir: CONVERSATION_DIR
};
} catch (err) {
return {
activeUsers: 0,
conversationDir: CONVERSATION_DIR
};
}
}
module.exports = {
loadHistory: loadHistory,
saveHistory: saveHistory,
addMessage: addMessage,
buildContext: buildContext,
clearHistory: clearHistory,
getStats: getStats
};