zhizhi/persona-studio/backend/brain/memory-manager.js

137 lines
3.2 KiB
JavaScript

/**
* persona-studio · 记忆读写管理
* 管理每个体验者的独立记忆空间 brain/memory/{EXP-XXX}/
*/
const fs = require('fs');
const path = require('path');
const BRAIN_DIR = path.join(__dirname, '..', '..', 'brain');
const MEMORY_DIR = path.join(BRAIN_DIR, 'memory');
/**
* 确保体验者目录存在
*/
function ensureDevDir(devId) {
const dir = path.join(MEMORY_DIR, devId);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
return dir;
}
/**
* 加载体验者的对话记忆
*/
function loadMemory(devId) {
const dir = ensureDevDir(devId);
const file = path.join(dir, 'memory.json');
try {
return JSON.parse(fs.readFileSync(file, 'utf-8'));
} catch {
const initial = {
dev_id: devId,
conversations: [],
last_topic: null,
preferences: {},
updated_at: null
};
fs.writeFileSync(file, JSON.stringify(initial, null, 2), 'utf-8');
return initial;
}
}
/**
* 追加对话记录
*/
function appendConversation(devId, messages) {
const memory = loadMemory(devId);
memory.conversations = memory.conversations.concat(messages);
// 保留最近 200 条对话
if (memory.conversations.length > 200) {
memory.conversations = memory.conversations.slice(-200);
}
memory.updated_at = new Date().toISOString();
saveMemory(devId, memory);
}
/**
* 更新最后话题
*/
function updateLastTopic(devId, topic) {
const memory = loadMemory(devId);
// 取消息的前 30 个字符作为话题摘要
memory.last_topic = topic.length > 30 ? topic.substring(0, 30) + '…' : topic;
memory.updated_at = new Date().toISOString();
saveMemory(devId, memory);
}
/**
* 保存记忆
*/
function saveMemory(devId, memory) {
const dir = ensureDevDir(devId);
const file = path.join(dir, 'memory.json');
fs.writeFileSync(file, JSON.stringify(memory, null, 2), 'utf-8');
}
/**
* 加载体验者的项目记录
*/
function loadProjects(devId) {
const dir = ensureDevDir(devId);
const file = path.join(dir, 'projects.json');
try {
return JSON.parse(fs.readFileSync(file, 'utf-8'));
} catch {
const initial = { dev_id: devId, projects: [], updated_at: null };
fs.writeFileSync(file, JSON.stringify(initial, null, 2), 'utf-8');
return initial;
}
}
/**
* 添加项目记录
*/
function addProject(devId, project) {
const data = loadProjects(devId);
data.projects.push(project);
data.updated_at = new Date().toISOString();
const dir = ensureDevDir(devId);
const file = path.join(dir, 'projects.json');
fs.writeFileSync(file, JSON.stringify(data, null, 2), 'utf-8');
}
/**
* 加载/更新体验者画像
*/
function loadProfile(devId) {
const dir = ensureDevDir(devId);
const file = path.join(dir, 'profile.json');
try {
return JSON.parse(fs.readFileSync(file, 'utf-8'));
} catch {
const initial = {
dev_id: devId,
tech_level: null,
communication_style: null,
aesthetic_preference: null,
growth_records: [],
updated_at: null
};
fs.writeFileSync(file, JSON.stringify(initial, null, 2), 'utf-8');
return initial;
}
}
module.exports = {
loadMemory,
saveMemory,
appendConversation,
updateLastTopic,
loadProjects,
addProject,
loadProfile
};