From 3a953a7e41b07886489901d433c26be4ad65988b Mon Sep 17 00:00:00 2001 From: Sidney Date: Fri, 17 Jul 2026 22:28:33 -0300 Subject: [PATCH] feat: isola as configuracoes de IA em tabela especifica configuracoes_ia no PostgreSQL, removendo-as do JSON de school_data --- manager/services/database.js | 104 ++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/manager/services/database.js b/manager/services/database.js index 7362dcf..b79049d 100644 --- a/manager/services/database.js +++ b/manager/services/database.js @@ -22,6 +22,48 @@ pool.on('error', (err) => { console.error('[PostgreSQL] Erro inesperado no pool:', err); }); +// Inicializar a tabela configuracoes_ia se não existir +export async function verificarEInicializarTabelaIA() { + const client = await pool.connect(); + try { + await client.query(` + CREATE TABLE IF NOT EXISTS configuracoes_ia ( + id INT PRIMARY KEY DEFAULT 1, + active_provider VARCHAR(50) DEFAULT 'gemini', + gemini_key TEXT, + openai_key TEXT, + claude_key TEXT, + openrouter_key TEXT, + gemini_model VARCHAR(100) DEFAULT 'gemini-1.5-flash', + openai_model VARCHAR(100) DEFAULT 'gpt-4o-mini', + claude_model VARCHAR(100) DEFAULT 'claude-3-5-sonnet-20241022', + openrouter_model VARCHAR(100) DEFAULT 'google/gemini-2.5-flash', + active_image_provider VARCHAR(50) DEFAULT 'gemini', + openai_image_model VARCHAR(100) DEFAULT 'dall-e-3', + gemini_image_model VARCHAR(100) DEFAULT 'imagen-3.0-generate-002', + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + CONSTRAINT single_row CHECK (id = 1) + ) + `); + + await client.query(` + INSERT INTO configuracoes_ia (id) + VALUES (1) + ON CONFLICT (id) DO NOTHING + `); + } catch (err) { + console.error('[PostgreSQL] Erro ao inicializar configuracoes_ia:', err.message); + } finally { + client.release(); + } +} + +// Chamar inicialização +verificarEInicializarTabelaIA().catch(err => { + console.error('[PostgreSQL] Erro na inicialização da tabela de IA:', err); +}); + // ============================================================ // HELPER: Buscar school_data JSON blob (compatibilidade legada) // ============================================================ @@ -29,7 +71,32 @@ export async function getSchoolData() { const { rows } = await pool.query( 'SELECT data FROM school_data WHERE id = 1' ); - return rows[0]?.data || {}; + const data = rows[0]?.data || {}; + + try { + const aiRes = await pool.query('SELECT * FROM configuracoes_ia WHERE id = 1'); + if (aiRes.rows[0]) { + const dbConfig = aiRes.rows[0]; + data.aiConfig = { + activeProvider: dbConfig.active_provider, + geminiKey: dbConfig.gemini_key || '', + openaiKey: dbConfig.openai_key || '', + claudeKey: dbConfig.claude_key || '', + openrouterKey: dbConfig.openrouter_key || '', + geminiModel: dbConfig.gemini_model || 'gemini-1.5-flash', + openaiModel: dbConfig.openai_model || 'gpt-4o-mini', + claudeModel: dbConfig.claude_model || 'claude-3-5-sonnet-20241022', + openrouterModel: dbConfig.openrouter_model || 'google/gemini-2.5-flash', + activeImageProvider: dbConfig.active_image_provider || 'gemini', + openaiImageModel: dbConfig.openai_image_model || 'dall-e-3', + geminiImageModel: dbConfig.gemini_image_model || 'imagen-3.0-generate-002' + }; + } + } catch (err) { + console.warn('[Database] Erro ao mesclar configuracoes_ia no school_data:', err.message); + } + + return data; } /** @@ -126,6 +193,41 @@ export async function saveSchoolData(data) { // Aplicar fechamento de pauta automático antes de salvar const dataWithAbsences = await processAutoAbsences(data); + if (dataWithAbsences.aiConfig) { + const c = dataWithAbsences.aiConfig; + try { + await pool.query( + `INSERT INTO configuracoes_ia + (id, active_provider, gemini_key, openai_key, claude_key, openrouter_key, + gemini_model, openai_model, claude_model, openrouter_model, + active_image_provider, openai_image_model, gemini_image_model, updated_at) + VALUES (1, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, NOW()) + ON CONFLICT (id) DO UPDATE SET + active_provider = EXCLUDED.active_provider, + gemini_key = EXCLUDED.gemini_key, + openai_key = EXCLUDED.openai_key, + claude_key = EXCLUDED.claude_key, + openrouter_key = EXCLUDED.openrouter_key, + gemini_model = EXCLUDED.gemini_model, + openai_model = EXCLUDED.openai_model, + claude_model = EXCLUDED.claude_model, + openrouter_model = EXCLUDED.openrouter_model, + active_image_provider = EXCLUDED.active_image_provider, + openai_image_model = EXCLUDED.openai_image_model, + gemini_image_model = EXCLUDED.gemini_image_model, + updated_at = NOW()`, + [ + c.activeProvider, c.geminiKey || '', c.openaiKey || '', c.claudeKey || '', c.openrouterKey || '', + c.geminiModel, c.openaiModel, c.claudeModel, c.openrouterModel, + c.activeImageProvider, c.openaiImageModel, c.geminiImageModel + ] + ); + } catch (err) { + console.error('[Database] Erro ao salvar na tabela configuracoes_ia:', err.message); + } + delete dataWithAbsences.aiConfig; + } + await pool.query( `INSERT INTO school_data (id, data, updated_at) VALUES (1, $1, NOW())