Sobre este encontro

Relatórios Automatizados com Python · Prof. Afonso

Objetivo de aprendizagem

Ao final do encontro, o estudante deve ser capaz de aplicar ao projeto os conceitos de Relatórios Automatizados com Python. Escopo do encontro: Crie relatórios financeiros automatizados e profissionais com Python.

Estratégia do encontro

Exposição dialogada dos conceitos, alternada com aplicação guiada ao projeto do grupo, e fechamento com verificação do entendimento.

Estrutura do encontro

  1. Você vai sair com um app melhor que "só funciona"
  2. Bloco inicial obrigatório
  3. Quando usar `gr.Interface`
  4. Quando o app cresce, use `gr.Blocks`
  5. Separação em 3 camadas
  6. Tratar diferentes formatos sem quebrar o app
  7. Valide antes de calcular
  8. Não devolva só um número

Objetivo prático da aula

Setup mínimo no Colab

!pip install gradio pandas numpy plotly openpyxl -q

import pandas as pd
import numpy as np
import plotly.express as px
import gradio as gr

Boa prática: versão de dependências no topo da primeira célula e imports agrupados.

App mínimo: gr.Interface

def calcular_simples(investimento, taxa, fluxo_anual, anos):
    fcls = [fluxo_anual] * int(anos)
    vpl = -investimento + sum(fc / ((1 + taxa) ** (i + 1))
                              for i, fc in enumerate(fcls))
    return f"VPL: R$ {vpl:,.2f}"

app = gr.Interface(
    fn=calcular_simples,
    inputs=[
        gr.Number(label="Investimento inicial"),
        gr.Slider(0.01, 0.5, value=0.14, step=0.01, label="Taxa de desconto"),
        gr.Number(label="Fluxo anual"),
        gr.Slider(1, 10, value=5, step=1, label="Anos")
    ],
    outputs=gr.Textbox(label="Resultado")
)
app.launch()

Arquitetura em 3 camadas

io_data.py — leitura de CSV/XLSX e limpeza de dados
service_finance.py — regras de negócio: VPL, TIR, Payback
ui_gradio.py — layout Gradio: inputs, eventos, outputs

Regra: a função de negócio não importa Gradio. Ela recebe dados Python e retorna dados Python.

Upload de arquivos com tratamento de erros

def carregar_arquivo(file_obj):
    if file_obj is None:
        raise ValueError("Envie um arquivo CSV ou XLSX.")

    nome = file_obj.name.lower()
    if nome.endswith(".csv"):
        df = pd.read_csv(file_obj.name)
    elif nome.endswith(".xlsx"):
        df = pd.read_excel(file_obj.name)
    else:
        raise ValueError("Formato invalido. Use CSV ou XLSX.")

    # Padronizar nomes de colunas
    df.columns = [c.strip().lower() for c in df.columns]

    # Validar colunas obrigatórias
    obrigatorias = ["ano", "receita", "custos", "investimento"]
    faltantes = [c for c in obrigatorias if c not in df.columns]
    if faltantes:
        raise ValueError(f"Colunas ausentes: {faltantes}")

    return df

App completo com gr.Blocks

def processar(file_obj, taxa_pct):
    df = carregar_arquivo(file_obj)
    taxa = float(taxa_pct) / 100
    # ... calcular VPL, TIR, montar tabela e gráfico ...
    fig = px.bar(df, x="ano", y="vp_fcl", title="Valor presente por ano")
    return mensagem, df_resultado, fig

with gr.Blocks(theme=gr.themes.Soft()) as demo:
    gr.Markdown("# Analise de Investimento — Projeto 5")
    with gr.Row():
        arquivo_input = gr.File(label="Envie CSV ou XLSX", file_types=[".csv", ".xlsx"])
        taxa_input = gr.Number(label="Taxa de Desconto (%)", value=14)
    with gr.Row():
        botao_calcular = gr.Button("Calcular", variant="primary")
        botao_limpar = gr.Button("Limpar")
    mensagem_out = gr.Textbox(label="Resultado")
    tabela_out = gr.Dataframe(label="Detalhamento")
    grafico_out = gr.Plot(label="Visualizacao")

    botao_calcular.click(
        fn=processar,
        inputs=[arquivo_input, taxa_input],
        outputs=[mensagem_out, tabela_out, grafico_out]
    )
    botao_limpar.click(
        fn=lambda: ("", None, None),
        inputs=[],
        outputs=[mensagem_out, tabela_out, grafico_out]
    )

demo.queue(max_size=20)
demo.launch(share=True)

5 ajustes de alto impacto no UX

  1. Títulos de campos orientados a negócio, não a código ("Taxa de Desconto (%)" em vez de "taxa").
  2. Valores padrão realistas para reduzir erro de input.
  3. Textos curtos explicando cada output.
  4. Botão "Limpar" com estado inicial previsível.
  5. Limite de tamanho de arquivo aceito para evitar travamentos.

Checklist de entrega