diff --git a/app.py b/app.py index 09e3406..6552c38 100644 --- a/app.py +++ b/app.py @@ -1,198 +1,175 @@ -import streamlit as st -import pandas as pd -import time -import os -from datetime import datetime -import pytz -from apscheduler.schedulers.background import BackgroundScheduler -from monitor_logic import run_monitor_check, diagnose_n8n_webhook - -# Carregar timezone da variável de ambiente (padrão: America/Sao_Paulo) -TIMEZONE = os.getenv("TIMEZONE", "America/Sao_Paulo") -tz = pytz.timezone(TIMEZONE) - -# ===== Configuração da Página (DEVE ser a primeira chamada Streamlit!) ===== -st.set_page_config( - page_title="Monitor Evolution API", - page_icon="🤖", - layout="wide" -) - -# Função para gerar tabela HTML customizada -def gerar_tabela_html(logs): - """Gera tabela HTML com estilos inline para garantir funcionamento.""" - if not logs: - return "" - - # Estilos inline - estilo_tabela = "width: 100%; border-collapse: collapse; margin-top: 10px;" - estilo_header = "background-color: #f0f2f6; padding: 12px 15px; text-align: center; font-weight: bold; font-size: 16px; border-bottom: 2px solid #ddd;" - estilo_celula = "padding: 10px 15px; text-align: center; font-size: 14px; border-bottom: 1px solid #eee;" - estilo_celula_detalhes = "padding: 10px 15px; text-align: left; font-size: 14px; border-bottom: 1px solid #eee;" - - html = f'' - - # Cabeçalho - html += '' - html += f'' - html += f'' - html += f'' - html += f'' - html += f'' - html += '' - - # Corpo - html += '' - for log in logs: - html += '' - html += f'' - html += f'' - html += f'' - html += f'' - html += f'' - html += '' - html += '
HoraStatusWhatsAppEmailDetalhes
{log["Hora"]}{log["Status"]}{log["WhatsApp"]}{log["Email"]}{log["Detalhes"]}
' - - return html - -# ===== Inicializar estado da sessão ===== -if 'logs' not in st.session_state: - st.session_state['logs'] = [] - -if 'last_run' not in st.session_state: - st.session_state['last_run'] = "Nunca" - -if 'intervalo_horas' not in st.session_state: - st.session_state['intervalo_horas'] = 3 - -# ===== Função wrapper para o Scheduler gravar logs ===== -def scheduled_job(): - """Executa verificação agendada (roda em background thread).""" - now = datetime.now(tz) - print(f"[{now}] Executando verificação agendada...") - status, messages, whatsapp_status, email_status = run_monitor_check() - print(f"Status: {status} | WhatsApp: {whatsapp_status} | Email: {email_status}") - print("\n".join(messages)) - -# ===== Configurar o Agendador (Singleton via cache_resource) ===== -@st.cache_resource -def init_scheduler(intervalo_horas): - scheduler = BackgroundScheduler(timezone=TIMEZONE) - # Job com intervalo configurável a partir de 00:00 - scheduler.add_job( - scheduled_job, - 'interval', - hours=intervalo_horas, - start_date='2025-01-01 00:00:00' - ) - scheduler.start() - return scheduler - -scheduler = init_scheduler(st.session_state['intervalo_horas']) - -# ===== Interface Principal ===== -st.title("🤖 Monitor Evolution API + Webhook") -st.markdown("---") - -# Métricas superiores -col1, col2 = st.columns(2) - -with col1: - st.metric(label="Última Verificação", value=st.session_state['last_run']) - -with col2: - st.write("### Status Agendador") - intervalo_atual = st.session_state['intervalo_horas'] - st.success(f"✅ Ativo (a cada {intervalo_atual}h desde 00:00)") - -st.markdown("### Ações") - -# Botão de execução manual -if st.button("🚀 Executar Verificação Agora", type="primary"): - with st.spinner('Verificando status dos serviços...'): - status, messages, whatsapp_status, email_status = run_monitor_check() - now = datetime.now(tz) - st.session_state['last_run'] = now.strftime("%H:%M:%S") - - # Adicionar ao histórico de logs - timestamp = now.strftime("%H:%M:%S") - entry = { - "Hora": timestamp, - "Status": "✅ Sucesso" if status else "❌ Erro", - "WhatsApp": whatsapp_status, - "Email": email_status, - "Detalhes": " | ".join(messages) - } - st.session_state['logs'].insert(0, entry) # Adiciona no topo - - if status: - st.success("✅ Todos os serviços estão operacionais!") - else: - st.error("❌ Falha detectada em um ou mais serviços. Verifique os logs.") - -st.markdown("---") -st.markdown("### 📋 Histórico de Execuções (Sessão Atual)") - -if st.session_state['logs']: - # Renderizar tabela HTML customizada - tabela_html = gerar_tabela_html(st.session_state['logs']) - st.markdown(tabela_html, unsafe_allow_html=True) -else: - st.info("ℹ️ Nenhuma verificação executada nesta sessão ainda.") - -# ===== Sidebar ===== -st.sidebar.title("ℹ️ Sobre") -st.sidebar.info( - """ - Este aplicativo monitora: - - 1. **Evolution API**: Verifica se a instância está online. - 2. **N8N Webhook**: Verifica se o endpoint responde. - - **Notificações:** - - ✅ **Sucesso**: Envia WhatsApp. - - ❌ **Erro**: Envia Email. - """ -) - -st.sidebar.markdown("---") - -# Configuração do Intervalo de Disparo -st.sidebar.markdown("### ⏱️ Intervalo de Disparo") -intervalo_slider = st.sidebar.slider( - "Executar a cada (horas):", - min_value=1, - max_value=12, - value=st.session_state['intervalo_horas'], - step=1, - help="Define o intervalo entre execuções automáticas a partir de 00:00" -) - -# Mostrar horários de execução baseados no intervalo -horarios = [f"{h:02d}:00" for h in range(0, 24, intervalo_slider)] -st.sidebar.caption(f"Horários: {', '.join(horarios)}") - -# Verificar se o intervalo mudou -if intervalo_slider != st.session_state['intervalo_horas']: - st.sidebar.warning("⚠️ Reinicie a aplicação para aplicar o novo intervalo.") - st.session_state['intervalo_horas'] = intervalo_slider - -st.sidebar.markdown("---") - -# Diagnóstico N8N na Sidebar -with st.sidebar.expander("🛠️ Diagnóstico N8N"): - st.write("Teste isolado do Webhook N8N") - if st.button("Testar Webhook N8N", key="btn_diag"): - with st.spinner("Enviando POST de teste..."): - success, log_data = diagnose_n8n_webhook() - - if success: - st.success(f"✅ Status: {log_data['status_code']}") - else: - st.error(f"❌ Erro: {log_data.get('status_code') or log_data.get('error')}") - - st.json(log_data) - -# Informações de configuração -st.sidebar.markdown("---") -st.sidebar.caption(f"Intervalo atual: {st.session_state['intervalo_horas']}h") +import os +from datetime import datetime + +import pytz +import streamlit as st +from apscheduler.schedulers.background import BackgroundScheduler + +from monitor_logic import diagnose_n8n_webhook, run_monitor_check + + +# Timezone configuravel via variavel de ambiente (padrao: America/Sao_Paulo) +TIMEZONE = os.getenv("TIMEZONE", "America/Sao_Paulo") +tz = pytz.timezone(TIMEZONE) + + +st.set_page_config( + page_title="Monitor Evolution API", + page_icon="🤖", + layout="wide", +) + + +def gerar_tabela_html(logs): + """Gera tabela HTML com estilos inline para garantir funcionamento.""" + if not logs: + return "" + + estilo_tabela = "width: 100%; border-collapse: collapse; margin-top: 10px;" + estilo_header = ( + "background-color: #f0f2f6; padding: 12px 15px; text-align: center; " + "font-weight: bold; font-size: 16px; border-bottom: 2px solid #ddd;" + ) + estilo_celula = ( + "padding: 10px 15px; text-align: center; font-size: 14px; " + "border-bottom: 1px solid #eee;" + ) + estilo_celula_detalhes = ( + "padding: 10px 15px; text-align: left; font-size: 14px; " + "border-bottom: 1px solid #eee;" + ) + + html = f'' + + html += "" + html += f'' + html += f'' + html += f'' + html += f'' + html += f'' + html += "" + + html += "" + for log in logs: + html += "" + html += f'' + html += f'' + html += f'' + html += f'' + html += f'' + html += "" + html += "
HoraStatusWhatsAppEmailDetalhes
{log["Hora"]}{log["Status"]}{log["WhatsApp"]}{log["Email"]}{log["Detalhes"]}
" + + return html + + +if "logs" not in st.session_state: + st.session_state["logs"] = [] + +if "last_run" not in st.session_state: + st.session_state["last_run"] = "Nunca" + + +def scheduled_job(): + """Executa verificacao agendada (background thread).""" + now = datetime.now(tz) + print(f"[{now}] Executando verificacao agendada...") + status, messages, whatsapp_status, email_status = run_monitor_check() + print(f"Status: {status} | WhatsApp: {whatsapp_status} | Email: {email_status}") + print("\n".join(messages)) + + +@st.cache_resource +def init_scheduler(): + scheduler = BackgroundScheduler(timezone=TIMEZONE) + scheduler.add_job( + scheduled_job, + "cron", + hour=8, + minute=0, + second=0, + id="daily_080000_check", + replace_existing=True, + ) + scheduler.start() + return scheduler + + +scheduler = init_scheduler() + + +st.title("🤖 Monitor Evolution API + Webhook") +st.markdown("---") + +col1, col2 = st.columns(2) + +with col1: + st.metric(label="Ultima Verificacao", value=st.session_state["last_run"]) + +with col2: + st.write("### Status Agendador") + st.success("✅ Ativo (diariamente as 08:00:00 | intervalo 24h)") + +st.markdown("### Acoes") + +if st.button("🚀 Executar Verificacao Agora", type="primary"): + with st.spinner("Verificando status dos servicos..."): + status, messages, whatsapp_status, email_status = run_monitor_check() + now = datetime.now(tz) + st.session_state["last_run"] = now.strftime("%H:%M:%S") + + entry = { + "Hora": now.strftime("%H:%M:%S"), + "Status": "✅ Sucesso" if status else "❌ Erro", + "WhatsApp": whatsapp_status, + "Email": email_status, + "Detalhes": " | ".join(messages), + } + st.session_state["logs"].insert(0, entry) + + if status: + st.success("✅ Todos os servicos estao operacionais!") + else: + st.error("❌ Falha detectada em um ou mais servicos. Verifique os logs.") + +st.markdown("---") +st.markdown("### Historico de Execucoes (Sessao Atual)") + +if st.session_state["logs"]: + tabela_html = gerar_tabela_html(st.session_state["logs"]) + st.markdown(tabela_html, unsafe_allow_html=True) +else: + st.info("ℹ️ Nenhuma verificacao executada nesta sessao ainda.") + + +st.sidebar.title("ℹ️ Sobre") +st.sidebar.info( + """ + Este aplicativo monitora: + + 1. **Evolution API**: Verifica se a instancia esta online. + 2. **N8N Webhook**: Verifica se o endpoint responde. + + **Notificacoes:** + - ✅ **Sucesso**: Envia WhatsApp. + - ❌ **Erro**: Envia Email. + """ +) + +st.sidebar.markdown("---") + +with st.sidebar.expander("🛠️ Diagnostico N8N"): + st.write("Teste isolado do Webhook N8N") + if st.button("Testar Webhook N8N", key="btn_diag"): + with st.spinner("Enviando POST de teste..."): + success, log_data = diagnose_n8n_webhook() + + if success: + st.success(f"✅ Status: {log_data['status_code']}") + else: + st.error(f"❌ Erro: {log_data.get('status_code') or log_data.get('error')}") + + st.json(log_data) + +st.sidebar.markdown("---") +st.sidebar.caption("Disparador automatico: diariamente as 08:00:00 (24h)")