import requests
import streamlit as st
import pandas as pd
from datetime import datetime
from storage import StorageHandler
import plotly.express as px
import os
import redis
# Conectar ao Redis
redis_client = redis.Redis(host=os.getenv('REDIS_HOST', 'localhost'), port=int(os.getenv('REDIS_PORT', 6380)), decode_responses=True)
# Função para salvar configurações no Redis
def save_to_redis(key, value):
try:
redis_client.set(key, value)
st.success(f"Configuração {key} salva com sucesso!")
except Exception as e:
st.error(f"Erro ao salvar no Redis: {key} -> {e}")
# Função para buscar configurações no Redis
def get_from_redis(key, default=None):
try:
value = redis_client.get(key)
return value if value is not None else default
except Exception as e:
st.error(f"Erro ao buscar no Redis: {key} -> {e}")
return default
# Função para buscar grupos do Whatsapp
def fetch_whatsapp_groups(server_url, instance, api_key):
url = f"{server_url}/group/fetchAllGroups/{instance}"
headers = {"apikey": api_key}
params = {"getParticipants": "false"} # Adicionando o parâmetro de query
try:
st.write(f"Requisição para URL: {url}") # Debug para URL
st.write(f"Cabeçalhos: {headers}") # Debug para headers
st.write(f"Parâmetros: {params}") # Debug para parâmetros
response = requests.get(url, headers=headers, params=params)
st.write(f"Status Code: {response.status_code}") # Debug para status HTTP
response.raise_for_status() # Levanta exceções HTTP
return response.json() # Retorna o JSON da resposta
except requests.RequestException as e:
st.error(f"Erro ao buscar grupos: {str(e)}")
if response.text:
st.error(f"Resposta do servidor: {response.text}")
return []
# Configuração da página
st.set_page_config(
page_title="TranscreveZAP by Impacte AI",
page_icon="🎙️",
layout="wide",
initial_sidebar_state="expanded",
)
# Estilos CSS personalizados
st.markdown("""
""", unsafe_allow_html=True)
# Configuração do storage
storage = StorageHandler()
# Função para carregar configurações do Redis para o Streamlit
def load_settings():
try:
st.session_state.settings = {
"GROQ_API_KEY": get_from_redis("GROQ_API_KEY", "default_key"),
"BUSINESS_MESSAGE": get_from_redis("BUSINESS_MESSAGE", "*Impacte AI* Premium Services"),
"PROCESS_GROUP_MESSAGES": get_from_redis("PROCESS_GROUP_MESSAGES", "false"),
"PROCESS_SELF_MESSAGES": get_from_redis("PROCESS_SELF_MESSAGES", "true"),
"TRANSCRIPTION_LANGUAGE": get_from_redis("TRANSCRIPTION_LANGUAGE", "pt"),
}
except Exception as e:
st.error(f"Erro ao carregar configurações do Redis: {e}")
# Carregar configurações na sessão, se necessário
if "settings" not in st.session_state:
load_settings()
# Função para salvar configurações do Streamlit no Redis
def save_settings():
try:
save_to_redis("GROQ_API_KEY", st.session_state.groq_api_key)
save_to_redis("BUSINESS_MESSAGE", st.session_state.business_message)
save_to_redis("PROCESS_GROUP_MESSAGES", st.session_state.process_group_messages)
save_to_redis("PROCESS_SELF_MESSAGES", st.session_state.process_self_messages)
st.success("Configurações salvas com sucesso!")
except Exception as e:
st.error(f"Erro ao salvar configurações: {e}")
def show_logo():
try:
logo_path = os.path.join(os.path.dirname(__file__), "static", "fluxo.png")
if os.path.exists(logo_path):
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
st.image(logo_path, width=400, use_column_width=True) # Aumentado e responsivo
else:
st.warning("Logo não encontrada.")
except Exception as e:
st.error(f"Erro ao carregar logo: {e}")
def show_footer():
st.markdown(
"""
""",
unsafe_allow_html=True,
)
def login_page():
show_logo()
st.markdown("TranscreveZAP
", unsafe_allow_html=True)
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
with st.form("login_form"):
st.markdown("Login
", unsafe_allow_html=True)
username = st.text_input('Usuário', key='username')
password = st.text_input('Senha', type='password', key='password')
submit_button = st.form_submit_button('Entrar')
if submit_button:
if username == os.getenv('MANAGER_USER') and password == os.getenv('MANAGER_PASSWORD'):
st.session_state.authenticated = True
st.experimental_rerun()
else:
st.error('Credenciais inválidas')
def dashboard():
show_logo()
st.sidebar.markdown('', unsafe_allow_html=True)
page = st.sidebar.radio(
"Navegação",
["📊 Painel de Controle", "👥 Gerenciar Grupos", "🚫 Gerenciar Bloqueios", "⚙️ Configurações"]
)
if st.sidebar.button("Sair"):
st.session_state.authenticated = False
st.experimental_rerun()
if page == "📊 Painel de Controle":
show_statistics()
elif page == "👥 Gerenciar Grupos":
manage_groups()
elif page == "🚫 Gerenciar Bloqueios":
manage_blocks()
elif page == "⚙️ Configurações":
manage_settings()
def show_statistics():
st.title("📊 Painel de Controle")
try:
stats = storage.get_statistics()
col1, col2, col3 = st.columns(3)
with col1:
st.metric("Total de Áudios Processados", stats.get("total_processed", 0))
with col2:
last_processed = stats.get("last_processed", "Nunca")
st.metric("Último Processamento", last_processed)
with col3:
total_groups = len(storage.get_allowed_groups())
st.metric("Grupos Permitidos", total_groups)
daily_data = stats["stats"]["daily_count"]
if daily_data:
df = pd.DataFrame(list(daily_data.items()), columns=['Data', 'Processamentos'])
df['Data'] = pd.to_datetime(df['Data'])
fig = px.line(df, x='Data', y='Processamentos', title='Processamentos por Dia')
st.plotly_chart(fig, use_container_width=True)
else:
st.info("Ainda não há dados de processamento disponíveis.")
# Adicionar informações sobre o endpoint da API
st.subheader("Endpoint da API")
api_domain = get_from_redis("API_DOMAIN", "seu.dominio.com")
api_endpoint = f"https://{api_domain}/transcreve-audios"
st.code(api_endpoint, language="text")
if st.button("ℹ️ Instruções de Uso"):
st.info(
"Para utilizar o serviço de transcrição, siga estas etapas:\n\n"
"1. Copie a URL completa acima.\n"
"2. Na configuração de webhook da Evolution API:\n"
" - Cole a URL no campo apropriado.\n"
" - Ative o webhook.\n"
" - Marque as opções 'Webhook Base64' e o Evento 'MESSAGES_UPSERT'.\n\n"
"Isso permitirá que a Evolution API envie as mensagens de áudio para o nosso serviço de transcrição."
)
except Exception as e:
st.error(f"Erro ao carregar estatísticas: {e}")
def manage_groups():
st.title("👥 Gerenciar Grupos")
# Campos para inserção dos dados da API
st.subheader("Configuração da API Evolution")
col1, col2, col3 = st.columns(3)
with col1:
server_url = st.text_input("URL do Servidor", value=get_from_redis("EVOLUTION_API_URL", ""))
with col2:
instance = st.text_input("Instância", value=get_from_redis("EVOLUTION_INSTANCE", ""))
with col3:
api_key = st.text_input("API Key", value=get_from_redis("EVOLUTION_API_KEY", ""), type="password")
if st.button("Salvar Configurações da API"):
save_to_redis("EVOLUTION_API_URL", server_url)
save_to_redis("EVOLUTION_INSTANCE", instance)
save_to_redis("EVOLUTION_API_KEY", api_key)
st.success("Configurações da API salvas com sucesso!")
# Busca e exibição de grupos do WhatsApp
if server_url and instance and api_key:
if st.button("Buscar Grupos do WhatsApp"):
with st.spinner('Buscando grupos...'):
groups = fetch_whatsapp_groups(server_url, instance, api_key)
if groups:
st.session_state.whatsapp_groups = groups
st.success(f"{len(groups)} grupos carregados com sucesso!")
else:
st.warning("Nenhum grupo encontrado ou erro ao buscar grupos.")
if 'whatsapp_groups' in st.session_state:
st.subheader("Grupos do WhatsApp")
search_term = st.text_input("Buscar grupos", "")
filtered_groups = [group for group in st.session_state.whatsapp_groups if search_term.lower() in group['subject'].lower()]
for group in filtered_groups:
col1, col2 = st.columns([4, 1])
with col1:
st.text(f"{group['subject']} ({group['id']})")
with col2:
is_allowed = group['id'] in storage.get_allowed_groups()
if st.checkbox("Permitir", value=is_allowed, key=f"allow_{group['id']}"):
if not is_allowed:
storage.add_allowed_group(group['id'])
st.success(f"Grupo {group['subject']} permitido!")
else:
if is_allowed:
storage.remove_allowed_group(group['id'])
st.success(f"Grupo {group['subject']} removido!")
else:
st.info("Por favor, insira as configurações da API Evolution para buscar os grupos.")
# Adicionar grupo manualmente
st.subheader("Adicionar Grupo Manualmente")
new_group = st.text_input("Número do Grupo", placeholder="Ex: 5521999999999")
if st.button("Adicionar"):
formatted_group = f"{new_group}@g.us"
storage.add_allowed_group(formatted_group)
st.success(f"Grupo {formatted_group} adicionado com sucesso!")
st.experimental_rerun()
# Lista de grupos permitidos
st.subheader("Grupos Permitidos")
allowed_groups = storage.get_allowed_groups()
if allowed_groups:
for group in allowed_groups:
col1, col2 = st.columns([4, 1])
with col1:
st.text(group)
with col2:
if st.button("Remover", key=f"remove_{group}"):
storage.remove_allowed_group(group)
st.success(f"Grupo {group} removido!")
st.experimental_rerun()
else:
st.info("Nenhum grupo permitido.")
def manage_blocks():
st.title("🚫 Gerenciar Bloqueios")
st.subheader("Bloquear Usuário")
col1, col2 = st.columns([3, 1])
with col1:
new_user = st.text_input("Número do Usuário", placeholder="Ex: 5521999999999")
with col2:
if st.button("Bloquear"):
formatted_user = f"{new_user}@s.whatsapp.net"
storage.add_blocked_user(formatted_user)
st.success(f"Usuário {formatted_user} bloqueado!")
st.experimental_rerun()
st.subheader("Usuários Bloqueados")
blocked_users = storage.get_blocked_users()
if blocked_users:
for user in blocked_users:
col1, col2 = st.columns([4, 1])
with col1:
st.text(user)
with col2:
if st.button("Desbloquear", key=f"unblock_{user}"):
storage.remove_blocked_user(user)
st.success(f"Usuário {user} desbloqueado!")
st.experimental_rerun()
else:
st.info("Nenhum usuário bloqueado.")
def manage_settings():
st.title("⚙️ Configurações")
st.subheader("Configurações do Sistema")
# Seção de chaves GROQ com sistema de rodízio
st.subheader("🔑 Gerenciamento de Chaves GROQ")
# Campo para chave principal (mantendo compatibilidade)
main_key = st.text_input(
"GROQ API Key Principal",
value=st.session_state.settings["GROQ_API_KEY"],
key="groq_api_key",
type="password",
help="Chave GROQ principal do sistema"
)
# Seção de chaves adicionais
st.markdown("---")
st.subheader("Chaves GROQ Adicionais (Sistema de Rodízio)")
# Exibir chaves existentes
groq_keys = storage.get_groq_keys()
if groq_keys:
st.write("Chaves configuradas para rodízio:")
for key in groq_keys:
col1, col2 = st.columns([4, 1])
with col1:
masked_key = f"{key[:10]}...{key[-4:]}"
st.code(masked_key, language=None)
with col2:
if st.button("🗑️", key=f"remove_{key}", help="Remover esta chave"):
storage.remove_groq_key(key)
st.success(f"Chave removida do rodízio!")
st.experimental_rerun()
# Adicionar nova chave
new_key = st.text_input(
"Adicionar Nova Chave GROQ",
key="new_groq_key",
type="password",
help="Insira uma nova chave GROQ para adicionar ao sistema de rodízio"
)
col1, col2 = st.columns([4, 1])
with col1:
if st.button("➕ Adicionar ao Rodízio", help="Adicionar esta chave ao sistema de rodízio"):
if new_key:
if new_key.startswith("gsk_"):
storage.add_groq_key(new_key)
st.success("Nova chave adicionada ao sistema de rodízio!")
st.experimental_rerun()
else:
st.error("Chave inválida! A chave deve começar com 'gsk_'")
else:
st.warning("Por favor, insira uma chave válida")
# Outras configurações do sistema
st.markdown("---")
st.subheader("Outras Configurações")
# Business Message
st.text_input(
"Mensagem de Serviço no Rodapé",
value=st.session_state.settings["BUSINESS_MESSAGE"],
key="business_message"
)
# Process Group Messages
st.selectbox(
"Processar Mensagens em Grupos",
options=["true", "false"],
index=["true", "false"].index(st.session_state.settings["PROCESS_GROUP_MESSAGES"]),
key="process_group_messages"
)
# Process Self Messages
st.selectbox(
"Processar Mensagens Próprias",
options=["true", "false"],
index=["true", "false"].index(st.session_state.settings["PROCESS_SELF_MESSAGES"]),
key="process_self_messages"
)
# Nova seção de configuração de idioma
st.markdown("---")
st.subheader("🌐 Configuração de Idioma")
# Dicionário de idiomas em português
IDIOMAS = {
"pt": "Português",
"en": "Inglês",
"es": "Espanhol",
"fr": "Francês",
"de": "Alemão",
"it": "Italiano",
"ja": "Japonês",
"ko": "Coreano",
"zh": "Chinês",
"ro": "Romeno",
"ru": "Russo",
"ar": "Árabe",
"hi": "Hindi",
"nl": "Holandês",
"pl": "Polonês",
"tr": "Turco"
}
# Carregar configuração atual de idioma
current_language = get_from_redis("TRANSCRIPTION_LANGUAGE", "pt")
# Seleção de idioma
selected_language = st.selectbox(
"Idioma para Transcrição e Resumo",
options=list(IDIOMAS.keys()),
format_func=lambda x: IDIOMAS[x],
index=list(IDIOMAS.keys()).index(current_language) if current_language in IDIOMAS else 0,
help="Selecione o idioma para transcrição dos áudios e geração dos resumos",
key="transcription_language"
)
# Botão de salvar com feedback visual
if st.button("💾 Salvar Todas as Configurações"):
try:
# Salvar configurações principais
save_settings()
# Se há uma chave principal, adicionar ao sistema de rodízio
if main_key and main_key.startswith("gsk_"):
storage.add_groq_key(main_key)
# Salvar configuração de idioma
save_to_redis("TRANSCRIPTION_LANGUAGE", selected_language)
st.success("✅ Todas as configurações foram salvas com sucesso!")
# Mostrar resumo das chaves ativas e idioma selecionado
total_keys = len(storage.get_groq_keys())
st.info(f"""Sistema configurado com {total_keys} chave(s) GROQ no rodízio
Idioma definido: {IDIOMAS[selected_language]}""")
except Exception as e:
st.error(f"Erro ao salvar configurações: {str(e)}")
if "authenticated" not in st.session_state:
st.session_state.authenticated = False
if st.session_state.authenticated:
dashboard()
else:
login_page()
show_footer()