Files
Civita/dist/ai/gemini.js
2025-10-20 16:30:50 +02:00

63 lines
2.8 KiB
JavaScript

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