Objetivo prático da aula
- Entender quando usar gr.Interface vs gr.Blocks.
- Estruturar o app em 3 camadas (io / domínio / ui).
- Implementar upload de CSV/XLSX com validação robusta.
- Criar saídas ricas: métricas + tabela + gráfico.
- Publicar o app no Colab ou Hugging Face Spaces.
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
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 dfApp 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
- Títulos de campos orientados a negócio, não a código ("Taxa de Desconto (%)" em vez de "taxa").
- Valores padrão realistas para reduzir erro de input.
- Textos curtos explicando cada output.
- Botão "Limpar" com estado inicial previsível.
- Limite de tamanho de arquivo aceito para evitar travamentos.
Checklist de entrega
- App funcional com upload de arquivo CSV ou XLSX.
- Validação de colunas obrigatórias com mensagens de erro claras.
- Saída com pelo menos: VPL formatado, TIR e gráfico.
- Código organizado em funções separadas por responsabilidade.
- Link de deploy gerado (Colab share=True ou Hugging Face).