victormottatz's picture
Upload 4 files
a527900 verified
Raw
History Blame Contribute Delete
10.6 kB
# app.py
import pandas as pd
import requests
import io
import itertools
from collections import defaultdict
import gradio as gr # Importação principal para Gradio
import os # Para variáveis de ambiente, se necessário
# 🔧 CONFIGURAÇÕES GLOBAIS
# O ID da planilha para Consórcio de Automóveis
# Certifique-se de que este FILE_ID esteja acessível publicamente ou para "Qualquer pessoa com o link"
FILE_ID = "1XvNz7DlWioT64uNdcfBSL8Ui2nRSi9gT"
URL = f"https://drive.google.com/uc?export=download&id={FILE_ID}"
# Variável global para armazenar o DataFrame
df = None
def carregar_planilha():
"""Carrega e prepara a planilha para análise de consórcios de automóveis."""
global df
try:
print("⏳ Carregando planilha...")
response = requests.get(URL)
response.raise_for_status()
data = io.BytesIO(response.content)
df = pd.read_excel(data)
# Padroniza nomes das colunas
df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_")
# Converte colunas numéricas
numeric_cols = ['valor_credito', 'valor_entrada', 'valor_parcela', 'saldo_devedor', 'qtd_parcelas']
for col in numeric_cols:
if col in df.columns:
df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
# Verifica colunas essenciais
if 'tipo_do_bem' not in df.columns or 'administradora' not in df.columns:
raise ValueError("Colunas essenciais não encontradas na planilha")
# Remove duplicatas
df.drop_duplicates(inplace=True)
print("✅ Planilha carregada com sucesso!")
return True
except Exception as e:
print(f"❌ Erro ao carregar planilha: {str(e)}")
# Retorne uma mensagem de erro mais útil para o usuário
return False
def agrupar_por_administradora(dataframe):
"""Agrupa cotas por administradora."""
grupos = defaultdict(list)
for _, row in dataframe.iterrows():
grupos[row['administradora']].append(row.to_dict())
return grupos
def buscar_combinacoes(credito_desejado, entrada_desejada, parcela_desejada, administradoras=None):
"""Busca combinações de cotas para automóveis dentro dos parâmetros especificados."""
# Garante que o DataFrame está carregado antes de cada busca
# Isso é útil caso a sessão expire ou o DF seja limpo por algum motivo no servidor do HF.
global df
if df is None:
if not carregar_planilha():
return "❌ Erro: Planilha não carregada. Verifique se o ID do arquivo está correto e público."
# Filtra por tipo de bem (Auto) e administradoras selecionadas
df_filtrado = df[df['tipo_do_bem'].str.lower() == 'auto']
if administradoras:
# Garante que 'administradoras' seja uma lista para o isin()
if isinstance(administradoras, tuple): # Gradio SelectMultiple retorna uma tupla
administradoras = list(administradoras)
df_filtrado = df_filtrado[df_filtrado['administradora'].isin(administradoras)]
if df_filtrado.empty:
return "🚫 Nenhuma cota de automóvel encontrada com os filtros aplicados."
# Define faixas de tolerância
credito_min, credito_max = credito_desejado * 0.93, credito_desejado * 1.07
entrada_min, entrada_max = entrada_desejada * 0.93, entrada_desejada * 1.07
parcela_min, parcela_max = parcela_desejada * 0.5, parcela_desejada * 1.5
grupos = agrupar_por_administradora(df_filtrado)
resultados = []
for adm, cotas in grupos.items():
for r in range(1, min(3, len(cotas)) + 1): # Máximo 3 cotas por combinação
for combinacao in itertools.combinations(cotas, r):
total_credito = sum(c['valor_credito'] for c in combinacao)
total_entrada = sum(c['valor_entrada'] for c in combinacao)
total_parcelas = sum(c['valor_parcela'] for c in combinacao)
if (credito_min <= total_credito <= credito_max and
entrada_min <= total_entrada <= entrada_max and
parcela_min <= total_parcelas <= parcela_max):
total_saldo = sum(c['saldo_devedor'] for c in combinacao)
valor_final = round(total_entrada + total_saldo, 2)
diferenca = abs(valor_final - total_credito)
resultados.append((adm, combinacao, diferenca))
if not resultados:
return "Nenhuma combinação adequada encontrada para automóveis com os parâmetros fornecidos."
resultados.sort(key=lambda x: x[2])
return formatar_resultados(resultados)
def formatar_moeda(valor):
return f"R$ {valor:,.2f}".replace(",", "v").replace(".", ",").replace("v", ".")
def formatar_resultados(resultados):
"""Formata os resultados para exibição."""
resposta = ""
# Limita a 15 resultados para evitar saídas muito longas
for idx, (adm, combinacao, _) in enumerate(resultados[:15], 1):
codigos = [str(c.get('codigo', 'N/A')) for c in combinacao]
total_credito = sum(c['valor_credito'] for c in combinacao)
total_entrada = sum(c['valor_entrada'] for c in combinacao)
total_saldo = sum(c['saldo_devedor'] for c in combinacao)
total_parcelas = sum(c['valor_parcela'] for c in combinacao)
maior_prazo = max(int(c.get('qtd_parcelas', 0)) for c in combinacao)
valor_final = round(total_entrada + total_saldo, 2)
credito_real = round(total_credito - total_entrada, 2)
taxa_total = total_saldo - credito_real
taxa_percentual = (taxa_total / credito_real) * 100 if credito_real > 0 else 0
taxa_mensal = taxa_percentual / maior_prazo if maior_prazo > 0 else 0
resposta += f"""
--- COMBINAÇÃO {idx} ---
🏢 Administradora: {adm}
🔢 Códigos: {', '.join(codigos)}
💰 Crédito Total: {formatar_moeda(total_credito)}
💵 Entrada (+comissão): {formatar_moeda(total_entrada)}
📉 Saldo Devedor: {formatar_moeda(total_saldo)}
💲 Parcela: {formatar_moeda(total_parcelas)}
⏳ Prazo: {maior_prazo} meses
🔚 Valor Final: {formatar_moeda(valor_final)}
💠 Crédito Líquido: {formatar_moeda(credito_real)}
📊 Taxa Total: {taxa_percentual:.2f}% ({formatar_moeda(taxa_total)})
🗓️ Taxa Mensal: {taxa_mensal:.2f}%
🗓️ Taxa Anual: {taxa_mensal * 12:.2f}%
"""
return resposta
# --- INICIALIZAÇÃO PARA GRADIO ---
# Carrega a planilha UMA VEZ no início do aplicativo
# Se der erro, a função de busca tentará carregar novamente.
if not carregar_planilha():
print("⚠️ Aviso: Planilha não carregada na inicialização. Tentará carregar na primeira busca.")
# Prepara as opções para o seletor de administradoras do Gradio
def get_administradoras_options():
if df is not None:
adm_list = df[df['tipo_do_bem'].str.lower() == 'auto']['administradora'].unique()
return sorted(adm_list.tolist()) # Converter para lista, pois .unique() pode retornar um numpy array
return []
# --- Interface Gradio ---
with gr.Blocks(title="Sistema de Busca de Consórcio de Automóveis") as demo:
gr.HTML("""
<link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
<style>
* {
font-family: 'Poppins', sans-serif !important;
}
body {
background-color: #ff8f00 !important;
color: black !important;
}
/* Inputs Numéricos: Crédito, Entrada, Parcela */
input[type="number"] {
background-color: white !important;
border: 2px solid #000 !important;
border-radius: 12px !important;
color: black !important;
padding: 10px !important;
font-weight: 500;
}
/* Inputs de texto e áreas de texto (como a saída e código) */
input[type="text"], textarea {
background-color: white !important;
border: 2px solid black !important;
border-radius: 12px !important;
color: black !important;
padding: 10px !important;
}
input::placeholder, textarea::placeholder {
color: #333 !important;
opacity: 0.7;
}
.gr-checkbox label {
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
}
input[type="checkbox"] {
accent-color: black !important;
width: 18px;
height: 18px;
}
.gr-button {
font-weight: bold;
border-radius: 10px !important;
background-color: white !important;
color: black !important;
border: 2px solid black !important;
}
.gr-button:hover {
background-color: #fff3e0 !important;
color: black !important;
}
label {
font-weight: 600 !important;
}
</style>
""")
gr.Markdown("# 🚗 Sistema de Busca de Combinações de Consórcio (Automóveis)")
gr.Markdown("Preencha os campos abaixo para encontrar as melhores combinações de cotas de consórcio de veículo.")
with gr.Row():
credito_input = gr.Number(label="Crédito Desejado (R$)", value=30000, step=1000, interactive=True)
entrada_input = gr.Number(label="Entrada Desejada (R$)", value=3000, step=100, interactive=True)
parcela_input = gr.Number(label="Parcela Desejada (R$)", value=500, step=10, interactive=True)
administradoras_options = get_administradoras_options()
administradoras_multiselect = gr.CheckboxGroup(
label="Filtrar por Administradoras",
choices=administradoras_options,
value=administradoras_options, # Seleciona todas por padrão
interactive=True
)
submit_btn = gr.Button("🔍 Buscar Combinações", variant="primary")
output_text = gr.Textbox(label="Resultados da Busca", lines=20, max_lines=40, interactive=False, placeholder="Os resultados aparecerão aqui...")
# Conecta o botão à função de busca
submit_btn.click(
fn=buscar_combinacoes,
inputs=[credito_input, entrada_input, parcela_input, administradoras_multiselect],
outputs=output_text
)
gr.Markdown("---")
gr.Markdown("Ferramenta desenvolvida para otimizar a busca por consórcios de automóveis.")
if __name__ == "__main__":
demo.launch() # Você não precisa disso no Colab, mas sim no arquivo que você fará o deploy