import { GoogleGenerativeAI } from '@google/generative-ai'; import { env } from '../config/env.js'; import { withConn } from '../db/pool.js'; let client = null; export function getGemini() { if (!client) { client = new GoogleGenerativeAI(env.geminiApiKey); } return client; } export async function generateQOTD() { const model = getGemini().getGenerativeModel({ model: 'gemini-2.5-flash' }); const prompt = 'Generate a single, engaging, family-friendly “Question of the Day” suitable for a Discord community. Keep it under 25 words. No preface or explanation, only the question.'; const res = await model.generateContent(prompt); const text = res.response.text().trim(); return text.replace(/^"|"$/g, ''); } export async function chatAnswer(question) { const model = getGemini().getGenerativeModel({ model: 'gemini-2.5-flash' }); const res = await model.generateContent(`Answer concisely and helpfully for a Discord chat:\n${question}`); return res.response.text().trim(); } export async function loadUserMemory(guildId, userId) { const rows = await withConn((conn) => conn.query('SELECT messages, updated_at FROM user_ai_memory WHERE guild_id = ? AND user_id = ? LIMIT 1', [guildId, userId])); const raw = rows[0]?.messages; const updatedAt = rows[0]?.updated_at; if (!raw) return []; // Auto-reset if inactive for 3 days if (updatedAt && Date.now() - new Date(updatedAt).getTime() > 3 * 24 * 60 * 60 * 1000) { await withConn((conn) => conn.query('DELETE FROM user_ai_memory WHERE guild_id = ? AND user_id = ?', [guildId, userId])); return []; } try { return Array.isArray(raw) ? raw : JSON.parse(raw); } catch { return []; } } export async function saveUserMemory(guildId, userId, history) { const json = JSON.stringify(history.slice(-20)); await withConn((conn) => conn.query('INSERT INTO user_ai_memory (guild_id, user_id, messages) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE messages = VALUES(messages)', [guildId, userId, json])); } export async function chatAnswerWithMemory(guildId, userId, question) { const history = await loadUserMemory(guildId, userId); const model = getGemini().getGenerativeModel({ model: 'gemini-2.5-flash' }); const prompt = [ { role: 'user', content: 'You are a helpful Discord assistant. Be concise.' }, ...history, { role: 'user', content: question } ]; const res = await model.generateContent(prompt.map(m => `${m.role === 'user' ? 'User' : 'Assistant'}: ${m.content}`).join('\n')); const answer = res.response.text().trim(); const next = [ ...history, { role: 'user', content: question }, { role: 'assistant', content: answer } ]; await saveUserMemory(guildId, userId, next); return answer; }