167 lines
6.3 KiB
JavaScript
167 lines
6.3 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const DB_PATH = path.join(__dirname, '../Data/ai-memory.json');
|
|
|
|
function load() {
|
|
try {
|
|
const raw = fs.readFileSync(DB_PATH, 'utf8');
|
|
return JSON.parse(raw);
|
|
} catch (e) {
|
|
return {
|
|
ai_conversations: [],
|
|
ai_summaries: [],
|
|
ai_facts: [],
|
|
ai_knowledge: [],
|
|
ai_sessions: [],
|
|
};
|
|
}
|
|
}
|
|
|
|
function save(state) {
|
|
try {
|
|
fs.mkdirSync(path.dirname(DB_PATH), { recursive: true });
|
|
fs.writeFileSync(DB_PATH, JSON.stringify(state, null, 2), 'utf8');
|
|
} catch (e) {
|
|
console.error('Failed to persist ai-memory:', e);
|
|
}
|
|
}
|
|
|
|
const state = load();
|
|
|
|
function nextId(arr) {
|
|
return arr.length === 0 ? 1 : Math.max(...arr.map(a => a.id || 0)) + 1;
|
|
}
|
|
|
|
module.exports = {
|
|
saveUserFact({ guildId, userId, factType, factKey, factValue }) {
|
|
const existing = state.ai_facts.find(f => f.guild_id === (guildId || null) && f.user_id === (userId || null) && f.fact_type === factType && f.fact_key === factKey);
|
|
if (existing) {
|
|
existing.fact_value = factValue;
|
|
existing.updated_at = Date.now();
|
|
save(state);
|
|
return;
|
|
}
|
|
|
|
const id = nextId(state.ai_facts);
|
|
state.ai_facts.push({ id, guild_id: guildId || null, channel_id: null, user_id: userId || null, fact_type: factType, fact_key: factKey, fact_value: factValue, created_at: Date.now(), updated_at: Date.now() });
|
|
save(state);
|
|
},
|
|
|
|
getUserFacts(guildId, userId) {
|
|
return state.ai_facts.filter(f => f.guild_id === (guildId || null) && f.user_id === (userId || null)).sort((a,b) => b.updated_at - a.updated_at);
|
|
},
|
|
|
|
getUserFactsByScope({ guildId = null, userId = null, scope = "guild" }) {
|
|
if (!userId) return [];
|
|
if (scope === "global") {
|
|
return state.ai_facts.filter(f => f.user_id === (userId || null)).sort((a,b) => b.updated_at - a.updated_at);
|
|
}
|
|
|
|
return state.ai_facts.filter(f => f.guild_id === (guildId || null) && f.user_id === (userId || null)).sort((a,b) => b.updated_at - a.updated_at);
|
|
},
|
|
|
|
addMessage({ guildId, channelId, userId, role, content }) {
|
|
const id = nextId(state.ai_conversations);
|
|
state.ai_conversations.push({ id, guild_id: guildId || null, channel_id: channelId || null, user_id: userId || null, role, content, created_at: Date.now() });
|
|
save(state);
|
|
},
|
|
|
|
getRecentMessages(channelId, limit = 15) {
|
|
const msgs = state.ai_conversations.filter(m => m.channel_id === channelId).sort((a,b) => b.created_at - a.created_at).slice(0, limit).reverse();
|
|
return msgs;
|
|
},
|
|
|
|
getRecentMessagesByScope({ guildId = null, channelId = null, limit = 15, scope = "guild" }) {
|
|
if (scope === "channel") {
|
|
return state.ai_conversations.filter(m => m.channel_id === (channelId || null)).sort((a,b) => b.created_at - a.created_at).slice(0, limit).reverse();
|
|
}
|
|
|
|
if (scope === "global") {
|
|
return state.ai_conversations.sort((a,b) => b.created_at - a.created_at).slice(0, limit).reverse();
|
|
}
|
|
|
|
return state.ai_conversations.filter(m => m.guild_id === (guildId || null)).sort((a,b) => b.created_at - a.created_at).slice(0, limit).reverse();
|
|
},
|
|
|
|
saveSummary({ guildId, channelId, summary }) {
|
|
const existing = state.ai_summaries.find(s => s.guild_id === (guildId || null) && s.channel_id === (channelId || null));
|
|
if (existing) {
|
|
existing.summary = summary;
|
|
existing.updated_at = Date.now();
|
|
save(state);
|
|
return;
|
|
}
|
|
const id = nextId(state.ai_summaries);
|
|
state.ai_summaries.push({ id, guild_id: guildId || null, channel_id: channelId || null, summary, created_at: Date.now(), updated_at: Date.now() });
|
|
save(state);
|
|
},
|
|
|
|
getLatestSummary(channelId) {
|
|
const arr = state.ai_summaries.filter(s => s.channel_id === channelId).sort((a,b) => b.updated_at - a.updated_at);
|
|
return arr.length ? arr[0] : null;
|
|
},
|
|
|
|
getLatestSummaryByScope({ guildId = null, channelId = null, scope = "guild" }) {
|
|
if (scope === "channel") {
|
|
const arr = state.ai_summaries.filter(s => s.channel_id === (channelId || null)).sort((a,b) => b.updated_at - a.updated_at);
|
|
return arr.length ? arr[0] : null;
|
|
}
|
|
if (scope === "global") {
|
|
const arr = state.ai_summaries.sort((a,b) => b.updated_at - a.updated_at);
|
|
return arr.length ? arr[0] : null;
|
|
}
|
|
|
|
const arr = state.ai_summaries.filter(s => s.guild_id === (guildId || null)).sort((a,b) => b.updated_at - a.updated_at);
|
|
return arr.length ? arr[0] : null;
|
|
},
|
|
|
|
saveFact({ guildId, channelId, factType, factKey, factValue }) {
|
|
const existing = state.ai_facts.find(f => f.guild_id === (guildId || null) && f.channel_id === (channelId || null) && f.fact_type === factType && f.fact_key === factKey);
|
|
if (existing) {
|
|
existing.fact_value = factValue;
|
|
existing.updated_at = Date.now();
|
|
save(state);
|
|
return;
|
|
}
|
|
const id = nextId(state.ai_facts);
|
|
state.ai_facts.push({ id, guild_id: guildId || null, channel_id: channelId || null, user_id: null, fact_type: factType, fact_key: factKey, fact_value: factValue, created_at: Date.now(), updated_at: Date.now() });
|
|
save(state);
|
|
},
|
|
|
|
getFacts(channelId) {
|
|
return state.ai_facts.filter(f => f.channel_id === channelId).sort((a,b) => b.updated_at - a.updated_at);
|
|
},
|
|
|
|
getFactsByScope({ guildId = null, channelId = null, scope = "guild" }) {
|
|
if (scope === "channel") {
|
|
return state.ai_facts.filter(f => f.channel_id === (channelId || null) && f.user_id == null).sort((a,b) => b.updated_at - a.updated_at);
|
|
}
|
|
if (scope === "global") {
|
|
return state.ai_facts.filter(f => f.user_id == null).sort((a,b) => b.updated_at - a.updated_at);
|
|
}
|
|
|
|
return state.ai_facts.filter(f => f.guild_id === (guildId || null) && f.user_id == null).sort((a,b) => b.updated_at - a.updated_at);
|
|
},
|
|
|
|
addKnowledge({ sourceType, sourceName, title, content }) {
|
|
const id = nextId(state.ai_knowledge);
|
|
state.ai_knowledge.push({ id, source_type: sourceType, source_name: sourceName, title, content, created_at: Date.now(), updated_at: Date.now() });
|
|
save(state);
|
|
},
|
|
|
|
getKnowledge(limit = 25) {
|
|
return state.ai_knowledge.sort((a,b) => b.updated_at - a.updated_at).slice(0, limit);
|
|
},
|
|
|
|
clearKnowledge() {
|
|
state.ai_knowledge = [];
|
|
save(state);
|
|
},
|
|
|
|
clearConversations(channelId) {
|
|
if (!channelId) return;
|
|
state.ai_conversations = state.ai_conversations.filter(c => c.channel_id !== channelId);
|
|
save(state);
|
|
},
|
|
}; |