Files
carinha-control-panel/overview.js
T

159 lines
5.9 KiB
JavaScript

/**
* overview.js — Lógica de supervisão da Visão Geral
* Monitora métricas do robô, bateria, IA Gemini, reações e gerencia ações rápidas.
*/
(() => {
const el = id => document.getElementById(id);
let reload = null;
let start = 0;
let ultimoEstadoOnline = null;
function adicionarEvento(texto, tipo = 'info') {
const feed = el('overviewFeed');
if (!feed) return;
const item = document.createElement('div');
item.style.cssText = 'display:flex;align-items:center;gap:10px;animation:fadeInMsg .2s ease-out';
const cor = tipo === 'online' ? '#10b981' : tipo === 'alerta' ? '#f59e0b' : 'var(--ciano)';
const hora = new Date().toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
item.innerHTML = `
<span class="badge-dot" style="background:${cor};box-shadow:0 0 8px ${cor}"></span>
<span style="color:var(--texto)">${texto}</span>
<span style="margin-left:auto;font-size:11px;font-family:'JetBrains Mono',monospace;color:var(--fraco)">${hora}</span>
`;
feed.prepend(item);
while (feed.children.length > 7) {
feed.removeChild(feed.lastChild);
}
}
async function refresh() {
try {
const [s, c, t] = await Promise.all(['/app/status', '/conversa/status', '/treinamento/status'].map(async p => {
const r = await fetch(p, { cache: 'no-store', signal: AbortSignal.timeout(3000) });
if (!r.ok) throw Error('Servidor indisponível');
return r.json();
}));
// Estado do Celular
if (el('overviewPhone')) {
el('overviewPhone').textContent = s.online ? 'Conectado' : 'Desconectado';
el('overviewPhone').style.color = s.online ? '#34d399' : 'var(--fraco)';
}
if (el('overviewIP')) {
el('overviewIP').textContent = s.celular_ip || (s.online ? 'IP Detectado' : 'Abra o Carinha no celular');
}
// Registra evento de conexão/desconexão
if (ultimoEstadoOnline !== null && ultimoEstadoOnline !== s.online) {
if (s.online) {
adicionarEvento('Galaxy S10 conectado e sincronizado', 'online');
if (window.RobotAudio) window.RobotAudio.happy();
} else {
adicionarEvento('Galaxy S10 desconectou da Central', 'alerta');
}
}
ultimoEstadoOnline = s.online;
// Bateria
if (el('overviewBattery')) {
const nivel = s.online && s.estado?.bateria?.nivel != null ? s.estado.bateria.nivel + '%' : '—';
el('overviewBattery').textContent = nivel;
if (s.estado?.bateria?.nivel != null) {
if (s.estado.bateria.nivel <= 20) {
el('overviewBattery').style.color = '#fb7185';
} else {
el('overviewBattery').style.color = '#f0f6fc';
}
}
}
if (el('overviewCharge')) {
const carregando = s.estado?.bateria?.carregando;
el('overviewCharge').textContent = carregando ? '⚡ Carregando na tomada' : 'Operando na bateria';
el('overviewCharge').style.color = carregando ? 'var(--ciano)' : 'var(--fraco)';
}
// Inteligência IA
if (el('overviewAI')) {
el('overviewAI').textContent = c.provedor === 'gemini' ? 'Google Gemini' : 'Qwen Local';
}
if (el('overviewModel')) {
el('overviewModel').textContent = c.modelo || 'IA Pronta';
}
// Biblioteca de reações
if (el('overviewReactions')) {
el('overviewReactions').textContent = Array.isArray(t.reacoes) ? t.reacoes.length : '0';
}
// Botão de recarga
if (el('overviewReload')) {
el('overviewReload').disabled = !s.online;
}
// Confirmação de recarga remota
if (reload && s.recarga?.id === reload && s.recarga.confirmada) {
el('overviewMessage').textContent = '✅ Tela atualizada: Galaxy S10 confirmou o recarregamento.';
adicionarEvento('Tela do Galaxy S10 recarregada com sucesso', 'online');
reload = null;
} else if (reload && Date.now() - start > 12000) {
el('overviewMessage').textContent = '⚠️ Sem confirmação. Reabra o app Carinha no celular.';
reload = null;
}
} catch (e) {
if (el('overviewMessage')) el('overviewMessage').textContent = e.message;
}
}
// Ação de recarregar a tela do celular
if (el('overviewReload')) {
el('overviewReload').onclick = async () => {
try {
if (window.RobotAudio) window.RobotAudio.click();
const r = await fetch('/app/recarregar', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: '{}'
});
const d = await r.json();
if (!r.ok) throw Error(d.erro);
el('overviewMessage').textContent = d.mensagem;
adicionarEvento('Solicitação de recarga enviada ao celular...');
const s = await (await fetch('/app/status')).json();
reload = s.recarga?.id;
start = Date.now();
} catch (e) {
el('overviewMessage').textContent = 'Erro: ' + e.message;
}
};
}
// Botões de Expressão Rápida (Mood Buttons)
document.querySelectorAll('.btn-mood').forEach(btn => {
btn.onclick = async () => {
const gesto = btn.getAttribute('data-gesto');
if (!gesto) return;
try {
if (window.RobotAudio) window.RobotAudio.tocarGesto(gesto);
await fetch('/gesto/' + encodeURIComponent(gesto));
adicionarEvento(`Expressão disparada: ${gesto}`);
btn.style.transform = 'scale(0.94)';
setTimeout(() => btn.style.transform = '', 160);
} catch (err) {
console.error('Falha ao acionar gesto:', err);
}
};
});
// Botão de Teste Sonoro
if (el('overviewSfxHappy')) {
el('overviewSfxHappy').onclick = () => {
if (window.RobotAudio) {
window.RobotAudio.happy();
adicionarEvento('Sintetizador gerou trinado alegre');
}
};
}
refresh();
setInterval(refresh, 3500);
})();