import os os.environ["GRADIO_ANALYTICS_ENABLED"] = "False" os.environ["HF_HUB_DISABLE_TELEMETRY"] = "1" import pandas as pd import requests import io import itertools from collections import defaultdict import gradio as gr # 🔥 NOVO: import do middleware CORS do FastAPI (usado internamente pelo Gradio) from fastapi.middleware.cors import CORSMiddleware # 🔧 CONFIGURAÇÕES DO ARQUIVO FILE_ID = "1EoH8V3Fyls0mNa95VcBN6ZL1B552ty3X" URL = f"https://drive.google.com/uc?export=download&id={FILE_ID}" # Variáveis globais df_auto = None grupos_auto = None planilha_carregada = False ADMIN_OPCOES = [] def carregar_planilha(): global df_auto, grupos_auto, planilha_carregada, ADMIN_OPCOES if planilha_carregada: return True try: print("⏳ Carregando planilha de automóveis...") response = requests.get(URL) response.raise_for_status() data = io.BytesIO(response.content) df = pd.read_excel(data) df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_") colunas_numericas = ['valor_credito', 'valor_entrada', 'valor_parcela', 'saldo_devedor', 'qtd_parcelas'] for col in colunas_numericas: if col in df.columns: df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0) if 'tipo_do_bem' not in df.columns or 'administradora' not in df.columns: raise ValueError("Colunas essenciais não encontradas") df.drop_duplicates(inplace=True) df_auto = df[df['tipo_do_bem'].str.lower() == 'auto'].copy() df_auto['administradora'] = df_auto['administradora'].astype(str).str.strip().str.lower() df_auto = df_auto[df_auto['administradora'].notna() & (df_auto['administradora'] != '')] grupos_auto = defaultdict(list) for _, row in df_auto.iterrows(): grupos_auto[row['administradora']].append(row.to_dict()) ADMIN_OPCOES = sorted(df_auto['administradora'].unique()) planilha_carregada = True print(f"✅ Total de cotas AUTO: {len(df_auto)}") print(f"✅ Administradoras AUTO: {ADMIN_OPCOES}") return True except Exception as e: print(f"❌ Erro ao carregar planilha AUTO: {e}") return False def formatar_moeda(valor): return f"R$ {valor:,.2f}".replace(",", "v").replace(".", ",").replace("v", ".") def definir_margens_absolutas(credito, entrada, parcela): margem_credito = 20_000 # ex.: 30.000 → 10.000–50.000 margem_entrada = 2_000 margem_parcela = 100 cred_min = max(0, credito - margem_credito) cred_max = credito + margem_credito ent_min = max(0, entrada - margem_entrada) ent_max = entrada + margem_entrada parc_min = max(0, parcela - margem_parcela) parc_max = parcela + margem_parcela return cred_min, cred_max, ent_min, ent_max, parc_min, parc_max def filtrar_cotas_por_faixa(cotas, cred_min, cred_max): return [c for c in cotas if c['valor_credito'] < cred_max * 2] def calcular_tempo_parcelas(combinacao): if not combinacao: return "" try: cotas_ordenadas = sorted(combinacao, key=lambda x: int(x.get('qtd_parcelas', 0))) prazos = sorted(set(int(c.get('qtd_parcelas', 0)) for c in combinacao)) if not prazos or prazos[0] <= 0: return "" resultado = [] prazo_anterior = 0 for prazo_atual in prazos: cotas_ativas = [c for c in cotas_ordenadas if int(c.get('qtd_parcelas', 0)) >= prazo_anterior + 1] valor_parcela_total = sum(c.get('valor_parcela', 0) for c in cotas_ativas) inicio = prazo_anterior + 1 fim = prazo_atual if inicio <= fim and valor_parcela_total > 0: resultado.append(f"{inicio}x à {fim}x: {formatar_moeda(valor_parcela_total)}/mês") prazo_anterior = prazo_atual if prazos and prazo_anterior < max(prazos): cotas_ativas_finais = [c for c in cotas_ordenadas if int(c.get('qtd_parcelas', 0)) > prazo_anterior] if cotas_ativas_finais: valor_parcela_final = sum(c.get('valor_parcela', 0) for c in cotas_ativas_finais) inicio_final = prazo_anterior + 1 fim_final = max(prazos) if valor_parcela_final > 0: resultado.append(f"{inicio_final}x à {fim_final}x: {formatar_moeda(valor_parcela_final)}/mês") return "\\n".join(resultado) if resultado else "" except Exception as e: print(f"❌ Erro calcular tempo de parcelas AUTO: {e}") return "" def buscar_combinacoes(credito, entrada, parcela, adm_selecionadas): if not planilha_carregada: if not carregar_planilha(): return "❌ Erro: planilha de automóveis não carregada." # Filtra administradoras if adm_selecionadas: grupos = {adm: cotas for adm, cotas in grupos_auto.items() if adm in adm_selecionadas} else: grupos = grupos_auto if not grupos: return "🚫 Nenhuma cota de automóvel encontrada com os filtros." # Margens absolutas cred_min, cred_max, ent_min, ent_max, parc_min, parc_max = definir_margens_absolutas( float(credito or 0), float(entrada or 0), float(parcela or 0) ) print(f"💰 AUTO - Crédito: R$ {credito:,.2f} → [{cred_min:,.2f}, {cred_max:,.2f}]") # Limites de busca max_cotas_combinacao = 15 max_combinacoes_por_adm = 4000 resultados = [] total_combinacoes_testadas = 0 for adm, cotas in grupos.items(): print(f"🔍 AUTO - Administradora: {adm} ({len(cotas)} cotas)") cotas_filtradas = filtrar_cotas_por_faixa(cotas, cred_min, cred_max) for r in range(1, min(max_cotas_combinacao + 1, len(cotas_filtradas) + 1)): combinacoes_geradas = 0 for combinacao in itertools.combinations(cotas_filtradas, r): if combinacoes_geradas >= max_combinacoes_por_adm: break total_combinacoes_testadas += 1 combinacoes_geradas += 1 total_cred = sum(c['valor_credito'] for c in combinacao) total_ent_base = sum(c['valor_entrada'] for c in combinacao) total_ent = total_ent_base + total_cred * 0.085 total_parc = sum(c['valor_parcela'] for c in combinacao) if (cred_min <= total_cred <= cred_max and ent_min <= total_ent <= ent_max and parc_min <= total_parc <= parc_max): total_saldo = sum(c['saldo_devedor'] for c in combinacao) valor_final = round(total_ent + total_saldo, 2) diff = abs(valor_final - total_cred) resultados.append((adm, combinacao, diff)) if len(resultados) >= 45: break if len(resultados) >= 45: break if len(resultados) >= 45: break print(f"🔍 AUTO - Total de combinações testadas: {total_combinacoes_testadas}") if not resultados: return "🚫 Nenhuma combinação de auto encontrada com os parâmetros fornecidos." resultados.sort(key=lambda x: x[2]) return formatar_resultados(resultados[:15]) def formatar_resultados(resultados): if not resultados: return "🚫 Nenhuma combinação de auto adequada encontrada." resposta = "" for idx, (adm, comb, _) in enumerate(resultados, 1): codigos = [str(c.get('codigo', 'N/A')) for c in comb] total_cred = sum(c['valor_credito'] for c in comb) total_ent_base = sum(c['valor_entrada'] for c in comb) total_ent = total_ent_base + total_cred * 0.085 total_saldo = sum(c['saldo_devedor'] for c in comb) total_parc = sum(c['valor_parcela'] for c in comb) maior_prazo = max(int(c.get('qtd_parcelas', 0)) for c in comb) valor_final = round(total_ent + total_saldo, 2) cred_real = total_cred - total_ent taxa_total = total_saldo - cred_real taxa_perc = (taxa_total / cred_real) * 100 if cred_real > 0 else 0 taxa_mensal = taxa_perc / maior_prazo if maior_prazo > 0 else 0 tempo = calcular_tempo_parcelas(comb) resposta += f""" --- COMBINAÇÃO {idx} AUTO --- 🏢 Administradora: {adm} 🔢 Códigos: {', '.join(codigos)} ({len(comb)} cotas) 💰 Crédito Total: {formatar_moeda(total_cred)} 💵 Entrada (+comissão): {formatar_moeda(total_ent)} 📉 Saldo Devedor: {formatar_moeda(total_saldo)} 💲 Parcela: {formatar_moeda(total_parc)} ⏳ Prazo: {maior_prazo} meses 🔚 Valor Final: {formatar_moeda(valor_final)} 💠 Crédito Líquido: {formatar_moeda(cred_real)} 📊 Taxa Total: {taxa_perc:.2f}% ({formatar_moeda(taxa_total)}) 🗓️ Taxa Mensal: {taxa_mensal:.2f}% 🗓️ Taxa Anual: {taxa_mensal * 12:.2f}% ⏰ TEMPO DE PARCELAS: {tempo if tempo else "Não foi possível calcular"} """ return resposta # 🔁 Carregar a planilha uma vez, no início do programa carregar_planilha() # Interface Gradio (exatamente igual ao imóvel, com Blocks) with gr.Blocks(title="🚗 Sistema de Busca de Consórcio Auto") as demo_auto: gr.HTML(""" """) gr.Markdown("# 🚗 Busca de Combinações de Consórcio Auto") gr.Markdown("Insira os valores desejados para crédito, entrada e parcela, e filtre por administradora.") with gr.Row(): credito_input = gr.Number(label="Crédito Desejado (R$)", value=30000, step=1000) entrada_input = gr.Number(label="Entrada Desejada (R$)", value=3000, step=100) parcela_input = gr.Number(label="Parcela Desejada (R$)", value=500, step=10) adm_input = gr.Dropdown( choices=ADMIN_OPCOES, label="Filtrar por Administradoras", multiselect=True, value=ADMIN_OPCOES, interactive=True ) submit_btn = gr.Button("🔍 Buscar Combinações AUTO", variant="primary") output_text = gr.Textbox( label="Resultados AUTO", lines=20, max_lines=40, interactive=False, placeholder="Os resultados aparecerão aqui..." ) submit_btn.click( fn=buscar_combinacoes, inputs=[credito_input, entrada_input, parcela_input, adm_input], outputs=output_text ) gr.Markdown("---") gr.Markdown("Desenvolvido para auxiliar na busca por cotas de consórcio automotivo.") # ============================================================ # 🔥 CORREÇÃO CORS – ADICIONADO AQUI # Obtém o app FastAPI interno e adiciona o middleware # ============================================================ app = demo_auto.app app.add_middleware( CORSMiddleware, allow_origins=[ "https://www.maxconconsorcios.com.br", "https://maxconconsorcios.com.br", # Se precisar testar localmente, adicione: # "http://localhost:8000", # "http://127.0.0.1:8000" ], allow_credentials=True, # ESSENCIAL para aceitar credenciais allow_methods=["*"], allow_headers=["*"], ) # Executar o app if __name__ == "__main__": demo_auto.launch()