Files
SupportBot/Structures/AIDatabase.js
T
2026-08-06 17:29:37 +01:00

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);
},
};