diff --git a/.env b/.env index 26ca77b..6b9296d 100644 --- a/.env +++ b/.env @@ -2,7 +2,7 @@ PORT=3000 ACCESS_PASSWORD=puglindo26 OPENROUTER_API_KEY=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 OPENROUTER_MODEL=openai/gpt-4.1-nano -SESSION_SECRET=camila-secret-key-321123 +SESSION_SECRET=pedagog-secret-key-321123 MINIMAX_API_KEY=sk-cp-siEwoNh9WA3Prxe6frpJ2HsXPje-gjt5jObhHloqqoO0FX0i9yP54N3zhY492GKu18l9XiANDiCoECU3t0uMtRODvkzzi93A2Rmtco6MjATrKNOEDR_bxa4 MINIMAX_API_BASE=https://api.minimax.io/v1 GROQ_API_KEY=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 diff --git a/Agente/kemily_persona.md b/Agente/pedagogia_persona.md similarity index 70% rename from Agente/kemily_persona.md rename to Agente/pedagogia_persona.md index f0d8c64..4ec5f5d 100644 --- a/Agente/kemily_persona.md +++ b/Agente/pedagogia_persona.md @@ -1,10 +1,10 @@ -# Kemily — Agente de Educação Infantil +# PedagogIA — Agente de Educação Infantil ## Identidade -- **Nome:** Kemily -- **Género:** Feminino -- **Voz:** Feminina brasileira (将来 implementação de TTS) +- **Nome:** PedagogIA +- **Gênero:** Feminino +- **Voz:** Feminina brasileira (MsEdgeTTS pt-BR) - **Idioma:** Português do Brasil (PT-BR) - **Papel:** Assistente de Educação Infantil para Camila (professora da rede municipal de São Bernardo do Campo) @@ -22,7 +22,7 @@ Todo o conhecimento está armazenado em `/root/Apps/Camila/Agente/`: - `dossie_sbc.md` — Educação municipal de São Bernardo do Campo - `mindlab_dossier.md` — Organização e programas Mind Lab - `mindlab_jogos_detalhado.md` — Jogos, regras, aplicações práticas -- `exemplos/` — Documentos reais da Camila (quando disponíveis) +- `exemplos/` — Documentos reais da professora Camila ### Áreas de Especialização @@ -30,7 +30,7 @@ Todo o conhecimento está armazenado em `/root/Apps/Camila/Agente/`: - Desenvolvimento infantil - Campos de experiência BNCC - Planejamento pedagógico - - Relatórios descritivos (semanais/mensais) + - Relatórios descritivos (semanais/mensais/semestrais) 2. **Metodologia Mind Lab** - Jogos pedagógicos (certificados INMETRO) @@ -45,7 +45,7 @@ Todo o conhecimento está armazenado em `/root/Apps/Camila/Agente/`: - Objetivos de aprendizagem e desenvolvimento 4. **Documentação Pedagógica** - - Relatórios semanais/mensais + - Relatórios semanais/mensais/semestrais - Resumos de livros infantis - Planejamento de atividades - Avaliação descritiva @@ -60,7 +60,7 @@ Todo o conhecimento está armazenado em `/root/Apps/Camila/Agente/`: ### Como Responder 1. **Entender a necessidade:** Identificar se é relatório, planejamento, pesquisa, resumo, etc. -2. **Aplicar contexto:** Usar conhecimento da pasta Agente para fundamentar resposta +2. **Aplicar contexto:** Usar conhecimento pedagógico para fundamentar resposta 3. **Linguagem adequada:** Adaptar para português brasileiro acessível 4. **Formato prático:** Fornecer modelos, estruturas, sugestões prontas 5. **Incluir referência:** Quando usar Mind Lab ou BNCC, mencionar a conexão @@ -69,7 +69,7 @@ Todo o conhecimento está armazenado em `/root/Apps/Camila/Agente/`: | Tipo | Como Agir | |------|-----------| -| Relatório semanal | Fornecer estrutura, pontos a abordar, modelo | +| Relatório semanal/semestral | Fornecer estrutura, pontos a abordar, modelo | | Resumo de livro | Extrair temas, personagens, lições, sugestões de atividade | | Pesquisa | Buscar em conhecimentos locais, fornecer informações fundamentadas | | Planejamento | Criar estrutura com objetivos, atividades, recursos, avaliação | @@ -80,31 +80,18 @@ Todo o conhecimento está armazenado em `/root/Apps/Camila/Agente/`: - ❌ Usar inglês ou termos técnicos sem necessidade - ❌ Respostas genéricas sem conexão com contexto brasileiro -- ❌忽略 a especificidade da idade (2-5 anos) +- ❌ Ignorar a especificidade da idade (2-5 anos) - ❌ Fazer afirmações sobre legislação sem confirmar com fontes -## Integração Técnica - -### Arquivo de Configuração -- `.env` do app: `/root/Apps/Camila/.env` -- Modelo: `openai/gpt-4.1-nano` -- Contexto máximo: ~1M tokens - -### Como o Contexto é Injetado - -O sistema usa o prompt do sistema abaixo para definir a persona Kemily. -As mensagens da Camila são concatenadas com o system prompt. -O modelo GPT-4.1-nano recebe o contexto completo e responde como Kemily. - ## System Prompt (Injetado em cada conversa) ``` -Você é a Kemily, uma assistente de educação infantil especializada. -Você ajuda Camilly (professora de educação infantil na rede municipal de São Bernardo do Campo, SP) no seu trabalho diário. +Você é a PedagogIA, uma assistente de educação infantil especializada. +Você ajuda a professora Camila (professora de educação infantil na rede municipal de São Bernardo do Campo, SP) no seu trabalho diário. Sua missão: facilitar a criação de relatórios, planejamentos, resumos de livros infantis, pesquisas pedagógicas e uso de metodologias como Mind Lab. -Sua personalidade: carinhosa, paciente, prática, profissional. Você fala em português brasileiro e adapt para o nível da Camila. +Sua personalidade: carinhosa, paciente, prática, profissional. Você fala em português brasileiro e adapta para as necessidades da docência. Você tem acesso a conhecimento detalhado sobre: - BNCC e campos de experiência para educação infantil (2-5 anos) @@ -120,12 +107,3 @@ Sempre que possível: Responda SEMPRE em português do Brasil. ``` - ---- - -**Criado em:** 2026-05-25 -**Status:** Atualizado em 2026-05-26 — System prompt agora inclui: -- Estilo de escrita rigoroso baseado em documentos reais da Camila -- 4 exemplos reais de textos (HTPC, carta de intenções, planejamento, formação) -- Conhecimento detalhado de projetos, livros, formadoras e metodologia -- Regras de atuação e estrutura documental \ No newline at end of file diff --git a/PROMPT_KEMILY_RELATORIOS_SEMESTRAIS.md b/PROMPT_PEDAGOGI_RELATORIOS_SEMESTRAIS.md similarity index 94% rename from PROMPT_KEMILY_RELATORIOS_SEMESTRAIS.md rename to PROMPT_PEDAGOGI_RELATORIOS_SEMESTRAIS.md index 0be01c0..29c7356 100644 --- a/PROMPT_KEMILY_RELATORIOS_SEMESTRAIS.md +++ b/PROMPT_PEDAGOGI_RELATORIOS_SEMESTRAIS.md @@ -1,6 +1,6 @@ -# PROMPT PARA KEMILY — ANÁLISE E REDAÇÃO DE RELATÓRIOS SEMESTRAIS +# PROMPT PARA PEDAGOGIA — ANÁLISE E REDAÇÃO DE RELATÓRIOS SEMESTRAIS -Você é a assistente da Professora Camila Reifonas, do Educação Infantil da rede municipal de São Bernardo do Campo. Sua função é analisar observações de alunos e redigir relatórios semestrais no **EXATO** estilo da Professora Camila. +Você é a assistente virtual e especialista pedagógica da Professora Camila Reifonas, da Educação Infantil da rede municipal de São Bernardo do Campo. Sua função é analisar observações de alunos e redigir relatórios semestrais no **EXATO** estilo da Professora Camila. --- @@ -13,7 +13,7 @@ Ao receber observações cruas (notas, fotos, registros) sobre um aluno: - Brincadeiras e Preferências (materiais, brinquedos, espaços) - Interações Sociais (com quem brinca, como se relaciona, conflitos) - Desenvolvimento Motor (correr, pular, pedalar, equilíbrio) - - Linguagem e Oralidade (vocabulário, clareza,连贯性) + - Linguagem e Oralidade (vocabulário, clareza, coerência) - Criatividade e Atividades (construções, arte, imaginação) - Autonomia (cuidado de material, organização, refeições) - Desafios a desenvolver (sempre formular com cuidado) @@ -138,7 +138,7 @@ Espero que o/a [nome] continue se interessando bastante pela escola e avançando | `cultura de paz` | resolução de conflitos | | `sensibilidade e afetividade` | empatia | | `concentração e foco` | atenção | -| `combidados` | regras da turma (nunca diga "regras") | +| `combinados` | regras da turma (nunca diga "regras") | | `porcionar` | servings de comida | | `ampliou sua preferência por` | alimentação | @@ -146,8 +146,8 @@ Espero que o/a [nome] continue se interessando bastante pela escola e avançando ### EXPRESSÕES CARACTERÍSTICAS: -- `a todo momento` — para常态化 -- `juntos com` — nunca "junto com" +- `a todo momento` — para constância +- `juntos com` — conforme estilo da professora - `de acordo com o que lhe é proposto` - `especialmente` — para destacar pontos marcantes - `demonstrando` — ações que evidenciam qualidades @@ -159,7 +159,7 @@ Espero que o/a [nome] continue se interessando bastante pela escola e avançando ### O QUE NUNCA USAR: - ❌ `mostrou` → use **demonstrou** -- ❌ `acordos` → use **combidados** +- ❌ `acordos` → use **combinados** - ❌ `regras` isoladamente → use **regras e combinados** - ❌ Críticas diretas ou palavras como "problema", "dificuldade" - ❌ Menção a condições de saúde ou situações familiares @@ -242,15 +242,15 @@ O relatório semestral completo é composto por **3 partes**: ## PARTE 7 — DIFERENÇAS COM A ESTRUTURA INSTITUCIONAL -Os relatórios da Camila **NÃO têm:** +Os relatórios **NÃO têm:** - Cabeçalhos institucionais (escola, turma, ano) - Numeração de blocos ou tópicos - Notas ou conceitos (satisfatório, insatisfatório, etc.) - Avaliação por disciplina (é Educação Infantil) -Os relatórios da Camila **TÊM:** +Os relatórios **TÊM:** - Texto corrido, narrativo, em parágrafos - Linguagem descritiva e positiva - Foco em avanços, não em deficiências - Pronóstico esperançoso no fechamento -- Linguagem atenuada para pontos de melhoria ("necessitando de", "permanece o desafio de") \ No newline at end of file +- Linguagem atenuada para pontos de melhoria ("necessitando de", "permanece o desafio de") diff --git a/agent_config.json b/agent_config.json index 1e7ceaf..07be3fa 100644 --- a/agent_config.json +++ b/agent_config.json @@ -1,5 +1,5 @@ { - "agentName": "Kemily", - "kemilyAvatarUrl": "assets/kemily.png", - "camilaAvatarUrl": "assets/camila_prof.png" + "agentName": "PedagogIA", + "iaAvatarUrl": "assets/pedagog_ia.png", + "userAvatarUrl": "assets/pedagog_user.png" } diff --git a/package.json b/package.json index 25f90f5..3348a9b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "camila-chatgpt-clone", + "name": "pedagog", "version": "1.0.0", - "description": "Replica do ChatGPT moderna com autenticação e integração OpenRouter", + "description": "Pedagog - Plataforma de IA Educacional para Professores", "main": "server.js", "scripts": { "start": "node server.js", diff --git a/public/app.js b/public/app.js index 42ee593..21c65e7 100644 --- a/public/app.js +++ b/public/app.js @@ -216,16 +216,16 @@ const initApp = () => { const searchClearAll = document.getElementById('searchClearAll'); const sidebarTags = document.getElementById('sidebarTags'); - // Configuração de Identidade do Agente (Kemily/Camila) + // Configuração de Identidade do Agente (PedagogIA/Pedagog) const btnSettings = document.getElementById('btnSettings'); const settingsModal = document.getElementById('settingsModal'); const closeSettingsModal = document.getElementById('closeSettingsModal'); const btnSaveSettings = document.getElementById('btnSaveSettings'); const settingAgentName = document.getElementById('settingAgentName'); - const previewKemilyAvatar = document.getElementById('previewKemilyAvatar'); - const uploadKemilyAvatar = document.getElementById('uploadKemilyAvatar'); - const previewCamilaAvatar = document.getElementById('previewCamilaAvatar'); - const uploadCamilaAvatar = document.getElementById('uploadCamilaAvatar'); + const previewIaAvatar = document.getElementById('previewIaAvatar'); + const uploadIaAvatar = document.getElementById('uploadIaAvatar'); + const previewUserAvatar = document.getElementById('previewUserAvatar'); + const uploadUserAvatar = document.getElementById('uploadUserAvatar'); const welcomeTitle = document.getElementById('welcomeTitle'); const welcomeAvatarImg = document.getElementById('welcomeAvatarImg'); const sidebarAvatarImg = document.getElementById('sidebarAvatarImg'); @@ -235,9 +235,9 @@ const initApp = () => { const btnAddKnowledge = document.getElementById('btnAddKnowledge'); window.agentConfig = { - agentName: "Kemily", - kemilyAvatarUrl: "assets/kemily.png", - camilaAvatarUrl: "assets/camila_prof.png", + agentName: "PedagogIA", + iaAvatarUrl: "assets/pedagog_ia.png", + userAvatarUrl: "assets/pedagog_user.png", temperaturePreset: 'equilibrado' }; @@ -264,22 +264,22 @@ const initApp = () => { const updateAgentIdentityUI = () => { if (welcomeTitle) { - welcomeTitle.innerText = `Olá! Sou sua assistente virtual e me chamo ${window.agentConfig.agentName}. Como posso ajudar?`; + welcomeTitle.innerText = `Olá! Sou sua assistente virtual e me chamo ${window.agentConfig.agentName || 'PedagogIA'}. Como posso ajudar?`; } if (welcomeAvatarImg) { - welcomeAvatarImg.src = window.agentConfig.kemilyAvatarUrl; + welcomeAvatarImg.src = window.agentConfig.iaAvatarUrl || window.agentConfig.kemilyAvatarUrl || 'assets/pedagog_ia.png'; } if (sidebarAvatarImg) { - sidebarAvatarImg.src = window.agentConfig.camilaAvatarUrl; + sidebarAvatarImg.src = window.agentConfig.userAvatarUrl || window.agentConfig.camilaAvatarUrl || 'assets/pedagog_user.png'; } if (settingAgentName) { - settingAgentName.value = window.agentConfig.agentName; + settingAgentName.value = window.agentConfig.agentName || 'PedagogIA'; } - if (previewKemilyAvatar) { - previewKemilyAvatar.src = window.agentConfig.kemilyAvatarUrl; + if (previewIaAvatar) { + previewIaAvatar.src = window.agentConfig.iaAvatarUrl || window.agentConfig.kemilyAvatarUrl || 'assets/pedagog_ia.png'; } - if (previewCamilaAvatar) { - previewCamilaAvatar.src = window.agentConfig.camilaAvatarUrl; + if (previewUserAvatar) { + previewUserAvatar.src = window.agentConfig.userAvatarUrl || window.agentConfig.camilaAvatarUrl || 'assets/pedagog_user.png'; } // Atualiza seleção de temperatura renderTemperatureOptions(); @@ -472,17 +472,17 @@ const initApp = () => { }; // Variáveis temporárias para avatares (em base64 ou URLs novas) - let newKemilyAvatarData = null; - let newCamilaAvatarData = null; + let newIaAvatarData = null; + let newUserAvatarData = null; // Eventos do Modal if (btnSettings) { btnSettings.addEventListener('click', () => { - newKemilyAvatarData = null; - newCamilaAvatarData = null; - if (settingAgentName) settingAgentName.value = window.agentConfig.agentName; - if (previewKemilyAvatar) previewKemilyAvatar.src = window.agentConfig.kemilyAvatarUrl; - if (previewCamilaAvatar) previewCamilaAvatar.src = window.agentConfig.camilaAvatarUrl; + newIaAvatarData = null; + newUserAvatarData = null; + if (settingAgentName) settingAgentName.value = window.agentConfig.agentName || 'PedagogIA'; + if (previewIaAvatar) previewIaAvatar.src = window.agentConfig.iaAvatarUrl || window.agentConfig.kemilyAvatarUrl || 'assets/pedagog_ia.png'; + if (previewUserAvatar) previewUserAvatar.src = window.agentConfig.userAvatarUrl || window.agentConfig.camilaAvatarUrl || 'assets/pedagog_user.png'; renderTemperatureOptions(); loadConhecimento(); settingsModal.style.display = 'flex'; @@ -529,18 +529,18 @@ const initApp = () => { } }; - if (uploadKemilyAvatar) { - uploadKemilyAvatar.addEventListener('change', () => { - handleAvatarFileSelect(uploadKemilyAvatar, previewKemilyAvatar, (base64) => { - newKemilyAvatarData = base64; + if (uploadIaAvatar) { + uploadIaAvatar.addEventListener('change', () => { + handleAvatarFileSelect(uploadIaAvatar, previewIaAvatar, (base64) => { + newIaAvatarData = base64; }); }); } - if (uploadCamilaAvatar) { - uploadCamilaAvatar.addEventListener('change', () => { - handleAvatarFileSelect(uploadCamilaAvatar, previewCamilaAvatar, (base64) => { - newCamilaAvatarData = base64; + if (uploadUserAvatar) { + uploadUserAvatar.addEventListener('change', () => { + handleAvatarFileSelect(uploadUserAvatar, previewUserAvatar, (base64) => { + newUserAvatarData = base64; }); }); } @@ -552,31 +552,31 @@ const initApp = () => { btnSaveSettings.innerText = 'Salvando...'; try { - let kemilyUrl = window.agentConfig.kemilyAvatarUrl; - let camilaUrl = window.agentConfig.camilaAvatarUrl; + let iaUrl = window.agentConfig.iaAvatarUrl || window.agentConfig.kemilyAvatarUrl || 'assets/pedagog_ia.png'; + let userUrl = window.agentConfig.userAvatarUrl || window.agentConfig.camilaAvatarUrl || 'assets/pedagog_user.png'; // Se houver novas imagens, faz upload - if (newKemilyAvatarData) { + if (newIaAvatarData) { const res = await fetch('/api/upload-avatar', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ avatarType: 'kemily', base64Data: newKemilyAvatarData }) + body: JSON.stringify({ avatarType: 'ia', base64Data: newIaAvatarData }) }); if (res.ok) { const data = await res.json(); - kemilyUrl = data.url; + iaUrl = data.url; } } - if (newCamilaAvatarData) { + if (newUserAvatarData) { const res = await fetch('/api/upload-avatar', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ avatarType: 'camila', base64Data: newCamilaAvatarData }) + body: JSON.stringify({ avatarType: 'user', base64Data: newUserAvatarData }) }); if (res.ok) { const data = await res.json(); - camilaUrl = data.url; + userUrl = data.url; } } @@ -587,8 +587,8 @@ const initApp = () => { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ agentName: settingAgentName.value, - kemilyAvatarUrl: kemilyUrl, - camilaAvatarUrl: camilaUrl, + iaAvatarUrl: iaUrl, + userAvatarUrl: userUrl, temperaturePreset: selectedTempPreset }) }); @@ -615,10 +615,10 @@ const initApp = () => { loadAgentConfig(); // Variáveis de Estado - let chats = JSON.parse(localStorage.getItem('camila_chats')) || []; + let chats = JSON.parse(localStorage.getItem('pedagog_chats') || localStorage.getItem('camila_chats')) || []; // Migração: adicionar campos tags e pinned a chats antigos chats = chats.map(c => ({ ...c, tags: c.tags || [], pinned: c.pinned || false })); - let currentChatId = localStorage.getItem('camila_current_chat_id') || null; + let currentChatId = localStorage.getItem('pedagog_current_chat_id') || localStorage.getItem('camila_current_chat_id') || null; let isGenerating = false; let searchQuery = ''; let activeTag = 'all'; @@ -638,7 +638,7 @@ const initApp = () => { const applyTheme = (theme) => { document.documentElement.setAttribute('data-theme', theme); - localStorage.setItem('camila_theme', theme); + localStorage.setItem('pedagog_theme', theme); if (theme === 'light') { iconThemeSun.style.display = 'none'; iconThemeMoon.style.display = 'block'; @@ -649,7 +649,7 @@ const initApp = () => { }; // Init theme from localStorage or system preference - const savedTheme = localStorage.getItem('camila_theme'); + const savedTheme = localStorage.getItem('pedagog_theme') || localStorage.getItem('camila_theme'); if (savedTheme) { applyTheme(savedTheme); } else { @@ -1283,11 +1283,11 @@ const initApp = () => { // ========================================================================== const saveChats = () => { - localStorage.setItem('camila_chats', JSON.stringify(chats)); + localStorage.setItem('pedagog_chats', JSON.stringify(chats)); if (currentChatId) { - localStorage.setItem('camila_current_chat_id', currentChatId); + localStorage.setItem('pedagog_current_chat_id', currentChatId); } else { - localStorage.removeItem('camila_current_chat_id'); + localStorage.removeItem('pedagog_current_chat_id'); } }; @@ -1563,7 +1563,7 @@ const initApp = () => { if (isGenerating) return; currentChatId = null; - localStorage.removeItem('camila_current_chat_id'); + localStorage.removeItem('pedagog_current_chat_id'); welcomeContainer.style.display = 'flex'; conversationList.innerHTML = ''; @@ -1599,8 +1599,8 @@ const initApp = () => { row.className = `message-row ${role}`; const avatarHtml = isUser - ? `
Camila
` - : `
${window.agentConfig?.agentName || 'Kemily'}
`; + ? `
Usuário
` + : `
${window.agentConfig?.agentName || 'PedagogIA'}
`; let contentHtml = ''; if (isUser) { @@ -1991,7 +1991,7 @@ const initApp = () => { botRow.innerHTML = `
-
${window.agentConfig?.agentName || 'Kemily'}
+
${window.agentConfig?.agentName || 'PedagogIA'}
@@ -2713,7 +2713,7 @@ const initApp = () => { showRecordState('processing'); try { - const turmaData = localStorage.getItem('camila_turma') || '[]'; + const turmaData = localStorage.getItem('pedagog_turma') || localStorage.getItem('camila_turma') || '[]'; const res = await fetch('/api/observacao/analisar', { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -2923,7 +2923,7 @@ const initApp = () => { let especialKidsNames = []; if (isSpecialObsMode) { - const turma = JSON.parse(localStorage.getItem('camila_turma') || '[]'); + const turma = JSON.parse(localStorage.getItem('pedagog_turma') || localStorage.getItem('camila_turma') || '[]'); especialKidsNames = turma.filter(c => c.especial).map(c => (c.nome || '').toLowerCase().trim()).filter(Boolean); if (especialKidsNames.length === 0) { obsList.innerHTML = '
Nenhuma criança com "Educação Especial" cadastrada na Minha Turma.
'; @@ -3051,7 +3051,7 @@ const initApp = () => { try { const res = await fetch('/api/alunos'); currentAlunos = await res.json(); - localStorage.setItem('camila_turma', JSON.stringify(currentAlunos)); + localStorage.setItem('pedagog_turma', JSON.stringify(currentAlunos)); return currentAlunos; } catch(e) { console.error(e); return []; } }; @@ -4981,7 +4981,7 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.` } // Renderizar quadrinhos na tela (todos, incluindo os anteriores caso tenha sido extensão) - comicsResultTitle.textContent = scriptData.title || comicsResultTitle.textContent || 'Fábrica de Quadrinhos Camila'; + comicsResultTitle.textContent = scriptData.title || comicsResultTitle.textContent || 'Fábrica de Quadrinhos Pedagog'; comicsGridContainer.innerHTML = ''; generatedPanelsData.forEach((panel, index) => { diff --git a/public/assets/pedagog_ia.png b/public/assets/pedagog_ia.png new file mode 100644 index 0000000..563548d Binary files /dev/null and b/public/assets/pedagog_ia.png differ diff --git a/public/assets/pedagog_user.png b/public/assets/pedagog_user.png new file mode 100644 index 0000000..8e14e08 Binary files /dev/null and b/public/assets/pedagog_user.png differ diff --git a/public/index.html b/public/index.html index dacca9a..68a6dae 100644 --- a/public/index.html +++ b/public/index.html @@ -146,10 +146,10 @@
- +
- Camila Preview - - + Usuário Preview + +
diff --git a/public/login.html b/public/login.html index 009fdea..8b14fe9 100644 --- a/public/login.html +++ b/public/login.html @@ -4,7 +4,7 @@ - Camila - Entrar + Pedagog - Entrar @@ -21,10 +21,10 @@
diff --git a/public/style.css b/public/style.css index 2204961..0e7a67f 100644 --- a/public/style.css +++ b/public/style.css @@ -2361,7 +2361,7 @@ code { color: #fdba74; } -/* Modo Texto/História: Estilos e Cores (Verde Kemily) */ +/* Modo Texto/História: Estilos e Cores (Verde PedagogIA) */ .btn-prompt-mode.mode-text { border-color: rgba(16, 163, 127, 0.4); color: #34d399; diff --git a/public/sw.js b/public/sw.js index b9da099..a9a9bb8 100644 --- a/public/sw.js +++ b/public/sw.js @@ -1,12 +1,14 @@ -const CACHE_NAME = 'camila-ai-v10'; +const CACHE_NAME = 'pedagog-ai-v11'; const urlsToCache = [ '/', '/index.html', '/style.css', '/app.js', '/manifest.json', - '/icon-192.png', - '/icon-512.png' + '/assets/icon-192.png', + '/assets/icon-512.png', + '/assets/pedagog_user.png', + '/assets/pedagog_ia.png' ]; // Instalação - abre cache e armazena os arquivos iniciais @@ -14,7 +16,7 @@ self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_NAME) .then((cache) => { - console.log('Camila AI SW: Armazenando cache inicial'); + console.log('Pedagog AI SW: Armazenando cache inicial'); return cache.addAll(urlsToCache); }) .then(() => self.skipWaiting()) @@ -28,7 +30,7 @@ self.addEventListener('activate', (event) => { return Promise.all( cacheNames.map((cacheName) => { if (cacheName !== CACHE_NAME) { - console.log('Camila AI SW: Removendo cache antigo:', cacheName); + console.log('Pedagog AI SW: Removendo cache antigo:', cacheName); return caches.delete(cacheName); } }) diff --git a/scratch/migrate_config.js b/scratch/migrate_config.js new file mode 100644 index 0000000..e024714 --- /dev/null +++ b/scratch/migrate_config.js @@ -0,0 +1,46 @@ +require('dotenv').config({ path: '/root/Apps/Camila/.env' }); +const { Pool } = require('pg'); + +const pool = new Pool({ + connectionString: process.env.DATABASE_URL +}); + +async function migrate() { + try { + console.log("Conectando ao banco..."); + const cols = await pool.query(` + SELECT column_name + FROM information_schema.columns + WHERE table_schema='escola' AND table_name='config'; + `); + const colNames = cols.rows.map(r => r.column_name); + console.log("Colunas atuais:", colNames); + + if (colNames.includes('kemily_avatar_url')) { + console.log("Renomeando kemily_avatar_url -> ia_avatar_url"); + await pool.query(`ALTER TABLE escola.config RENAME COLUMN kemily_avatar_url TO ia_avatar_url;`); + } + if (colNames.includes('camila_avatar_url')) { + console.log("Renomeando camila_avatar_url -> user_avatar_url"); + await pool.query(`ALTER TABLE escola.config RENAME COLUMN camila_avatar_url TO user_avatar_url;`); + } + + await pool.query(`ALTER TABLE escola.config ALTER COLUMN agent_name SET DEFAULT 'PedagogIA';`); + await pool.query(`ALTER TABLE escola.config ALTER COLUMN ia_avatar_url SET DEFAULT 'assets/pedagog_ia.png';`); + await pool.query(`ALTER TABLE escola.config ALTER COLUMN user_avatar_url SET DEFAULT 'assets/pedagog_user.png';`); + + await pool.query(`UPDATE escola.config SET agent_name = 'PedagogIA' WHERE agent_name = 'Kemily';`); + await pool.query(`UPDATE escola.config SET ia_avatar_url = 'assets/pedagog_ia.png' WHERE ia_avatar_url = 'assets/kemily.png';`); + await pool.query(`UPDATE escola.config SET user_avatar_url = 'assets/pedagog_user.png' WHERE user_avatar_url = 'assets/camila_prof.png';`); + + console.log("Migração concluída com sucesso!"); + const updated = await pool.query(`SELECT * FROM escola.config;`); + console.log("Configurações atualizadas:", updated.rows); + } catch (err) { + console.error("Erro na migração:", err); + } finally { + await pool.end(); + } +} + +migrate(); diff --git a/scratch/test_gen.js b/scratch/test_gen.js index ae33e04..1f2dde5 100644 --- a/scratch/test_gen.js +++ b/scratch/test_gen.js @@ -62,7 +62,7 @@ async function test() { }).join('\n\n---\n\n'); const agentConfig = readAgentConfig(); - const agentName = agentConfig.agentName || "Kemily"; + const agentName = agentConfig.agentName || "PedagogIA"; const targetStudentInfo = `\nATENÇÃO CRÍTICA: A criança que está sendo avaliada e para quem você deve gerar o relatório individual é especificamente: "${crianca}". Todas as observações, avanços, preferências e conclusões descritas na PARTE 2 (Desenvolvimento Individual) devem referir-se exclusivamente a ${crianca}. Nunca confunda ${crianca} com outros colegas eventualmente citados nas observações (como Joãozinho, Vanderlei, etc.), e não atribua as ações deles a ela.\n`; diff --git a/server.js b/server.js index 997d9c3..276d121 100644 --- a/server.js +++ b/server.js @@ -60,11 +60,11 @@ async function callMinimax({ messages, temperature = 0.5, max_tokens = 1500, sys app.use(express.json({ limit: '50mb' })); app.use(express.urlencoded({ limit: '50mb', extended: true })); -app.use(cookieParser(process.env.SESSION_SECRET || 'camila-secret')); +app.use(cookieParser(process.env.SESSION_SECRET || 'pedagog-secret')); // Middleware para verificar autenticação const requireAuth = (req, res, next) => { - const session = req.signedCookies.camila_session || req.cookies.camila_session; + const session = req.signedCookies.pedagog_session || req.cookies.pedagog_session || req.signedCookies.camila_session || req.cookies.camila_session; if (session === 'authenticated') { next(); } else { @@ -115,9 +115,9 @@ const TEMPERATURE_PRESETS = { }; let agentConfigCache = { - agentName: "Kemily", - kemilyAvatarUrl: "assets/kemily.png", - camilaAvatarUrl: "assets/camila_prof.png", + agentName: "PedagogIA", + iaAvatarUrl: "assets/pedagog_ia.png", + userAvatarUrl: "assets/pedagog_user.png", temperaturePreset: "equilibrado" }; @@ -127,27 +127,27 @@ function readAgentConfig() { async function writeAgentConfig(config) { agentConfigCache = { - agentName: config.agentName, - kemilyAvatarUrl: config.kemilyAvatarUrl, - camilaAvatarUrl: config.camilaAvatarUrl, + agentName: config.agentName || "PedagogIA", + iaAvatarUrl: config.iaAvatarUrl || config.kemilyAvatarUrl || "assets/pedagog_ia.png", + userAvatarUrl: config.userAvatarUrl || config.camilaAvatarUrl || "assets/pedagog_user.png", temperaturePreset: config.temperaturePreset || 'equilibrado' }; try { await dbPool.query( - `INSERT INTO escola.config (key, agent_name, kemily_avatar_url, camila_avatar_url, temperature_preset, updated_at) + `INSERT INTO escola.config (key, agent_name, ia_avatar_url, user_avatar_url, temperature_preset, updated_at) VALUES ('current', $1, $2, $3, $4, NOW()) ON CONFLICT (key) DO UPDATE SET agent_name = EXCLUDED.agent_name, - kemily_avatar_url = EXCLUDED.kemily_avatar_url, - camila_avatar_url = EXCLUDED.camila_avatar_url, + ia_avatar_url = EXCLUDED.ia_avatar_url, + user_avatar_url = EXCLUDED.user_avatar_url, temperature_preset = EXCLUDED.temperature_preset, updated_at = NOW();`, - [config.agentName, config.kemilyAvatarUrl, config.camilaAvatarUrl, config.temperaturePreset || 'equilibrado'] + [agentConfigCache.agentName, agentConfigCache.iaAvatarUrl, agentConfigCache.userAvatarUrl, agentConfigCache.temperaturePreset] ); - fs.writeFileSync(CONFIG_FILE_PATH, JSON.stringify(config, null, 2), 'utf8'); + fs.writeFileSync(CONFIG_FILE_PATH, JSON.stringify(agentConfigCache, null, 2), 'utf8'); const botConfigDir = path.join(__dirname, '..', 'BotVPS', 'data'); if (fs.existsSync(botConfigDir)) { - fs.writeFileSync(path.join(botConfigDir, 'agent_config.json'), JSON.stringify(config, null, 2), 'utf8'); + fs.writeFileSync(path.join(botConfigDir, 'agent_config.json'), JSON.stringify(agentConfigCache, null, 2), 'utf8'); } } catch (e) { console.error('Erro ao salvar agent_config no banco:', e); @@ -1386,7 +1386,7 @@ app.post('/api/cartazes/generate', requireAuth, async (req, res) => { try { const agentConfig = readAgentConfig(); - const agentName = agentConfig.agentName || "Kemily"; + const agentName = agentConfig.agentName || "PedagogIA"; // 1. Gerar Conteúdo do Cartaz const posterPrompt = `Você é a ${agentName}, assistente pedagógica da professora Camila Martella Gasparini Reifonas. @@ -1642,7 +1642,7 @@ Return ONLY the English prompt, nothing else.`; if (!tema) return res.status(400).json({ error: 'Tema ou layers_manual são obrigatórios.' }); const agentConfig = readAgentConfig(); - const agentName = agentConfig.agentName || "Kemily"; + const agentName = agentConfig.agentName || "PedagogIA"; const segmentPrompt = `Você é a ${agentName}, assistente pedagógica. Tema: "${tema}" / Título: "${titulo || ''}" @@ -2067,14 +2067,14 @@ app.get('/api/agent-config', requireAuth, (req, res) => { // Rota POST para atualizar configurações do agente app.post('/api/agent-config', requireAuth, async (req, res) => { - const { agentName, kemilyAvatarUrl, camilaAvatarUrl, temperaturePreset } = req.body; + const { agentName, iaAvatarUrl, userAvatarUrl, kemilyAvatarUrl, camilaAvatarUrl, temperaturePreset } = req.body; if (!agentName) { return res.status(400).json({ error: 'Nome do agente é obrigatório' }); } const config = { agentName: agentName.trim(), - kemilyAvatarUrl: kemilyAvatarUrl || "assets/kemily.png", - camilaAvatarUrl: camilaAvatarUrl || "assets/camila_prof.png", + iaAvatarUrl: iaAvatarUrl || kemilyAvatarUrl || "assets/pedagog_ia.png", + userAvatarUrl: userAvatarUrl || camilaAvatarUrl || "assets/pedagog_user.png", temperaturePreset: temperaturePreset || 'equilibrado' }; await writeAgentConfig(config); @@ -2473,21 +2473,37 @@ async function initDatabase() { } // 1. Sincronizar cache de configurações do agente ou migrar - const configRes = await dbPool.query("SELECT agent_name, kemily_avatar_url, camila_avatar_url, temperature_preset FROM escola.config WHERE key = 'current';"); + try { + await dbPool.query(` + DO $$ + BEGIN + IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='escola' AND table_name='config' AND column_name='kemily_avatar_url') THEN + ALTER TABLE escola.config RENAME COLUMN kemily_avatar_url TO ia_avatar_url; + END IF; + IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema='escola' AND table_name='config' AND column_name='camila_avatar_url') THEN + ALTER TABLE escola.config RENAME COLUMN camila_avatar_url TO user_avatar_url; + END IF; + END $$; + `); + } catch (migErr) { + console.warn('[Database Init] Aviso ao verificar colunas da tabela escola.config:', migErr.message); + } + + const configRes = await dbPool.query("SELECT agent_name, ia_avatar_url, user_avatar_url, temperature_preset FROM escola.config WHERE key = 'current';"); if (configRes.rows.length > 0) { agentConfigCache = { - agentName: configRes.rows[0].agent_name, - kemilyAvatarUrl: configRes.rows[0].kemily_avatar_url, - camilaAvatarUrl: configRes.rows[0].camila_avatar_url, - temperaturePreset: configRes.rows[0].temperature_preset + agentName: configRes.rows[0].agent_name || "PedagogIA", + iaAvatarUrl: configRes.rows[0].ia_avatar_url || "assets/pedagog_ia.png", + userAvatarUrl: configRes.rows[0].user_avatar_url || "assets/pedagog_user.png", + temperaturePreset: configRes.rows[0].temperature_preset || "equilibrado" }; console.log('[Database Init] Configurações do agente carregadas do banco de dados:', agentConfigCache.agentName); } else { console.log('[Database Init] Migrando configurações do agente do arquivo local...'); let localConfig = { - agentName: "Kemily", - kemilyAvatarUrl: "assets/kemily.png", - camilaAvatarUrl: "assets/camila_prof.png", + agentName: "PedagogIA", + iaAvatarUrl: "assets/pedagog_ia.png", + userAvatarUrl: "assets/pedagog_user.png", temperaturePreset: "equilibrado" }; try { @@ -2497,10 +2513,15 @@ async function initDatabase() { } catch (err) { console.error('[Database Init] Erro ao ler agent_config.json local:', err.message); } - agentConfigCache = localConfig; + agentConfigCache = { + agentName: localConfig.agentName || "PedagogIA", + iaAvatarUrl: localConfig.iaAvatarUrl || localConfig.kemilyAvatarUrl || "assets/pedagog_ia.png", + userAvatarUrl: localConfig.userAvatarUrl || localConfig.camilaAvatarUrl || "assets/pedagog_user.png", + temperaturePreset: localConfig.temperaturePreset || "equilibrado" + }; await dbPool.query( - "INSERT INTO escola.config (key, agent_name, kemily_avatar_url, camila_avatar_url, temperature_preset) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (key) DO NOTHING;", - ['current', localConfig.agentName, localConfig.kemilyAvatarUrl, localConfig.camilaAvatarUrl, localConfig.temperaturePreset || 'equilibrado'] + "INSERT INTO escola.config (key, agent_name, ia_avatar_url, user_avatar_url, temperature_preset) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (key) DO NOTHING;", + ['current', agentConfigCache.agentName, agentConfigCache.iaAvatarUrl, agentConfigCache.userAvatarUrl, agentConfigCache.temperaturePreset] ); } @@ -2663,7 +2684,7 @@ app.post('/api/observacao/analisar', requireAuth, async (req, res) => { try { const agentConfig = readAgentConfig(); - const agentName = agentConfig.agentName || "Kemily"; + const agentName = agentConfig.agentName || "PedagogIA"; const temperaturePreset = agentConfig.temperaturePreset || 'equilibrado'; const presetDesc = TEMPERATURE_PRESETS[temperaturePreset]?.description || TEMPERATURE_PRESETS['equilibrado'].description; const presetLabel = TEMPERATURE_PRESETS[temperaturePreset]?.label || 'Equilibrado'; @@ -3194,7 +3215,7 @@ app.post('/api/modelos/gerar-relatorio', requireAuth, async (req, res) => { }).join('\n\n---\n\n'); const agentConfig = readAgentConfig(); - const agentName = agentConfig.agentName || "Kemily"; + const agentName = agentConfig.agentName || "PedagogIA"; const isGlobal = crianca === 'todas'; const targetStudentInfo = isGlobal @@ -3445,7 +3466,7 @@ app.get('/api/observacoes/resumo', requireAuth, async (req, res) => { const combined = texts.join('\n\n---\n\n'); const agentConfig = readAgentConfig(); - const agentName = agentConfig.agentName || "Kemily"; + const agentName = agentConfig.agentName || "PedagogIA"; const compilePrompt = `Você é a ${agentName}, assistente pedagógica. Compilar um RESUMO PEDAGÓGICO consolidado a partir de várias observações de uma criança. @@ -3551,7 +3572,7 @@ app.post('/api/upload-avatar', requireAuth, (req, res) => { // Rota de login (página) app.get('/login', (req, res) => { - const session = req.signedCookies.camila_session || req.cookies.camila_session; + const session = req.signedCookies.pedagog_session || req.cookies.pedagog_session || req.signedCookies.camila_session || req.cookies.camila_session; if (session === 'authenticated') { res.redirect('/'); } else { @@ -3574,7 +3595,7 @@ app.post('/api/login', (req, res) => { const { password } = req.body; if (password === ACCESS_PASSWORD) { // Define cookie de sessão assinado que dura 30 dias - res.cookie('camila_session', 'authenticated', { + res.cookie('pedagog_session', 'authenticated', { signed: true, httpOnly: true, maxAge: 30 * 24 * 60 * 60 * 1000, // 30 dias @@ -3589,6 +3610,7 @@ app.post('/api/login', (req, res) => { // API para Logout app.post('/api/logout', (req, res) => { + res.clearCookie('pedagog_session'); res.clearCookie('camila_session'); res.json({ success: true }); }); @@ -3650,10 +3672,10 @@ app.get('/generated-media/:filename', async (req, res, next) => { // Servir arquivos estáticos do diretório public app.use(express.static(path.join(__dirname, 'public'))); -// System prompt da Kemily (injetado em todas as conversas) -const KEMILY_SYSTEM_PROMPT = { +// System prompt da PedagogIA (injetado em todas as conversas) +const PEDAGOG_IA_SYSTEM_PROMPT = { role: "system", - content: `Você é a Kemily, assistente virtual e extensionista digital da Profª Camila Martella Gasparini Reifonas. + content: `Você é a PedagogIA, assistente virtual e extensionista digital da Profª Camila Martella Gasparini Reifonas. ═══════════════════════════════════════════════════ IDENTIDADE — Quem é a Camila (para que você possa falar dela com precisão) @@ -4545,7 +4567,7 @@ app.post('/api/chat', requireAuth, async (req, res) => { // FLUXO PADRÃO DE TEXTO (OpenRouter com SSE streaming original, com fallback Groq) // ========================================================================== const agentConfig = readAgentConfig(); - const agentName = agentConfig.agentName || "Kemily"; + const agentName = agentConfig.agentName || "PedagogIA"; const temperaturePreset = agentConfig.temperaturePreset || 'equilibrado'; const temperature = TEMPERATURE_PRESETS[temperaturePreset]?.value || 0.6; @@ -4622,7 +4644,8 @@ app.post('/api/chat', requireAuth, async (req, res) => { const dynamicSystemPrompt = { role: "system", - content: styleDirective + languageDirective + KEMILY_SYSTEM_PROMPT.content + content: styleDirective + languageDirective + PEDAGOG_IA_SYSTEM_PROMPT.content + .replace(/Você é a PedagogIA/g, `Você é a ${agentName}`) .replace(/Você é a Kemily/g, `Você é a ${agentName}`) .replace('INFORMAÇÕES PESSOAIS:', `${knowledgeText}${observationsContext}INFORMAÇÕES PESSOAIS:`) + styleDirective + languageDirective }; @@ -4671,8 +4694,8 @@ app.post('/api/chat', requireAuth, async (req, res) => { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`, - 'HTTP-Referer': 'https://camila.reifonas.cloud', - 'X-Title': 'Camila ChatGPT replica', + 'HTTP-Referer': 'https://pedagog.app', + 'X-Title': 'Pedagog AI', 'Content-Type': 'application/json' }, body: JSON.stringify({ diff --git a/update.sh b/update.sh index d5bc613..5c42f2a 100755 --- a/update.sh +++ b/update.sh @@ -1,6 +1,6 @@ #!/bin/bash # --------------------------------------------------------- -# CAMILA - SCRIPT DE AUTO-DEPLOY E SYNC +# PEDAGOG - SCRIPT DE AUTO-DEPLOY E SYNC # --------------------------------------------------------- CYAN='\033[0;36m' @@ -8,7 +8,7 @@ GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' -echo -e "\n${CYAN}🚀 Iniciando Ciclo Automático Camila...${NC}" +echo -e "\n${CYAN}🚀 Iniciando Ciclo Automático Pedagog...${NC}" # 1. Sincronização Git echo -e "${YELLOW}📝 Sincronizando código com o Gitea...${NC}" @@ -18,7 +18,7 @@ if git diff-index --quiet HEAD --; then echo -e "${GREEN}✨ Código local já está sincronizado.${NC}" else TIMESTAMP=$(date +"%d/%m/%Y %H:%M:%S") - MSG="${1:-🚀 Auto-deploy: Camila atualizado em $TIMESTAMP}" + MSG="${1:-🚀 Auto-deploy: Pedagog atualizado em $TIMESTAMP}" git commit -m "$MSG" git push origin main fi @@ -27,7 +27,7 @@ fi COOLIFY_RESOURCE_UUID="zzmj37ya8lmntomh3bm8rivi" COOLIFY_TOKEN="12|wbepNILQe24LAOjfEUmMROgU93F6uG1zuwPLwrRi786bca03" -echo -e "${YELLOW}🔄 Disparando Deploy na Coolify (camila.reifonas.cloud)...${NC}" +echo -e "${YELLOW}🔄 Disparando Deploy na Coolify...${NC}" curl -s -X GET "https://painel.reifonas.cloud/api/v1/deploy?uuid=${COOLIFY_RESOURCE_UUID}&force=false" \ -H "Authorization: Bearer $COOLIFY_TOKEN"