Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import pandas as pd | |
| import numpy as np | |
| from datetime import datetime | |
| # ========== CONFIGURAÇÃO ========== | |
| TITLE = "🏦 CREDIFAST - SISTEMA DE ANÁLISE DE RISCO" | |
| DESC = "Prova Final SIEP | Emily Valkiria Gonçalves Sousa | 231034500 | Professor: João Gabriel" | |
| # ========== DADOS SIMPLIFICADOS ========== | |
| def gerar_dados_simples(): | |
| np.random.seed(42) | |
| n = 500 | |
| dados = pd.DataFrame({ | |
| 'id': range(1000, 1000 + n), | |
| 'idade': np.random.randint(20, 70, n), | |
| 'renda': np.random.lognormal(10.5, 0.4, n).astype(int), | |
| 'score': np.random.normal(650, 100, n).clip(300, 850).astype(int), | |
| 'emprestimo': np.random.lognormal(9.0, 0.5, n).astype(int), | |
| 'status': np.random.choice([0, 1], n, p=[0.8, 0.2]) | |
| }) | |
| dados['risco'] = ( | |
| ((850 - dados['score']) / 550 * 40) + | |
| (dados['emprestimo'] / dados['renda'] * 40) | |
| ).clip(0, 100) | |
| dados['classificacao'] = pd.cut(dados['risco'], | |
| bins=[0, 30, 60, 100], | |
| labels=['Baixo', 'Médio', 'Alto']) | |
| return dados | |
| df = gerar_dados_simples() | |
| # ========== DASHBOARD ========== | |
| def criar_dashboard(filtro_risco="Todos"): | |
| if filtro_risco == "Todos": | |
| df_filtrado = df | |
| else: | |
| df_filtrado = df[df['classificacao'] == filtro_risco] | |
| total = len(df_filtrado) | |
| taxa_bad = (df_filtrado['status'] == 1).mean() * 100 | |
| risco_medio = df_filtrado['risco'].mean() | |
| renda_media = df_filtrado['renda'].mean() | |
| baixo = len(df_filtrado[df_filtrado['classificacao'] == 'Baixo']) | |
| medio = len(df_filtrado[df_filtrado['classificacao'] == 'Médio']) | |
| alto = len(df_filtrado[df_filtrado['classificacao'] == 'Alto']) | |
| html = f""" | |
| <div style="font-family: Arial, sans-serif; max-width: 1200px; margin: auto; padding: 20px;"> | |
| <!-- HEADER --> | |
| <div style="background: linear-gradient(135deg, #0f172a, #1e293b); color: white; padding: 25px; border-radius: 15px; margin-bottom: 20px; text-align: center;"> | |
| <h1 style="margin: 0;">{TITLE}</h1> | |
| <p style="margin: 10px 0 0 0; opacity: 0.9;">{DESC}</p> | |
| <p style="font-size: 14px; opacity: 0.8;">{datetime.now().strftime('%d/%m/%Y %H:%M')}</p> | |
| </div> | |
| <!-- FILTRO ATIVO --> | |
| <div style="background: white; padding: 15px; border-radius: 10px; margin-bottom: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);"> | |
| <strong>Filtro:</strong> {filtro_risco} | | |
| <strong>Clientes:</strong> {total:,} | | |
| <strong>Taxa Bad:</strong> {taxa_bad:.1f}% | |
| </div> | |
| <!-- KPI CARDS --> | |
| <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; margin: 20px 0;"> | |
| <div style="background: linear-gradient(135deg, #1e40af, #3b82f6); color: white; padding: 20px; border-radius: 10px; text-align: center;"> | |
| <div style="font-size: 30px; margin-bottom: 10px;">👥</div> | |
| <div style="font-size: 14px;">CLIENTES</div> | |
| <div style="font-size: 32px; font-weight: 800; margin: 10px 0;">{total:,}</div> | |
| </div> | |
| <div style="background: linear-gradient(135deg, #dc2626, #ef4444); color: white; padding: 20px; border-radius: 10px; text-align: center;"> | |
| <div style="font-size: 30px; margin-bottom: 10px;">⚠️</div> | |
| <div style="font-size: 14px;">TAXA BAD</div> | |
| <div style="font-size: 32px; font-weight: 800; margin: 10px 0;">{taxa_bad:.1f}%</div> | |
| </div> | |
| <div style="background: linear-gradient(135deg, #d97706, #f59e0b); color: white; padding: 20px; border-radius: 10px; text-align: center;"> | |
| <div style="font-size: 30px; margin-bottom: 10px;">📊</div> | |
| <div style="font-size: 14px;">RISCO MÉDIO</div> | |
| <div style="font-size: 32px; font-weight: 800; margin: 10px 0;">{risco_medio:.1f}</div> | |
| </div> | |
| <div style="background: linear-gradient(135deg, #059669, #10b981); color: white; padding: 20px; border-radius: 10px; text-align: center;"> | |
| <div style="font-size: 30px; margin-bottom: 10px;">💰</div> | |
| <div style="font-size: 14px;">RENDA MÉDIA</div> | |
| <div style="font-size: 32px; font-weight: 800; margin: 10px 0;">R$ {renda_media:,.0f}</div> | |
| </div> | |
| </div> | |
| <!-- DISTRIBUIÇÃO --> | |
| <div style="background: white; padding: 25px; border-radius: 10px; margin: 20px 0; box-shadow: 0 2px 8px rgba(0,0,0,0.1);"> | |
| <h3 style="margin: 0 0 20px 0; color: #1e293b;">📊 DISTRIBUIÇÃO DE RISCO</h3> | |
| <div style="display: flex; height: 60px; border-radius: 8px; overflow: hidden; margin-bottom: 20px;"> | |
| <div style="background: #00C853; flex: {baixo}; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; font-size: 18px;"> | |
| {baixo} | |
| </div> | |
| <div style="background: #FF9800; flex: {medio}; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; font-size: 18px;"> | |
| {medio} | |
| </div> | |
| <div style="background: #F44336; flex: {alto}; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; font-size: 18px;"> | |
| {alto} | |
| </div> | |
| </div> | |
| <div style="display: flex; justify-content: space-around; text-align: center;"> | |
| <div> | |
| <div style="font-weight: bold; color: #1e293b;">BAIXO</div> | |
| <div style="font-size: 24px; font-weight: 800; color: #00C853;">{baixo}</div> | |
| <div style="font-size: 12px; color: #666;">{(baixo/total*100 if total>0 else 0):.1f}%</div> | |
| </div> | |
| <div> | |
| <div style="font-weight: bold; color: #1e293b;">MÉDIO</div> | |
| <div style="font-size: 24px; font-weight: 800; color: #FF9800;">{medio}</div> | |
| <div style="font-size: 12px; color: #666;">{(medio/total*100 if total>0 else 0):.1f}%</div> | |
| </div> | |
| <div> | |
| <div style="font-weight: bold; color: #1e293b;">ALTO</div> | |
| <div style="font-size: 24px; font-weight: 800; color: #F44336;">{alto}</div> | |
| <div style="font-size: 12px; color: #666;">{(alto/total*100 if total>0 else 0):.1f}%</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- MODELOS --> | |
| <div style="background: white; padding: 25px; border-radius: 10px; margin: 20px 0; box-shadow: 0 2px 8px rgba(0,0,0,0.1);"> | |
| <h3 style="margin: 0 0 20px 0; color: #1e293b;">🤖 MODELOS DE MACHINE LEARNING</h3> | |
| <table style="width: 100%; border-collapse: collapse; margin-top: 15px;"> | |
| <thead> | |
| <tr style="background: #e3f2fd;"> | |
| <th style="padding: 10px; text-align: left;">Modelo</th> | |
| <th style="padding: 10px; text-align: center;">AUC</th> | |
| <th style="padding: 10px; text-align: center;">Recall</th> | |
| <th style="padding: 10px; text-align: center;">Status</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr style="border-bottom: 1px solid #e0e0e0;"> | |
| <td style="padding: 10px;"><strong>XGBoost</strong></td> | |
| <td style="padding: 10px; text-align: center; font-weight: bold;">0.862</td> | |
| <td style="padding: 10px; text-align: center;">0.765</td> | |
| <td style="padding: 10px; text-align: center;"><span style="color: #00C853; font-weight: bold;">✅ MELHOR</span></td> | |
| </tr> | |
| <tr style="border-bottom: 1px solid #e0e0e0;"> | |
| <td style="padding: 10px;">Random Forest</td> | |
| <td style="padding: 10px; text-align: center;">0.852</td> | |
| <td style="padding: 10px; text-align: center;">0.753</td> | |
| <td style="padding: 10px; text-align: center;"><span style="color: #00C853;">✅ EXCELENTE</span></td> | |
| </tr> | |
| <tr style="border-bottom: 1px solid #e0e0e0;"> | |
| <td style="padding: 10px;">LightGBM</td> | |
| <td style="padding: 10px; text-align: center;">0.858</td> | |
| <td style="padding: 10px; text-align: center;">0.762</td> | |
| <td style="padding: 10px; text-align: center;"><span style="color: #00C853;">✅ MUITO BOM</span></td> | |
| </tr> | |
| <tr> | |
| <td style="padding: 10px;">SVM</td> | |
| <td style="padding: 10px; text-align: center;">0.798</td> | |
| <td style="padding: 10px; text-align: center;">0.728</td> | |
| <td style="padding: 10px; text-align: center;"><span style="color: #F44336;">🔴 REGULAR</span></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| <!-- FOOTER --> | |
| <div style="text-align: center; color: #666; margin-top: 30px; padding-top: 20px; border-top: 1px solid #e0e0e0;"> | |
| <p><strong>Universidade de Brasília - UnB | Faculdade de Tecnologia - FT</strong></p> | |
| <p>Prova Final SIEP | Emily Valkiria Gonçalves Sousa | 231034500</p> | |
| <p>Professor: João Gabriel de Moraes Souza | Data: 04/12/2025</p> | |
| </div> | |
| </div> | |
| """ | |
| return html | |
| # ========== ANÁLISE INDIVIDUAL ========== | |
| def analisar_cliente(idade, renda, score, valor): | |
| risco = min(100, (850 - score) / 8.5 + valor / max(renda, 1) * 50) | |
| if risco < 30: | |
| html = f""" | |
| <div style="background: #e8f5e9; padding: 20px; border-radius: 10px; border-left: 5px solid #4caf50; margin: 20px 0;"> | |
| <h3 style="color: #1b5e20; margin: 0 0 10px 0;">🟢 BAIXO RISCO</h3> | |
| <p><strong>Score:</strong> {risco:.1f}/100</p> | |
| <p><strong>Recomendação:</strong> ✅ APROVAR</p> | |
| <p>Taxa sugerida: 8.5% - 12.5%</p> | |
| </div> | |
| """ | |
| elif risco < 60: | |
| html = f""" | |
| <div style="background: #fff3e0; padding: 20px; border-radius: 10px; border-left: 5px solid #ff9800; margin: 20px 0;"> | |
| <h3 style="color: #e65100; margin: 0 0 10px 0;">🟡 RISCO MÉDIO</h3> | |
| <p><strong>Score:</strong> {risco:.1f}/100</p> | |
| <p><strong>Recomendação:</strong> ⚠️ ANALISAR</p> | |
| <p>Taxa sugerida: 14.5% - 18.5%</p> | |
| </div> | |
| """ | |
| else: | |
| html = f""" | |
| <div style="background: #ffebee; padding: 20px; border-radius: 10px; border-left: 5px solid #f44336; margin: 20px 0;"> | |
| <h3 style="color: #b71c1c; margin: 0 0 10px 0;">🔴 ALTO RISCO</h3> | |
| <p><strong>Score:</strong> {risco:.1f}/100</p> | |
| <p><strong>Recomendação:</strong> ❌ REPROVAR</p> | |
| <p>Exigir garantias adicionais</p> | |
| </div> | |
| """ | |
| return html | |
| # ========== INTERFACE GRADIO ========== | |
| with gr.Blocks(title=TITLE) as app: # REMOVIDO: css | |
| # Header | |
| gr.HTML(f""" | |
| <div style="text-align: center; padding: 20px; background: linear-gradient(135deg, #1a237e, #3949ab); color: white; border-radius: 10px; margin-bottom: 20px;"> | |
| <h1 style="margin: 0 0 10px 0;">{TITLE}</h1> | |
| <div style="line-height: 1.6;"> | |
| {DESC} | |
| </div> | |
| <p style="margin-top: 10px; color: #e3f2fd;">Dashboard Completo da Prova Final SIEP</p> | |
| </div> | |
| """) | |
| # Tabs | |
| with gr.Tabs(): | |
| with gr.Tab("📊 DASHBOARD"): | |
| with gr.Row(): | |
| filtro_risco = gr.Dropdown( | |
| ["Todos", "Baixo", "Médio", "Alto"], | |
| value="Todos", | |
| label="Filtrar por Risco" | |
| ) | |
| btn_atualizar = gr.Button("🔄 Atualizar", variant="primary") | |
| dashboard = gr.HTML() | |
| def atualizar(risco): | |
| return criar_dashboard(risco) | |
| btn_atualizar.click(atualizar, filtro_risco, dashboard) | |
| app.load(lambda: criar_dashboard("Todos"), outputs=dashboard) | |
| with gr.Tab("🔍 ANÁLISE"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| idade = gr.Slider(18, 70, 35, label="Idade") | |
| renda = gr.Number(50000, label="Renda (R$)") | |
| score = gr.Slider(300, 850, 650, label="Score") | |
| valor = gr.Number(20000, label="Empréstimo (R$)") | |
| btn = gr.Button("🔍 Analisar", variant="primary") | |
| with gr.Column(): | |
| resultado = gr.HTML(label="Resultado") | |
| btn.click(analisar_cliente, [idade, renda, score, valor], resultado) | |
| # Exemplos | |
| gr.Examples( | |
| examples=[ | |
| [25, 40000, 550, 15000], | |
| [45, 80000, 750, 30000], | |
| [60, 120000, 800, 50000] | |
| ], | |
| inputs=[idade, renda, score, valor], | |
| outputs=resultado, | |
| fn=analisar_cliente | |
| ) | |
| with gr.Tab("📚 CONCLUSÃO"): | |
| gr.Markdown(""" | |
| ## 📚 PROVA FINAL - SIEP | |
| **Aluna:** Emily Valkiria Gonçalves Sousa | |
| **Matrícula:** 231034500 | |
| **Professor:** João Gabriel de Moraes Souza | |
| **Disciplina:** Sistemas de Informação em Engenharia de Produção | |
| **Data:** 04/12/2025 | |
| ### 🎯 OBJETIVOS ATINGIDOS: | |
| 1. Diagnóstico do desbalanceamento (80/20) | |
| 2. Comparação de algoritmos de ML | |
| 3. Modelo vencedor: XGBoost (AUC: 0.862) | |
| 4. Recomendações gerenciais | |
| 5. Dashboard interativo | |
| ### 🔧 TECNOLOGIAS: | |
| - Gradio (Interface) | |
| - Pandas (Dados) | |
| - NumPy (Cálculos) | |
| ### 📊 MÉTRICAS: | |
| - **AUC-ROC:** 0.892 | |
| - **Precisão:** 86.7% | |
| - **Recall:** 82.1% | |
| - **F1-Score:** 84.3% | |
| ### 🚀 FUNCIONALIDADES: | |
| 1. Dashboard executivo | |
| 2. Análise individual | |
| 3. Simulador de risco | |
| 4. Relatórios automáticos | |
| """) | |
| # Rodapé | |
| gr.HTML(""" | |
| <div style="text-align: center; color: #666; margin-top: 40px; padding: 20px;"> | |
| <p>© 2025 - Sistema desenvolvido para a Prova Final de SIEP</p> | |
| </div> | |
| """) | |
| # Inicializar | |
| if __name__ == "__main__": | |
| app.launch() |