diff --git a/public/app.js b/public/app.js index b095a2c..f917ecd 100644 --- a/public/app.js +++ b/public/app.js @@ -107,13 +107,26 @@ const initApp = () => { const welcomeTitle = document.getElementById('welcomeTitle'); const welcomeAvatarImg = document.getElementById('welcomeAvatarImg'); const sidebarAvatarImg = document.getElementById('sidebarAvatarImg'); + const temperatureOptions = document.getElementById('temperatureOptions'); + const knowledgeList = document.getElementById('knowledgeList'); + const manualKnowledgeInput = document.getElementById('manualKnowledgeInput'); + const btnAddKnowledge = document.getElementById('btnAddKnowledge'); window.agentConfig = { agentName: "Kemily", kemilyAvatarUrl: "assets/kemily.png", - camilaAvatarUrl: "assets/camila_prof.png" + camilaAvatarUrl: "assets/camila_prof.png", + temperaturePreset: 'equilibrado' }; + window.temperaturePresets = { + tecnico: { value: 0.2, label: 'Técnico e Direto', description: 'Respostas curtas, objetivas, sem rodeios. Ideal para quando precisa só do essencial.' }, + equilibrado: { value: 0.6, label: 'Equilibrado', description: 'Bom para uso geral — nem muito curto, nem muito longo.' }, + detalhista: { value: 1.0, label: 'Detalhista e Falante', description: 'Respostas extensas, explicações completas, contextualização máxima. Ideal para estudo e revisão.' } + }; + + window.conhecimento = { facts: [], lastUpdated: null }; + // Carrega as configurações do servidor const loadAgentConfig = async () => { try { @@ -146,6 +159,125 @@ const initApp = () => { if (previewCamilaAvatar) { previewCamilaAvatar.src = window.agentConfig.camilaAvatarUrl; } + // Atualiza seleção de temperatura + renderTemperatureOptions(); + }; + + // Carregar presets de temperatura do servidor + const loadTemperaturePresets = async () => { + try { + const res = await fetch('/api/temperature-presets'); + if (res.ok) { + window.temperaturePresets = await res.json(); + renderTemperatureOptions(); + } + } catch (e) { + console.error('Erro ao carregar presets de temperatura:', e); + } + }; + + // Renderizar opções de temperatura + const renderTemperatureOptions = () => { + if (!temperatureOptions) return; + const preset = window.agentConfig.temperaturePreset || 'equilibrado'; + temperatureOptions.innerHTML = Object.entries(window.temperaturePresets).map(([key, t]) => ` + + `).join(''); + + // Event listeners para as opções + temperatureOptions.querySelectorAll('.temperature-option').forEach(opt => { + opt.addEventListener('click', () => { + temperatureOptions.querySelectorAll('.temperature-option').forEach(o => o.classList.remove('selected')); + opt.classList.add('selected'); + opt.querySelector('input').checked = true; + }); + }); + }; + + // Carregar conhecimento do servidor + const loadConhecimento = async () => { + try { + const res = await fetch('/api/conhecimento'); + if (res.ok) { + window.conhecimento = await res.json(); + renderKnowledgeList(); + } + } catch (e) { + console.error('Erro ao carregar conhecimento:', e); + } + }; + + // Renderizar lista de conhecimento + const renderKnowledgeList = () => { + if (!knowledgeList) return; + if (!window.conhecimento.facts || window.conhecimento.facts.length === 0) { + knowledgeList.innerHTML = '

Nenhum conhecimento aprendido ainda. A assistente aprende automaticamente quando você ensinar algo novo!

'; + return; + } + knowledgeList.innerHTML = window.conhecimento.facts.map(f => ` +
+
+ ${f.source} +

${f.content}

+ ${new Date(f.addedAt).toLocaleDateString('pt-BR')} +
+ +
+ `).join(''); + }; + + // Deletar item de conhecimento (função global para onclick) + window.deleteKnowledge = async (id) => { + try { + const res = await fetch(`/api/conhecimento/${id}`, { method: 'DELETE' }); + if (res.ok) { + window.conhecimento.facts = window.conhecimento.facts.filter(f => f.id !== id); + renderKnowledgeList(); + } + } catch (e) { + console.error('Erro ao deletar conhecimento:', e); + } + }; + + // Adicionar conhecimento manualmente + if (btnAddKnowledge) { + btnAddKnowledge.addEventListener('click', async () => { + const input = manualKnowledgeInput?.value.trim(); + if (!input) return; + try { + const res = await fetch('/api/conhecimento', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ fact: input, source: 'manual' }) + }); + if (res.ok) { + manualKnowledgeInput.value = ''; + await loadConhecimento(); + } + } catch (e) { + console.error('Erro ao adicionar conhecimento:', e); + } + }); + } + + // Função para extrair knowledge tags da resposta da IA e enviar ao servidor + window.extractAndSaveKnowledge = async (assistantMessage) => { + if (!assistantMessage || !assistantMessage.includes('[KNOWLEDGE:')) return; + try { + await fetch('/api/conhecimento/extrair', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ message: assistantMessage }) + }); + } catch (e) { + console.error('Erro ao extrair conhecimento:', e); + } }; // Variáveis temporárias para avatares (em base64 ou URLs novas) @@ -160,6 +292,8 @@ const initApp = () => { if (settingAgentName) settingAgentName.value = window.agentConfig.agentName; if (previewKemilyAvatar) previewKemilyAvatar.src = window.agentConfig.kemilyAvatarUrl; if (previewCamilaAvatar) previewCamilaAvatar.src = window.agentConfig.camilaAvatarUrl; + renderTemperatureOptions(); + loadConhecimento(); settingsModal.style.display = 'flex'; }); } @@ -170,6 +304,18 @@ const initApp = () => { }); } + // Tab switching logic + document.querySelectorAll('.settings-tab').forEach(tab => { + tab.addEventListener('click', () => { + document.querySelectorAll('.settings-tab').forEach(t => t.classList.remove('active')); + document.querySelectorAll('.settings-tab-content').forEach(c => c.classList.remove('active')); + tab.classList.add('active'); + const targetId = tab.dataset.tab; + const targetContent = document.getElementById(targetId); + if (targetContent) targetContent.classList.add('active'); + }); + }); + // Fechar clicando fora do modal-content if (settingsModal) { settingsModal.addEventListener('click', (e) => { @@ -244,13 +390,15 @@ const initApp = () => { } // Envia as configurações gerais + const selectedTempPreset = temperatureOptions?.querySelector('input[name="temperature"]:checked')?.value || 'equilibrado'; const resConfig = await fetch('/api/agent-config', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ agentName: settingAgentName.value, kemilyAvatarUrl: kemilyUrl, - camilaAvatarUrl: camilaUrl + camilaAvatarUrl: camilaUrl, + temperaturePreset: selectedTempPreset }) }); @@ -1646,6 +1794,9 @@ const initApp = () => { }); } + // Extrair e salvar conhecimento aprendido (tags [KNOWLEDGE: ...]) + window.extractAndSaveKnowledge(assistantContent); + // Adicionar botões de ação (Copiar, Regenerar, Ouvir) após o streaming const escapedContent = escapeHtml(assistantContent).replace(/"/g, '"'); const actionsDiv = document.createElement('div'); diff --git a/public/index.html b/public/index.html index 9d4f9d2..1f72b07 100644 --- a/public/index.html +++ b/public/index.html @@ -249,32 +249,73 @@