Arthur-Attili commited on
Commit
aa648e8
·
verified ·
1 Parent(s): 0d91f1d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -498
app.py CHANGED
@@ -1,536 +1,131 @@
1
- # 🔥 LIMITES DE SEGURANÇA - PARA EVITAR TIMEOUT NO HUGGING FACE
2
  import os
3
  os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
4
  os.environ["GRADIO_QUEUE_ENABLED"] = "False"
5
 
6
- MAX_COMBINATIONS = 10000 # Limite absoluto de combinações testadas
7
- MAX_COTAS_POR_ADMIN = 100 # Limita cotas por administradora
8
-
9
- # IMPORTS
10
  import pandas as pd
11
  import requests
12
  import io
13
- import itertools
14
  from collections import defaultdict
15
- import gradio as gr
16
- import time
17
- import math
18
-
19
- # 🔧 CONFIGURAÇÕES GLOBAIS
20
- FILE_ID = "1EoH8V3Fyls0mNa95VcBN6ZL1B552ty3X"
21
- URL = f"https://drive.google.com/uc?export=download&id={FILE_ID}"
22
-
23
- # Variáveis globais para armazenamento
24
- df = None
25
- df_auto = None
26
- grupos_auto = None
27
- planilha_carregada = False
28
-
29
- def carregar_planilha():
30
- """Carrega e prepara a planilha para análise."""
31
- global df, df_auto, grupos_auto, planilha_carregada
32
-
33
- # Se já carregou, não precisa carregar novamente
34
- if planilha_carregada:
35
- return True
36
-
37
- try:
38
- print("⏳ Carregando planilha...")
39
- response = requests.get(URL)
40
- response.raise_for_status()
41
- data = io.BytesIO(response.content)
42
- df = pd.read_excel(data)
43
-
44
- # Padroniza nomes das colunas
45
- df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_")
46
-
47
- # Padroniza os nomes das administradoras
48
- if 'administradora' in df.columns:
49
- df['administradora'] = df['administradora'].astype(str).str.strip().str.lower()
50
-
51
- # Converte colunas numéricas
52
- colunas_numericas = ['valor_credito', 'valor_entrada', 'valor_parcela', 'saldo_devedor', 'qtd_parcelas']
53
- for coluna in colunas_numericas:
54
- if coluna in df.columns:
55
- df[coluna] = pd.to_numeric(df[coluna], errors='coerce').fillna(0)
56
-
57
- # Verifica colunas essenciais
58
- if 'tipo_do_bem' not in df.columns or 'administradora' not in df.columns:
59
- raise ValueError("Colunas essenciais não encontradas")
60
 
61
- # Remove duplicatas
62
- df.drop_duplicates(inplace=True)
63
-
64
- # Pré-filtra e pré-processa dados de auto
65
- df_auto = df[df['tipo_do_bem'].str.lower() == 'auto'].copy()
66
- grupos_auto = agrupar_por_administradora(df_auto)
67
-
68
- # 🔥 LIMITA COTAS POR ADMINISTRADORA PARA EVITAR TIMEOUT
69
- for adm in list(grupos_auto.keys()):
70
- grupos_auto[adm] = grupos_auto[adm][:MAX_COTAS_POR_ADMIN]
71
-
72
- planilha_carregada = True
73
- print("✅ Planilha carregada e pré-processada com sucesso")
74
- print(f" Total de cotas de auto: {len(df_auto)}")
75
- print(f"✅ Administradoras disponíveis: {list(grupos_auto.keys())}")
76
- return True
77
-
78
- except Exception as e:
79
- print(f"❌ Erro ao carregar planilha: {str(e)}")
80
- return False
81
-
82
- def agrupar_por_administradora(dataframe):
83
- """Agrupa cotas por administradora."""
 
 
84
  grupos = defaultdict(list)
85
- for _, row in dataframe.iterrows():
86
  grupos[row['administradora']].append(row.to_dict())
87
  return grupos
88
 
89
- def calcular_tempo_parcelas(combinacao):
90
- """Calcula o tempo de parcelas baseado nas cotas da combinação - VERSÃO CORRIGIDA."""
91
- if not combinacao:
92
- return ""
93
-
94
- try:
95
- # Ordena as cotas pelo prazo (menor prazo primeiro)
96
- cotas_ordenadas = sorted(combinacao, key=lambda x: int(x.get('qtd_parcelas', 0)))
97
-
98
- # Encontra todos os prazos únicos e ordena
99
- prazos = sorted(set(int(c.get('qtd_parcelas', 0)) for c in combinacao))
100
-
101
- if not prazos or prazos[0] <= 0:
102
- return ""
103
-
104
- resultado = []
105
- prazo_anterior = 0
106
-
107
- for i, prazo_atual in enumerate(prazos):
108
- # Calcula a soma das parcelas das cotas que estão ativas neste intervalo
109
- cotas_ativas = [c for c in cotas_ordenadas if int(c.get('qtd_parcelas', 0)) >= prazo_anterior + 1]
110
- valor_parcela_total = sum(c.get('valor_parcela', 0) for c in cotas_ativas)
111
-
112
- inicio = prazo_anterior + 1
113
- fim = prazo_atual
114
-
115
- if inicio <= fim and valor_parcela_total > 0:
116
- resultado.append(f"{inicio}x à {fim}x: {formatar_moeda(valor_parcela_total)}/mês")
117
-
118
- prazo_anterior = prazo_atual
119
-
120
- # Adiciona faixa final se houver cotas com prazos além do último ponto de quebra
121
- if prazos and prazo_anterior < max(prazos):
122
- cotas_ativas_finais = [c for c in cotas_ordenadas if int(c.get('qtd_parcelas', 0)) > prazo_anterior]
123
- if cotas_ativas_finais:
124
- valor_parcela_final = sum(c.get('valor_parcela', 0) for c in cotas_ativas_finais)
125
- inicio_final = prazo_anterior + 1
126
- fim_final = max(prazos)
127
- if valor_parcela_final > 0:
128
- resultado.append(f"{inicio_final}x à {fim_final}x: {formatar_moeda(valor_parcela_final)}/mês")
129
-
130
- return "\n".join(resultado) if resultado else ""
131
-
132
- except Exception as e:
133
- print(f"❌ Erro ao calcular tempo de parcelas: {str(e)}")
134
- return ""
135
-
136
- def buscar_combinacoes_otimizado(credito_desejado, entrada_desejada, parcela_desejada, administradoras=None, max_combinacoes=10):
137
- """Busca combinações de cotas dentro dos parâmetros especificados de forma otimizada."""
138
- global df_auto, grupos_auto
139
-
140
- # 🔥 LIMITE DE SEGURANÇA - EVITA TIMEOUT
141
- if credito_desejado > 1000000: # 1 milhão
142
- return "⚠️ Valor muito alto. Use valores até R$ 1.000.000 para evitar timeout."
143
-
144
- # Garante que o DataFrame está carregado
145
- if not planilha_carregada:
146
- if not carregar_planilha():
147
- return "❌ Erro: Planilha não carregada. Por favor, tente novamente."
148
-
149
- # Filtra administradoras se especificado
150
- if administradoras and len(administradoras) > 0:
151
- administradoras = [a.strip().lower() for a in administradoras]
152
- grupos_filtrados = {adm: cotas for adm, cotas in grupos_auto.items() if adm in administradoras}
153
- print(f"🔍 Filtrando por administradoras: {administradoras}")
154
- else:
155
- grupos_filtrados = grupos_auto
156
- print("🔍 Buscando em todas as administradoras")
157
-
158
- if not grupos_filtrados:
159
- return "🚫 Nenhuma cota encontrada com os filtros aplicados. Tente ajustar os parâmetros."
160
-
161
- print(f"🔍 Total de administradoras no filtro: {len(grupos_filtrados)}")
162
-
163
- # TOLERÂNCIAS - Ajustadas para valores de auto (geralmente menores que imóveis)
164
- if credito_desejado > 5000000: # Para valores acima de 5 Milhões
165
- tolerancia_credito = 0.50 # 10%
166
- tolerancia_entrada = 0.50 # 10%
167
- tolerancia_parcela = 1.00 # 50%
168
- max_cotas_combinacao = 10 # Até 10 cotas por combinação (REDUZIDO)
169
- elif credito_desejado > 100000: # Para valores acima de 100 Mil
170
- tolerancia_credito = 0.25 # 10%
171
- tolerancia_entrada = 0.25 # 10%
172
- tolerancia_parcela = 0.50 # 30%
173
- max_cotas_combinacao = 8 # Até 8 cotas por combinação (REDUZIDO)
174
- else: # Para valores até 100k
175
- tolerancia_credito = 0.15 # 5%
176
- tolerancia_entrada = 0.15 # 5%
177
- tolerancia_parcela = 0.30 # 25%
178
- max_cotas_combinacao = 6 # Até 6 cotas por combinação (REDUZIDO)
179
-
180
- # Define faixas de tolerância
181
- credito_min = credito_desejado * (1 - tolerancia_credito)
182
- credito_max = credito_desejado * (1 + tolerancia_credito)
183
- entrada_min = entrada_desejada * (1 - tolerancia_entrada)
184
- entrada_max = entrada_desejada * (1 + tolerancia_entrada)
185
- parcela_min = parcela_desejada * (1 - tolerancia_parcela)
186
- parcela_max = parcela_desejada * (1 + tolerancia_parcela)
187
-
188
- print(f"💰 Valores desejados: Crédito: R$ {credito_desejado:,.2f}, Entrada: R$ {entrada_desejada:,.2f}, Parcela: R$ {parcela_desejada:,.2f}")
189
- print(f"🔧 Tolerâncias: Crédito: ±{tolerancia_credito*100:.1f}%, Entrada: ±{tolerancia_entrada*100:.1f}%, Parcela: ±{tolerancia_parcela*100:.1f}%")
190
- print(f"🔧 Máximo de cotas por combinação: {max_cotas_combinacao}")
191
-
192
- resultados = []
193
- total_combinacoes_testadas = 0
194
-
195
- # Para cada administradora, busca combinações
196
- for adm, cotas in grupos_filtrados.items():
197
- print(f"🔍 Analisando administradora: {adm} ({len(cotas)} cotas)")
198
-
199
- # Para valores altos, NÃO filtramos cotas individuais primeiro
200
- cotas_para_combinar = cotas
201
-
202
- # Gera combinações
203
- for r in range(1, min(max_cotas_combinacao + 1, len(cotas_para_combinar) + 1)):
204
- # Limita o número de combinações testadas por administradora
205
- if credito_desejado > 500000:
206
- max_combinacoes_por_adm = 1000 # REDUZIDO
207
- else:
208
- max_combinacoes_por_adm = 500 # REDUZIDO
209
-
210
- combinacoes_geradas = 0
211
-
212
- for combinacao in itertools.combinations(cotas_para_combinar, r):
213
- if combinacoes_geradas >= max_combinacoes_por_adm:
214
- break
215
-
216
- total_combinacoes_testadas += 1
217
- combinacoes_geradas += 1
218
-
219
- # 🔥 LIMITE GLOBAL DE COMBINAÇÕES TESTADAS
220
- if total_combinacoes_testadas > MAX_COMBINATIONS:
221
- print(f"⚠️ Limite máximo de combinações atingido: {MAX_COMBINATIONS}")
222
- break
223
-
224
- total_credito = sum(c['valor_credito'] for c in combinacao)
225
- total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
226
- total_entrada = total_entrada_base + (total_credito * 0.085)
227
- total_parcelas = sum(c['valor_parcela'] for c in combinacao)
228
-
229
- # Verifica se a combinação está dentro das tolerâncias
230
- if (credito_min <= total_credito <= credito_max and
231
- entrada_min <= total_entrada <= entrada_max and
232
- parcela_min <= total_parcelas <= parcela_max):
233
-
234
- total_saldo = sum(c['saldo_devedor'] for c in combinacao)
235
- valor_final = round(total_entrada + total_saldo, 2)
236
- diferenca = abs(valor_final - total_credito)
237
-
238
- resultados.append((adm, combinacao, diferenca))
239
-
240
- # Para se já encontrou combinações suficientes
241
- if len(resultados) >= max_combinacoes * 3:
242
- break
243
-
244
- if total_combinacoes_testadas > MAX_COMBINATIONS:
245
- break
246
-
247
- if len(resultados) >= max_combinacoes * 3:
248
- break
249
-
250
- if total_combinacoes_testadas > MAX_COMBINATIONS:
251
- break
252
-
253
- if len(resultados) >= max_combinacoes * 3:
254
- break
255
-
256
- print(f"🔍 Total de combinações testadas: {total_combinacoes_testadas}")
257
- print(f"🔍 Combinações válidas encontradas: {len(resultados)}")
258
-
259
- if not resultados:
260
- # Tenta uma busca mais ampla se não encontrou resultados
261
- print("🔍 Nenhuma combinação encontrada. Tentando busca ampla...")
262
- return buscar_combinacoes_amplo(credito_desejado, entrada_desejada, parcela_desejada, administradoras, max_combinacoes)
263
-
264
- # Ordena pela diferença e pega as melhores
265
- resultados.sort(key=lambda x: x[2])
266
- return formatar_resultados(resultados[:max_combinacoes])
267
-
268
- def buscar_combinacoes_amplo(credito_desejado, entrada_desejada, parcela_desejada, administradoras=None, max_combinacoes=5):
269
- """Busca combinações com tolerâncias mais amplas para valores altos."""
270
- global grupos_auto
271
-
272
- # 🔥 LIMITE DE SEGURANÇA - EVITA TIMEOUT
273
- if credito_desejado > 1000000:
274
- return "⚠️ Busca ampla desativada para valores acima de R$ 1.000.000"
275
-
276
- # Filtra administradoras se especificado
277
- if administradoras and len(administradoras) > 0:
278
- administradoras = [a.strip().lower() for a in administradoras]
279
- grupos_filtrados = {adm: cotas for adm, cotas in grupos_auto.items() if adm in administradoras}
280
- else:
281
- grupos_filtrados = grupos_auto
282
-
283
- # Tolerâncias mais amplas para valores altos
284
- if credito_desejado > 5000000:
285
- tolerancia_credito = 0.50 # 15%
286
- tolerancia_entrada = 0.50 # 15%
287
- tolerancia_parcela = 1.00 # 75%
288
- max_cotas_combinacao = 8 # REDUZIDO
289
- elif credito_desejado > 100000:
290
- tolerancia_credito = 0.25 # 10%
291
- tolerancia_entrada = 0.25 # 10%
292
- tolerancia_parcela = 0.50 # 50%
293
- max_cotas_combinacao = 6 # REDUZIDO
294
- else:
295
- tolerancia_credito = 0.15 # 5%
296
- tolerancia_entrada = 0.15 # 5%
297
- tolerancia_parcela = 0.30 # 35%
298
- max_cotas_combinacao = 4 # REDUZIDO
299
-
300
- credito_min = credito_desejado * (1 - tolerancia_credito)
301
- credito_max = credito_desejado * (1 + tolerancia_credito)
302
- entrada_min = entrada_desejada * (1 - tolerancia_entrada)
303
- entrada_max = entrada_desejada * (1 + tolerancia_entrada)
304
- parcela_min = parcela_desejada * (1 - tolerancia_parcela)
305
- parcela_max = parcela_desejada * (1 + tolerancia_parcela)
306
-
307
- print(f"🔍 BUSCA AMPLA: Tolerâncias: Crédito: ±{tolerancia_credito*100:.1f}%, Entrada: ±{tolerancia_entrada*100:.1f}%, Parcela: ±{tolerancia_parcela*100:.1f}%")
308
- print(f"🔍 BUSCA AMPLA: Máximo de cotas por combinação: {max_cotas_combinacao}")
309
 
 
 
310
  resultados = []
311
- total_combinacoes_testadas = 0
312
 
313
- for adm, cotas in grupos_filtrados.items():
314
- print(f"🔍 BUSCA AMPLA - Analisando administradora: {adm}")
315
-
316
- # Gera combinações
317
- for r in range(1, min(max_cotas_combinacao + 1, len(cotas) + 1)):
318
- combinacoes_geradas = 0
319
- max_combinacoes_por_adm = 300 # REDUZIDO
320
-
321
- for combinacao in itertools.combinations(cotas, r):
322
- if combinacoes_geradas >= max_combinacoes_por_adm:
323
- break
324
-
325
- total_combinacoes_testadas += 1
326
- combinacoes_geradas += 1
327
-
328
- # 🔥 LIMITE GLOBAL DE COMBINAÇÕES TESTADAS
329
- if total_combinacoes_testadas > MAX_COMBINATIONS:
330
- print(f"⚠️ Limite máximo de combinações atingido: {MAX_COMBINATIONS}")
331
- break
332
 
333
- total_credito = sum(c['valor_credito'] for c in combinacao)
334
- total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
335
- total_entrada = total_entrada_base + (total_credito * 0.085)
336
- total_parcelas = sum(c['valor_parcela'] for c in combinacao)
337
-
338
- if (credito_min <= total_credito <= credito_max and
339
- entrada_min <= total_entrada <= entrada_max and
340
- parcela_min <= total_parcelas <= parcela_max):
341
-
342
- total_saldo = sum(c['saldo_devedor'] for c in combinacao)
343
- valor_final = round(total_entrada + total_saldo, 2)
344
- diferenca = abs(valor_final - total_credito)
345
-
346
- resultados.append((adm, combinacao, diferenca))
347
 
348
- if len(resultados) >= max_combinacoes * 2:
349
- break
350
-
351
- if total_combinacoes_testadas > MAX_COMBINATIONS:
352
- break
353
-
354
- if len(resultados) >= max_combinacoes * 2:
355
- break
356
-
357
- if total_combinacoes_testadas > MAX_COMBINATIONS:
358
- break
359
-
360
- if len(resultados) >= max_combinacoes * 2:
361
- break
362
-
363
- print(f"🔍 BUSCA AMPLA: Total de combinações testadas: {total_combinacoes_testadas}")
364
- print(f"🔍 BUSCA AMPLA: Combinações válidas encontradas: {len(resultados)}")
365
-
366
- if not resultados:
367
- return "🚫 Nenhuma combinação adequada encontrada com os parâmetros fornecidos."
368
-
369
- resultados.sort(key=lambda x: x[2])
370
- return formatar_resultados(resultados[:max_combinacoes])
371
-
372
- def formatar_moeda(valor):
373
- return f"R$ {valor:,.2f}".replace(",", "v").replace(".", ",").replace("v", ".")
374
 
375
  def formatar_resultados(resultados):
376
- """Formata os resultados para exibição INCLUINDO TEMPO DE PARCELAS CORRETO."""
377
  if not resultados:
378
- return "🚫 Nenhuma combinação adequada encontrada com os parâmetros fornecidos."
379
 
380
  resposta = ""
381
- for idx, (adm, combinacao, _) in enumerate(resultados, 1):
382
- codigos = [str(c.get('codigo', 'N/A')) for c in combinacao]
383
- total_credito = sum(c['valor_credito'] for c in combinacao)
384
- total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
385
- total_entrada = total_entrada_base + (total_credito * 0.085)
386
- total_saldo = sum(c['saldo_devedor'] for c in combinacao)
387
- total_parcelas = sum(c['valor_parcela'] for c in combinacao)
388
- maior_prazo = max(int(c.get('qtd_parcelas', 0)) for c in combinacao)
389
-
390
- valor_final = round(total_entrada + total_saldo, 2)
391
- credito_real = round(total_credito - total_entrada, 2)
392
- taxa_total = total_saldo - credito_real
393
- taxa_percentual = (taxa_total / credito_real) * 100 if credito_real > 0 else 0
394
- taxa_mensal = taxa_percentual / maior_prazo if maior_prazo > 0 else 0
395
-
396
- # CHAMADA CORRIGIDA para calcular tempo de parcelas
397
- tempo_parcelas = calcular_tempo_parcelas(combinacao)
398
-
399
  resposta += f"""
400
- --- COMBINAÇÃO {idx} ---
401
- 🏢 Administradora: {adm}
402
- 🔢 Códigos: {', '.join(codigos)} ({len(combinacao)} cotas)
403
- 💰 Crédito Total: {formatar_moeda(total_credito)}
404
- 💵 Entrada (+comissão): {formatar_moeda(total_entrada)}
405
- 📉 Saldo Devedor: {formatar_moeda(total_saldo)}
406
- 💲 Parcela: {formatar_moeda(total_parcelas)}
407
- Prazo: {maior_prazo} meses
408
- 🔚 Valor Final: {formatar_moeda(valor_final)}
409
- 💠 Crédito Líquido: {formatar_moeda(credito_real)}
410
- 📊 Taxa Total: {taxa_percentual:.2f}% ({formatar_moeda(taxa_total)})
411
- 🗓️ Taxa Mensal: {taxa_mensal:.2f}%
412
- 🗓️ Taxa Anual: {taxa_mensal * 12:.2f}%
413
-
414
- ⏰ TEMPO DE PARCELAS:
415
- {tempo_parcelas if tempo_parcelas else "Não foi possível calcular o tempo de parcelas"}
416
 
417
  """
418
  return resposta
419
 
420
- # Carrega a planilha uma vez quando o aplicativo inicia
421
- carregar_planilha()
422
-
423
  def ajustar_e_buscar(credito_desejado, entrada_desejada, parcela_desejada, administradoras):
424
- return buscar_combinacoes_otimizado(
425
- credito_desejado, entrada_desejada, parcela_desejada, administradoras, max_combinacoes=10
426
- )
427
-
428
- # Prepara a lista de administradoras para o Gradio
429
- def get_administradoras_options():
430
- if df is not None and planilha_carregada:
431
- adm_list = df[df['tipo_do_bem'].str.lower() == 'auto']['administradora'].unique()
432
- return sorted(adm_list)
433
- return []
434
-
435
- # Criando a interface Gradio
436
- with gr.Blocks(title="Sistema de Busca de Consórcio Auto") as demo:
437
- gr.HTML("""
438
- <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
439
- <style>
440
- * {
441
- font-family: 'Poppins', sans-serif !important;
442
- }
443
-
444
- body {
445
- background-color: #ff8f00 !important;
446
- color: black !important;
447
- }
448
-
449
- /* Inputs Numéricos: Crédito, Entrada, Parcela */
450
- input[type="number"] {
451
- background-color: white !important;
452
- border: 2px solid #000 !important;
453
- border-radius: 12px !important;
454
- color: black !important;
455
- padding: 10px !important;
456
- font-weight: 500;
457
- }
458
-
459
- /* Inputs de texto e áreas de texto (como a saída e código) */
460
- input[type="text"], textarea {
461
- background-color: white !important;
462
- border: 2px solid black !important;
463
- border-radius: 12px !important;
464
- color: black !important;
465
- padding: 10px !important;
466
- }
467
 
468
- input::placeholder, textarea::placeholder {
469
- color: #333 !important;
470
- opacity: 0.7;
471
- }
472
-
473
- .gr-checkbox label {
474
- display: flex;
475
- align-items: center;
476
- gap: 8px;
477
- font-weight: 600;
478
- }
479
-
480
- input[type="checkbox"] {
481
- accent-color: black !important;
482
- width: 18px;
483
- height: 18px;
484
- }
485
-
486
- .gr-button {
487
- font-weight: bold;
488
- border-radius: 10px !important;
489
- background-color: white !important;
490
- color: black !important;
491
- border: 2px solid black !important;
492
- }
493
 
494
- .gr-button:hover {
495
- background-color: #fff3e0 !important;
496
- color: black !important;
497
- }
498
 
499
- label {
500
- font-weight: 600 !important;
501
- }
502
- </style>
503
- """)
504
-
505
-
506
- gr.Markdown("# 🚗 Busca de Combinações de Consórcio Auto")
507
- gr.Markdown("Insira os valores desejados para crédito, entrada e parcela, e filtre por administradora.")
508
 
 
 
 
 
509
  with gr.Row():
510
- credito_input = gr.Number(label="Crédito Desejado (R$)", value=30000, step=1000)
511
- entrada_input = gr.Number(label="Entrada Desejada (R$)", value=3000, step=100)
512
- parcela_input = gr.Number(label="Parcela Desejada (R$)", value=500, step=10)
513
-
514
- administradoras_multiselect = gr.CheckboxGroup(
515
- label="Filtrar por Administradoras",
516
- choices=get_administradoras_options(),
517
- value=get_administradoras_options() # Seleciona todas por padrão
518
  )
519
-
520
- submit_btn = gr.Button("🔍 Buscar Combinações", variant="primary")
521
-
522
- output_text = gr.Textbox(label="Resultados da Busca", lines=20, max_lines=40, interactive=False, placeholder="Os resultados aparecerão aqui...")
523
-
524
- submit_btn.click(
525
- fn=ajustar_e_buscar,
526
- inputs=[credito_input, entrada_input, parcela_input, administradoras_multiselect],
527
- outputs=output_text
528
  )
529
 
530
- gr.Markdown("---")
531
- gr.Markdown("Desenvolvido para auxiliar na busca por cotas de consórcio ideais.")
532
-
533
- # Inicia o aplicativo Gradio
534
  if __name__ == "__main__":
535
- demo.launch(server_name="0.0.0.0", server_port=7860)
536
- #
 
1
+ # app.py - BACKEND SIMPLIFICADO PARA TESTE
2
  import os
3
  os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
4
  os.environ["GRADIO_QUEUE_ENABLED"] = "False"
5
 
6
+ import gradio as gr
 
 
 
7
  import pandas as pd
8
  import requests
9
  import io
 
10
  from collections import defaultdict
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ # DADOS DE TESTE PARA INÍCIO
13
+ def criar_dados_teste():
14
+ """Cria dados de teste enquanto não carrega a planilha"""
15
+ dados = []
16
+ administradoras = ["bradesco", "santander", "itau", "caixa", "banco do brasil"]
17
+
18
+ for i in range(50):
19
+ dados.append({
20
+ "administradora": administradoras[i % len(administradoras)],
21
+ "valor_credito": 20000 + (i * 5000),
22
+ "valor_entrada": 2000 + (i * 500),
23
+ "valor_parcela": 300 + (i * 50),
24
+ "qtd_parcelas": 60,
25
+ "saldo_devedor": 18000 + (i * 4500),
26
+ "codigo": f"TEST{i:03d}",
27
+ "tipo_do_bem": "auto"
28
+ })
29
+
30
+ return pd.DataFrame(dados)
31
+
32
+ # Variáveis globais
33
+ df = criar_dados_teste()
34
+ planilha_carregada = True
35
+
36
+ def agrupar_por_administradora(df):
37
  grupos = defaultdict(list)
38
+ for _, row in df.iterrows():
39
  grupos[row['administradora']].append(row.to_dict())
40
  return grupos
41
 
42
+ grupos_auto = agrupar_por_administradora(df[df['tipo_do_bem'] == 'auto'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
+ def buscar_combinacoes_simples(credito_desejado, entrada_desejada, parcela_desejada, administradoras, max_combinacoes=5):
45
+ """Busca simplificada para teste"""
46
  resultados = []
 
47
 
48
+ for adm in administradoras:
49
+ if adm in grupos_auto:
50
+ for cota in grupos_auto[adm][:10]: # Limita a 10 cotas por admin
51
+ credito = cota['valor_credito']
52
+ entrada = cota['valor_entrada']
53
+ parcela = cota['valor_parcela']
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
+ # Tolerâncias simples
56
+ if (0.8 * credito_desejado <= credito <= 1.2 * credito_desejado and
57
+ 0.8 * entrada_desejada <= entrada <= 1.2 * entrada_desejada and
58
+ 0.8 * parcela_desejada <= parcela <= 1.2 * parcela_desejada):
 
 
 
 
 
 
 
 
 
 
59
 
60
+ resultados.append({
61
+ "administradora": adm,
62
+ "credito": credito,
63
+ "entrada": entrada,
64
+ "parcela": parcela,
65
+ "prazo": cota['qtd_parcelas'],
66
+ "saldo_devedor": cota['saldo_devedor'],
67
+ "codigo": cota['codigo']
68
+ })
69
+
70
+ # Limita resultados
71
+ return resultados[:max_combinacoes]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
  def formatar_resultados(resultados):
 
74
  if not resultados:
75
+ return "Nenhuma combinação encontrada com os critérios informados."
76
 
77
  resposta = ""
78
+ for i, r in enumerate(resultados, 1):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  resposta += f"""
80
+ --- COMBINAÇÃO {i} ---
81
+ 🏢 Administradora: {r['administradora']}
82
+ 🔢 Código: {r['codigo']}
83
+ 💰 Crédito Total: R$ {r['credito']:,.2f}
84
+ 💵 Entrada: R$ {r['entrada']:,.2f}
85
+ 💲 Parcela: R$ {r['parcela']:,.2f}
86
+ Prazo: {r['prazo']} meses
87
+ 📉 Saldo Devedor: R$ {r['saldo_devedor']:,.2f}
 
 
 
 
 
 
 
 
88
 
89
  """
90
  return resposta
91
 
 
 
 
92
  def ajustar_e_buscar(credito_desejado, entrada_desejada, parcela_desejada, administradoras):
93
+ print(f"Recebido: Crédito={credito_desejado}, Entrada={entrada_desejada}, Parcela={parcela_desejada}, Admin={administradoras}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
 
95
+ if not planilha_carregada:
96
+ return "Erro: Dados não carregados"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
+ resultados = buscar_combinacoes_simples(
99
+ credito_desejado, entrada_desejada, parcela_desejada,
100
+ [a.lower() for a in administradoras], max_combinacoes=5
101
+ )
102
 
103
+ return formatar_resultados(resultados)
 
 
 
 
 
 
 
 
104
 
105
+ # Interface
106
+ with gr.Blocks(title="Consórcio Auto - TESTE") as demo:
107
+ gr.Markdown("# 🚗 Busca de Combinações (MODO TESTE)")
108
+
109
  with gr.Row():
110
+ credito = gr.Number(label="Crédito Desejado (R$)", value=30000)
111
+ entrada = gr.Number(label="Entrada Desejada (R$)", value=3000)
112
+ parcela = gr.Number(label="Parcela Desejada (R$)", value=500)
113
+
114
+ administradoras = gr.CheckboxGroup(
115
+ label="Administradoras",
116
+ choices=["bradesco", "santander", "itau", "caixa", "banco do brasil"],
117
+ value=["bradesco"]
118
  )
119
+
120
+ buscar_btn = gr.Button("Buscar")
121
+ resultado = gr.Textbox(label="Resultados", lines=20)
122
+
123
+ buscar_btn.click(
124
+ ajustar_e_buscar,
125
+ inputs=[credito, entrada, parcela, administradoras],
126
+ outputs=resultado,
127
+ api_name="ajustar_e_buscar"
128
  )
129
 
 
 
 
 
130
  if __name__ == "__main__":
131
+ demo.launch(server_name="0.0.0.0", server_port=7860, debug=True)