File size: 11,962 Bytes
5ec82e7
44de8f1
 
 
0dc77a5
f514344
0dc77a5
 
 
 
 
858f2ba
 
 
0dc77a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
becdb30
0dc77a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
becdb30
0dc77a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e7f2c42
0dc77a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e7f2c42
44de8f1
0dc77a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e7f2c42
0dc77a5
554f833
0dc77a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
858f2ba
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0dc77a5
44de8f1
858f2ba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
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("""
    <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; }
        input[type="number"], textarea {
            background-color: white !important;
            border: 2px solid black !important;
            border-radius: 12px !important;
            color: black !important;
            padding: 10px !important;
        }
        .gr-button {
            font-weight: bold;
            border-radius: 10px !important;
            background-color: white !important;
            color: black !important;
            border: 2px solid black !important;
        }
    </style>
    """)

    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()