import streamlit as st
import pandas as pd
from sqlalchemy import create_engine
import google.generativeai as genai
import os
from dotenv import load_dotenv
import plotly.express as px
# Carrega as senhas e configurações do arquivo .env
load_dotenv()
# ==========================================
# CONFIGURAÇÃO DE PÁGINA E CABEÇALHO
# ==========================================
st.set_page_config(page_title="Câmara Municipal de Navegantes", page_icon="🔍", layout="wide")
st.title("🔍 Câmara Municipal de Navegantes - Bem-vindo à Navegantes IA")
# Subtítulo centralizado usando HTML/CSS dentro do Markdown
st.markdown("
Inteligência Artificial a serviço da cidadania e da transparência
", unsafe_allow_html=True)
# ==========================================
# BARRA LATERAL (SIDEBAR) - CHAT AO LADO
# ==========================================
with st.sidebar:
# 1. Logótipo da Câmara Municipal
logo_path = os.path.join("assets", "logo_cmn.jpg")
if os.path.exists(logo_path):
st.image(logo_path, use_column_width=True)
# 2. Controlos do Chat
st.header("⚙️ Controles")
if st.button("🗑️ Limpar Histórico de Chat", use_container_width=True, type="primary"):
st.session_state.mensagens = [{"role": "assistant", "content": "Olá! O motor de análise está pronto. De qual parlamentar ou secretaria deseja visualizar a execução orçamentária?"}]
st.rerun()
st.divider()
# 3. Seção de Prompts Sugeridos
st.header("💡 Pergunte à IA da CMN")
st.markdown("*Copie e cole estas perguntas no Chat ao lado e observe as respostas:*")
st.info("🏆 **Visão Macro e Ranking**\n\nConsiderando todos os dados da prefeitura, faça um ranking dos 3 parlamentares que possuem o maior volume financeiro de 'saldo parado'. Qual recomendação institucional você daria à Câmara Municipal como um todo para otimizar essa execução junto ao Executivo?")
st.success("🤝 **Plano de Ação e Articulação**\n\nTraga o relatório do Vereador Marcos Guarezi. Como o valor efetivamente pago está zerado, monte um plano de ação diplomático de 3 passos para o gabinete dele articular a execução técnica junto às secretarias competentes da prefeitura.")
st.warning("📊 **Didática e Literacia Financeira**\n\nAnalise os dados do Vereador Wancarlos. Sabendo que o sistema está em implantação e que os ritos demoram, explique de forma didática a diferença entre o que ele tem empenhado e o que já foi pago. O que o gabinete deve observar agora?")
# ==========================================
# 1. INICIALIZAR O GEMINI
# ==========================================
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
genai.configure(api_key=GOOGLE_API_KEY)
instrucoes_auditor = """
Você é uma Assistente Consultiva de Transparência Pública do município de Navegantes.
Sua missão é traduzir dados orçamentários para o cidadão e para os parlamentares de forma elegante, clara e construtiva.
DIRETRIZES RÍGIDAS DE CONDUTA:
1. FATOS ACIMA DE TUDO: Confie 100% nos números fornecidos nas tabelas. NUNCA invente dados.
2. TOM DIPLOMÁTICO: Abandone tons punitivos. Seja encorajador e institucional. Compreenda que a execução orçamentária possui ritos próprios.
3. MENSAGEM DE CONTEXTO: Inclua sempre uma linha sutil informando que "este sistema de rastreio por Inteligência Artificial está em implantação gradativa, visando auxiliar a transparência e a eficiência municipal".
4. SUGESTÕES PRÁTICAS: Ofereça caminhos construtivos. Sugira articulações entre os gabinetes e as secretarias.
5. FORMATAÇÃO: Respostas curtas, estruturadas em tópicos. Evite usar o símbolo de cifrão ($) repetidas vezes colado em números para não quebrar a formatação visual.
"""
modelo = genai.GenerativeModel(
model_name="gemini-2.5-flash",
system_instruction=instrucoes_auditor,
generation_config={"temperature": 0.0}
)
# ==========================================
# 2. CARREGAR DADOS DAS VIEWS DO GOOGLE CLOUD
# ==========================================
@st.cache_data(ttl=3600)
def carregar_dados_banco():
try:
db_url = os.getenv("DATABASE_URL")
engine = create_engine(db_url)
df_vereadores = pd.read_sql_query('SELECT * FROM vw_auditoria_consolidada', engine)
df_secretarias = pd.read_sql_query('SELECT * FROM vw_auditoria_secretarias', engine)
df_matriz = pd.read_sql_query('SELECT * FROM vw_auditoria_vereador_secretaria', engine)
return df_vereadores, df_secretarias, df_matriz
except Exception as e:
st.error(f"Erro ao conectar ao banco de dados: {e}")
return None, None, None
df_view, df_view_secretarias, df_matriz = carregar_dados_banco()
# ==========================================
# 3. MOTOR DE GRÁFICOS (PLOTLY)
# ==========================================
def renderizar_grafico_vereador(nome_vereador, df_v):
dados = df_v[df_v['vereador'] == nome_vereador]
if not dados.empty:
df_plot = pd.DataFrame({
'Fase da Execução': ['1. Destinado (Câmara)', '2. Empenhado', '3. Pago'],
'Valor (R$)': [
dados['total_destinado_camara'].values[0],
dados['total_empenhado'].values[0],
dados['total_pago'].values[0]
]
})
fig = px.bar(
df_plot,
x='Fase da Execução',
y='Valor (R$)',
color='Fase da Execução',
text_auto='.3s',
title=f"Resumo Financeiro: {nome_vereador}",
color_discrete_sequence=['#3b82f6', '#f59e0b', '#10b981']
)
st.plotly_chart(fig, use_container_width=True)
def renderizar_grafico_secretarias(df_s):
df_plot_s = df_s.sort_values(by='orcamento_atualizado', ascending=False)
fig = px.bar(
df_plot_s,
x='secretaria',
y='orcamento_atualizado',
color='secretaria',
text_auto='.3s',
title="Ranking Orçamentário por Secretaria/Órgão (Orçamento Atualizado)",
labels={'orcamento_atualizado': 'Valor Atualizado (R$)', 'secretaria': 'Secretaria'}
)
fig.update_layout(xaxis_tickangle=-45)
st.plotly_chart(fig, use_container_width=True)
# ==========================================
# 4. INTERFACE E LÓGICA DO AGENTE
# ==========================================
if df_view is not None and df_view_secretarias is not None and df_matriz is not None:
if "mensagens" not in st.session_state:
st.session_state.mensagens = [{"role": "assistant", "content": "Olá! O motor de análise está pronto. De qual parlamentar ou secretaria deseja visualizar a execução orçamentária?"}]
for msg in st.session_state.mensagens:
with st.chat_message(msg["role"]):
st.markdown(msg["content"])
if pergunta := st.chat_input("Ex: Relatório da execução do Vereador Chapecó"):
st.session_state.mensagens.append({"role": "user", "content": pergunta})
with st.chat_message("user"):
st.markdown(pergunta)
with st.chat_message("assistant"):
termos_secretaria = ['secretaria', 'secretarias', 'ranking', 'por pasta', 'executivo']
solicitou_grafico_secretarias = any(termo in pergunta.lower() for termo in termos_secretaria)
solicitou_ranking = "ranking" in pergunta.lower()
vereador_alvo = None
palavras_ignoradas = ['vereador', 'vereadora', 'professor', 'delegada', 'dr', 'dra', 'doutor', 'doutora']
for v in df_view['vereador']:
partes_nome = str(v).lower().split()
partes_uteis = [p for p in partes_nome if p not in palavras_ignoradas and len(p) > 3]
if any(p in pergunta.lower() for p in partes_uteis):
vereador_alvo = v
break
prompt_final = ""
# Prioridade 1: Vereador Específico (Envia o Resumo + O Drill-Down da Matriz)
if vereador_alvo:
renderizar_grafico_vereador(vereador_alvo, df_view)
dados_consolidados = df_view[df_view['vereador'] == vereador_alvo].to_markdown(index=False)
# Filtragem blindada contra espaços e maiúsculas/minúsculas
df_filtrado = df_matriz[df_matriz['vereador'].str.lower().str.strip() == str(vereador_alvo).lower().strip()]
dados_detalhados = df_filtrado.to_markdown(index=False)
prompt_final = f"""
DADOS CONSOLIDADOS DO GABINETE:
{dados_consolidados}
DADOS DETALHADOS (GABINETE x SECRETARIAS):
{dados_detalhados}
PERGUNTA DO USUÁRIO: {pergunta}
"""
# Prioridade 2: Ranking de Secretarias
elif solicitou_grafico_secretarias or solicitou_ranking:
renderizar_grafico_secretarias(df_view_secretarias)
prompt_final = f"""
DADOS POR SECRETARIA (RANKING):
{df_view_secretarias.to_markdown(index=False)}
O usuário solicitou um ranking/gráfico das secretarias municipais. O gráfico já foi gerado.
Redija um parecer comentando este ranking, destacando as pastas com maior Orçamento Atualizado e os maiores saldos parados.
"""
# Prioridade 3: Pergunta Genérica Macro
else:
prompt_final = f"""
DADOS MACRO - POR VEREADOR:
{df_view.to_markdown(index=False)}
DADOS MACRO - POR SECRETARIA/ÓRGÃO:
{df_view_secretarias.to_markdown(index=False)}
MATRIZ COMPLETA DE CRUZAMENTO (VEREADOR x SECRETARIA):
{df_matriz.to_markdown(index=False)}
PERGUNTA DO USUÁRIO: {pergunta}
"""
with st.spinner("A redigir o parecer consultivo..."):
try:
resposta = modelo.generate_content(prompt_final)
st.markdown(resposta.text)
st.session_state.mensagens.append({"role": "assistant", "content": resposta.text})
except Exception as e:
st.error(f"Erro ao consultar a IA: {e}")