tempagitse / app.py
reiner9's picture
Update app.py
d85d042 verified
Raw
History Blame Contribute Delete
10.7 kB
import gradio as gr
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from io import BytesIO
import tempfile, os
# Configurar estilo
sns.set_style("whitegrid")
plt.rcParams['figure.dpi'] = 100
# Dados históricos
DADOS_HISTORICOS = np.array([11, 17, 7, 4, 5, 8, 6, 10, 11, 15, 11, 4, 8])
class MonteCarloSimulator:
def __init__(self, dados_historicos):
self.dados = dados_historicos
self.media = np.mean(dados_historicos)
self.desvio = np.std(dados_historicos)
def simular(self, n_simulacoes=1000, semanas_futuras=15, meta=100):
np.random.seed(42)
resultados = []
simulacoes_completas = []
for sim in range(n_simulacoes):
entregas_semanais = []
total = 0
semanas_necessarias = 0
for semana in range(semanas_futuras):
entregas = max(0, int(np.random.normal(self.media, self.desvio)))
entregas_semanais.append(entregas)
total += entregas
if total >= meta and semanas_necessarias == 0:
semanas_necessarias = semana + 1
if semanas_necessarias == 0:
semanas_necessarias = semanas_futuras + 1
resultados.append({
'simulacao': sim + 1,
'semanas_necessarias': semanas_necessarias,
'total_entregas': total,
'atingiu_meta': total >= meta
})
simulacoes_completas.append(entregas_semanais)
return pd.DataFrame(resultados), np.array(simulacoes_completas)
def criar_visualizacoes(df_resultados, simulacoes_completas, meta, n_simulacoes):
df_atingiu = df_resultados[df_resultados['atingiu_meta']]
if len(df_atingiu) == 0:
fig, ax = plt.subplots(figsize=(10, 6))
ax.text(0.5, 0.5, 'Nenhuma simulação atingiu a meta.\nTente aumentar o horizonte de semanas.',
ha='center', va='center', fontsize=14, color='red')
ax.axis('off')
return fig
fig = plt.figure(figsize=(18, 12))
gs = fig.add_gridspec(3, 3, hspace=0.35, wspace=0.3)
# 1. Distribuição de semanas necessárias
ax1 = fig.add_subplot(gs[0, :2])
semanas_filtradas = df_atingiu['semanas_necessarias']
ax1.hist(semanas_filtradas, bins=range(1, int(semanas_filtradas.max()) + 2),
edgecolor='black', alpha=0.7, color='steelblue')
ax1.axvline(x=semanas_filtradas.mean(), color='r', linestyle='--', linewidth=2,
label=f'Média: {semanas_filtradas.mean():.1f}')
ax1.axvline(x=semanas_filtradas.median(), color='g', linestyle='--', linewidth=2,
label=f'Mediana: {semanas_filtradas.median():.0f}')
ax1.set_xlabel('Semanas Necessárias', fontsize=11)
ax1.set_ylabel('Frequência', fontsize=11)
ax1.set_title('Distribuição de Semanas para Atingir a Meta', fontsize=13, fontweight='bold')
ax1.legend(fontsize=9)
ax1.grid(True, alpha=0.3)
# 2. Probabilidade acumulada
ax2 = fig.add_subplot(gs[0, 2])
semanas_sorted = np.sort(semanas_filtradas)
prob_acum = np.arange(1, len(semanas_sorted) + 1) / len(semanas_sorted) * 100
ax2.plot(semanas_sorted, prob_acum, linewidth=2, color='darkgreen')
ax2.set_xlabel('Semanas', fontsize=11)
ax2.set_ylabel('Probabilidade (%)', fontsize=11)
ax2.set_title('Prob. Acumulada', fontsize=13, fontweight='bold')
ax2.grid(True, alpha=0.3)
ax2.axhline(y=50, color='r', linestyle='--', alpha=0.5, label='50%')
ax2.axhline(y=90, color='orange', linestyle='--', alpha=0.5, label='90%')
ax2.legend(fontsize=8)
# 3. Boxplot
ax3 = fig.add_subplot(gs[1, 0])
ax3.boxplot(semanas_filtradas, vert=True)
ax3.set_ylabel('Semanas', fontsize=11)
ax3.set_title('Boxplot', fontsize=13, fontweight='bold')
ax3.grid(True, alpha=0.3)
# 4. Taxa de sucesso
ax4 = fig.add_subplot(gs[1, 1])
taxa_sucesso = df_resultados['atingiu_meta'].sum() / len(df_resultados) * 100
taxa_falha = 100 - taxa_sucesso
colors = ['#2ecc71', '#e74c3c']
ax4.pie([taxa_sucesso, taxa_falha], labels=['Atingiu', 'Não Atingiu'],
autopct='%1.1f%%', startangle=90, colors=colors, textprops={'fontsize': 10})
ax4.set_title('Taxa de Sucesso', fontsize=13, fontweight='bold')
# 5. Total de entregas
ax5 = fig.add_subplot(gs[1, 2])
ax5.hist(df_resultados['total_entregas'], bins=30, edgecolor='black', alpha=0.7, color='coral')
ax5.axvline(x=meta, color='r', linestyle='--', linewidth=2, label=f'Meta: {meta}')
ax5.set_xlabel('Total de Entregas', fontsize=11)
ax5.set_ylabel('Frequência', fontsize=11)
ax5.set_title('Distribuição Total', fontsize=13, fontweight='bold')
ax5.legend(fontsize=9)
ax5.grid(True, alpha=0.3)
# 6. Evolução semanal
ax6 = fig.add_subplot(gs[2, :])
n_mostrar = min(100, n_simulacoes)
for i in range(n_mostrar):
entregas_acum = np.cumsum(simulacoes_completas[i])
ax6.plot(range(1, len(entregas_acum) + 1), entregas_acum, alpha=0.08, color='blue')
media_acumulada = np.cumsum(np.mean(simulacoes_completas, axis=0))
ax6.plot(range(1, len(media_acumulada) + 1), media_acumulada,
color='red', linewidth=3, label='Média', zorder=100)
ax6.axhline(y=meta, color='green', linestyle='--', linewidth=2, label=f'Meta: {meta}')
ax6.set_xlabel('Semana', fontsize=11)
ax6.set_ylabel('Entregas Acumuladas', fontsize=11)
ax6.set_title(f'Evolução das Entregas ({n_mostrar} simulações)', fontsize=13, fontweight='bold')
ax6.legend(fontsize=9)
ax6.grid(True, alpha=0.3)
plt.suptitle(f'Simulação de Monte Carlo - {n_simulacoes} Simulações',
fontsize=15, fontweight='bold', y=0.995)
return fig
def gerar_estatisticas(df_resultados, meta):
df_atingiu = df_resultados[df_resultados['atingiu_meta']]
texto = f"""
## 📊 Resultados da Simulação
### 🎯 Meta: {meta} tarefas
### ✅ Taxa de Sucesso
- **Simulações que atingiram a meta:** {df_resultados['atingiu_meta'].sum()} ({df_resultados['atingiu_meta'].sum()/len(df_resultados)*100:.1f}%)
- **Simulações que NÃO atingiram:** {(~df_resultados['atingiu_meta']).sum()} ({(~df_resultados['atingiu_meta']).sum()/len(df_resultados)*100:.1f}%)
"""
if len(df_atingiu) > 0:
p10 = np.percentile(df_atingiu['semanas_necessarias'], 10)
p50 = np.percentile(df_atingiu['semanas_necessarias'], 50)
p90 = np.percentile(df_atingiu['semanas_necessarias'], 90)
texto += f"""
### 📈 Estatísticas de Semanas Necessárias
- **Média:** {df_atingiu['semanas_necessarias'].mean():.2f} semanas
- **Mediana:** {df_atingiu['semanas_necessarias'].median():.0f} semanas
- **Mínimo:** {df_atingiu['semanas_necessarias'].min():.0f} semanas
- **Máximo:** {df_atingiu['semanas_necessarias'].max():.0f} semanas
- **Desvio Padrão:** {df_atingiu['semanas_necessarias'].std():.2f}
### 🎲 Percentis (Probabilidade)
- **10%** das simulações: até **{p10:.0f} semanas**
- **50%** das simulações: até **{p50:.0f} semanas**
- **90%** das simulações: até **{p90:.0f} semanas**
### 💡 Interpretação
Com base em {len(df_resultados)} simulações, há **{df_resultados['atingiu_meta'].sum()/len(df_resultados)*100:.1f}%** de chance de atingir a meta de {meta} tarefas.
Em metade das simulações bem-sucedidas, a meta foi atingida em até **{p50:.0f} semanas**.
"""
else:
texto += "\n\n⚠️ **Nenhuma simulação atingiu a meta no horizonte definido.**\n\nSugestão: Aumente o número de semanas ou revise a meta."
return texto
def simular_monte_carlo(n_simulacoes, semanas_futuras, meta):
# Validações
if n_simulacoes < 10 or n_simulacoes > 1000:
return None, "❌ Número de simulações deve estar entre 10 e 1000", None
if semanas_futuras < 5 or semanas_futuras > 52:
return None, "❌ Número de semanas deve estar entre 5 e 52", None
if meta < 10 or meta > 500:
return None, "❌ Meta deve estar entre 10 e 500 tarefas", None
try:
# Executar simulação
simulador = MonteCarloSimulator(DADOS_HISTORICOS)
df_resultados, simulacoes_completas = simulador.simular(
n_simulacoes=int(n_simulacoes),
semanas_futuras=int(semanas_futuras),
meta=int(meta)
)
# Criar visualizações
fig = criar_visualizacoes(df_resultados, simulacoes_completas, meta, n_simulacoes)
# Gerar estatísticas
stats_text = gerar_estatisticas(df_resultados, meta)
# Criar CSV temporário
temp_dir = tempfile.mkdtemp()
csv_path = os.path.join(temp_dir, "monte_carlo_resultados.csv")
df_resultados.to_csv(csv_path, index=False, encoding='utf-8')
return fig, stats_text, csv_path
except Exception as e:
return None, f"❌ Erro na simulação: {str(e)}", None
# Interface Gradio
with gr.Blocks(title="Simulação de Monte Carlo - Entregas", theme=gr.themes.Soft()) as app:
gr.Markdown("""
# 🎲 Simulação de Monte Carlo - Previsão de Entregas
Esta aplicação simula diferentes cenários para prever **em quantas semanas** uma meta de entregas será atingida,
baseando-se em dados históricos de performance.
""")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### ⚙️ Parâmetros da Simulação")
n_simulacoes = gr.Slider(minimum=10, maximum=1000, value=500, step=10, label="Número de Simulações")
semanas_futuras = gr.Slider(minimum=5, maximum=52, value=15, step=1, label="Horizonte (Semanas)")
meta = gr.Slider(minimum=10, maximum=500, value=100, step=5, label="Meta de Entregas")
btn_simular = gr.Button("🚀 Executar Simulação", variant="primary", size="lg")
with gr.Column(scale=2):
gr.Markdown("### 📈 Resultados")
stats_output = gr.Markdown(label="Estatísticas")
plot_output = gr.Plot(label="Visualizações")
csv_output = gr.File(label="📥 Download Resultados (CSV)")
# Conectar botão à função
btn_simular.click(
fn=simular_monte_carlo,
inputs=[n_simulacoes, semanas_futuras, meta],
outputs=[plot_output, stats_output, csv_output]
)
# Executar aplicação
if __name__ == "__main__":
app.launch()