Arthur-Attili commited on
Commit
0dc77a5
·
verified ·
1 Parent(s): e7f2c42

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +299 -321
app.py CHANGED
@@ -2,333 +2,311 @@ import os
2
  os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
3
  os.environ["HF_HUB_DISABLE_TELEMETRY"] = "1"
4
 
5
- import gradio as gr
6
  import requests
7
- import json
8
- from datetime import datetime
9
- import time
10
-
11
- # ==================== CONFIGURAÇÕES ====================
12
- API_BASE_URL = "https://api.maxconconsorcios.com.br"
13
- WHATSAPP_NUMBER = "5516997865738"
14
-
15
- # Cache simples
16
- cache = {}
17
-
18
- # ==================== MAPEAMENTO DE ADMINISTRADORAS ====================
19
- ADMIN_MAP = {
20
- 1: 'Itaú', 2: 'Bradesco', 3: 'Santander', 4: 'Honda', 5: 'Volkswagen',
21
- 6: 'Serello', 7: 'Ademicon', 8: 'Remaza', 9: 'Porto Seguro VP',
22
- 10: 'Banrisul', 11: 'Embracon', 12: 'Serrana', 13: 'Caixa XS5',
23
- 14: 'Caixa CNP', 15: 'Unifisa', 16: 'HS Consorcios', 17: 'Caixa Seguradora',
24
- 18: 'Porto Seguro', 19: 'Mycon', 20: 'Rodobens', 21: 'Ford',
25
- 22: 'Sicoob Unicoob', 23: 'Zema', 24: 'Maggi', 25: 'Ancora', 26: 'Yamaha',
26
- 27: 'Sponchiado', 28: 'Scania', 29: 'Disal', 30: 'Servopa', 31: 'Canopus',
27
- 32: 'Bradesco', 33: 'Banco do Brasil', 34: 'Santander', 35: 'Sicredi'
28
- }
29
-
30
- # ==================== FUNÇÕES AUXILIARES ====================
31
- def formatar_moeda(valor):
32
- """Formata valor para moeda brasileira"""
33
- if valor is None or valor == '':
34
- return "R$ 0,00"
35
- try:
36
- num = float(valor)
37
- return f"R$ {num:,.2f}".replace(",", "v").replace(".", ",").replace("v", ".")
38
- except:
39
- return "R$ 0,00"
40
-
41
- def get_administradora_nome(admin_id):
42
- """Retorna nome da administradora pelo ID"""
43
- return ADMIN_MAP.get(admin_id, 'Não especificado')
44
-
45
- def calcular_entrada_total(cota):
46
- """Calcula entrada total incluindo comissão de 8.5%"""
47
- credito = float(cota.get('valor_credito', 0))
48
- entrada = float(cota.get('entrada', 0))
49
- comissao = credito * 0.085
50
- return entrada + comissao
51
-
52
- # ==================== BUSCA DE COTAS ====================
53
- def buscar_cotas_da_api():
54
- """Busca cotas diretamente da API do Supabase"""
55
  try:
56
- print("🔄 Buscando cotas na API...")
57
- response = requests.post(
58
- f"{API_BASE_URL}/api/cotas",
59
- json={},
60
- headers={'Content-Type': 'application/json'},
61
- timeout=30
62
- )
63
-
64
- if response.status_code == 200:
65
- cotas = response.json()
66
- print(f"✅ {len(cotas)} cotas carregadas")
67
- return cotas
68
- else:
69
- print(f"❌ Erro na API: {response.status_code}")
70
- return []
71
-
72
- except requests.exceptions.Timeout:
73
- print("❌ Timeout na conexão com a API")
74
- return []
75
- except requests.exceptions.ConnectionError:
76
- print("❌ Erro de conexão com a API")
77
- return []
 
 
 
 
 
 
 
 
 
 
 
78
  except Exception as e:
79
- print(f"❌ Erro ao buscar cotas: {str(e)}")
80
- return []
81
-
82
- def buscar_combinacoes(credito, entrada, parcela, admin_selecionadas):
83
- """
84
- Função principal de busca de combinações
85
- """
86
- # Validação dos inputs
87
- try:
88
- credito_val = float(credito) if credito else 0
89
- except:
90
- credito_val = 0
91
-
92
- try:
93
- entrada_val = float(entrada) if entrada else 0
94
- except:
95
- entrada_val = 0
96
-
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  try:
98
- parcela_val = float(parcela) if parcela else 0
99
- except:
100
- parcela_val = 0
101
-
102
- if credito_val == 0 and entrada_val == 0 and parcela_val == 0:
103
- return "❌ Informe pelo menos um valor (Crédito, Entrada ou Parcela)"
104
-
105
- # Busca cotas
106
- cotas = buscar_cotas_da_api()
107
-
108
- if not cotas:
109
- return """❌ **Erro ao carregar dados**
110
-
111
- Não foi possível conectar ao servidor. Por favor, tente novamente em alguns instantes.
112
-
113
- Se o erro persistir, entre em contato pelo WhatsApp."""
114
-
115
- # Filtra cotas disponíveis
116
- cotas_disponiveis = [c for c in cotas if c.get('reserva') != 'reservado']
117
- print(f"📊 Cotas disponíveis: {len(cotas_disponiveis)}")
118
-
119
- # Filtra por administradora
120
- if admin_selecionadas and len(admin_selecionadas) > 0:
121
- adm_ids_filtro = []
122
- for admin_nome in admin_selecionadas:
123
- for admin_id, nome in ADMIN_MAP.items():
124
- if nome.lower() == admin_nome.lower():
125
- adm_ids_filtro.append(admin_id)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  break
127
-
128
- if adm_ids_filtro:
129
- cotas_disponiveis = [c for c in cotas_disponiveis if c.get('administradora_id') in adm_ids_filtro]
130
- print(f"📊 Após filtro de administradora: {len(cotas_disponiveis)}")
131
-
132
- # Filtra por crédito mínimo
133
- if credito_val > 0:
134
- cotas_disponiveis = [c for c in cotas_disponiveis if float(c.get('valor_credito', 0)) >= credito_val]
135
- print(f"📊 Após filtro de crédito (≥ R$ {credito_val:,.2f}): {len(cotas_disponiveis)}")
136
-
137
- # Filtra por parcela máxima
138
- if parcela_val > 0:
139
- cotas_disponiveis = [c for c in cotas_disponiveis if float(c.get('valor_parcela', 0)) <= parcela_val]
140
- print(f"📊 Após filtro de parcela (≤ R$ {parcela_val:,.2f}): {len(cotas_disponiveis)}")
141
-
142
- # Filtra por entrada máxima
143
- if entrada_val > 0:
144
- cotas_disponiveis = [c for c in cotas_disponiveis if calcular_entrada_total(c) <= entrada_val]
145
- print(f"📊 Após filtro de entrada (≤ R$ {entrada_val:,.2f}): {len(cotas_disponiveis)}")
146
-
147
- if not cotas_disponiveis:
148
- return """🚫 **Nenhuma cota encontrada**
149
-
150
- Tente ajustar os filtros:
151
- - Aumente o valor do crédito
152
- - Diminua o valor da entrada
153
- - Diminua o valor da parcela
154
- - Selecione mais administradoras"""
155
-
156
- # Ordena por crédito (do maior para o menor)
157
- cotas_disponiveis.sort(key=lambda x: float(x.get('valor_credito', 0)), reverse=True)
158
-
159
- # Limita para exibição (máximo 15 resultados)
160
- resultados = cotas_disponiveis[:15]
161
-
162
- return formatar_resultados(resultados)
163
-
164
- def formatar_resultados(cotas):
165
- """Formata os resultados para exibição"""
166
- if not cotas:
167
- return "🚫 Nenhum resultado encontrado."
168
-
169
- resultado = f"## 🎯 Resultados encontrados: {len(cotas)} cota(s)\n\n"
170
-
171
- for idx, cota in enumerate(cotas, 1):
172
- adm_nome = get_administradora_nome(cota.get('administradora_id'))
173
- codigo = cota.get('codigo', 'N/A')
174
- credito = float(cota.get('valor_credito', 0))
175
- entrada_total = calcular_entrada_total(cota)
176
- saldo = float(cota.get('saldo', 0))
177
- parcela = float(cota.get('valor_parcela', 0))
178
- prazo = int(cota.get('parcelas', 0))
179
-
180
- # Cálculos financeiros
181
- credito_real = credito - entrada_total
182
- valor_final = entrada_total + saldo
183
- taxa_total = saldo - credito_real
184
- taxa_percentual = (taxa_total / credito_real * 100) if credito_real > 0 else 0
185
-
186
- # Taxas
187
- if prazo > 0:
188
- taxa_mensal = taxa_percentual / prazo
189
- taxa_anual = taxa_mensal * 12
190
- else:
191
- taxa_mensal = 0
192
- taxa_anual = 0
193
-
194
- resultado += f"""
195
- ### 📌 Combinação {idx}
196
-
197
- | Campo | Valor |
198
- |-------|-------|
199
- | 🏢 **Administradora** | {adm_nome} |
200
- | 🔢 **Código** | {codigo} |
201
- | 💰 **Crédito** | {formatar_moeda(credito)} |
202
- | 💵 **Entrada** | {formatar_moeda(entrada_total)} |
203
- | 💲 **Parcela** | {formatar_moeda(parcela)} |
204
- | ⏳ **Prazo** | {prazo} meses |
205
- | 📉 **Saldo Devedor** | {formatar_moeda(saldo)} |
206
- | 🔚 **Valor Final** | {formatar_moeda(valor_final)} |
207
- | 💠 **Crédito Líquido** | {formatar_moeda(credito_real)} |
208
- | 📊 **Taxa Total** | {taxa_percentual:.2f}% ({formatar_moeda(taxa_total)}) |
209
- | 🗓️ **Taxa Mensal** | {taxa_mensal:.2f}% |
210
- | 🗓️ **Taxa Anual** | {taxa_anual:.2f}% |
211
-
212
- **⏰ Tempo de Parcelas:**
213
- - 1x à {min(21, prazo)}x: {formatar_moeda(parcela)}/mês
214
- """
215
- if prazo > 21:
216
- valor_reduzido = parcela * 0.44
217
- resultado += f"- {22}x à {prazo}x: {formatar_moeda(valor_reduzido)}/mês\n"
218
-
219
- resultado += f"""
220
- ---
221
- """
222
-
223
- resultado += f"""
224
- ### 📞 **Interessado?**
225
- Entre em contato pelo WhatsApp para negociar esta cota:
226
 
227
- [![WhatsApp](https://img.shields.io/badge/WhatsApp-25D366?style=for-the-badge&logo=whatsapp&logoColor=white)](https://wa.me/{WHATSAPP_NUMBER}?text=Olá! Tenho interesse nas cotas de consórcio)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  """
229
-
230
- return resultado
231
 
232
- # ==================== FUNÇÃO PARA OBTER ADMINISTRADORAS ====================
233
- def obter_administradoras():
234
- """Obtém lista de administradoras disponíveis"""
235
- try:
236
- cotas = buscar_cotas_da_api()
237
- adm_set = set()
238
- for cota in cotas:
239
- admin_id = cota.get('administradora_id')
240
- if admin_id:
241
- adm_set.add(get_administradora_nome(admin_id))
242
- return sorted(list(adm_set))
243
- except:
244
- # Lista fallback caso não consiga carregar
245
- return ["Porto Seguro", "Itaú", "Bradesco", "Santander", "Banco do Brasil", "Honda", "Yamaha"]
246
-
247
- # ==================== INTERFACE GRADIO ====================
248
- def create_interface():
249
- with gr.Blocks(title="MAXCON - Consórcio Auto", theme=gr.themes.Soft()) as demo:
250
- gr.HTML("""
251
- <div style="text-align: center; padding: 20px; background: linear-gradient(135deg, #1a3a6c 0%, #2a5a9c 100%); border-radius: 12px; margin-bottom: 20px;">
252
- <h1 style="color: white; margin: 0;">🚗 MAXCON Consórcios</h1>
253
- <p style="color: #ffd166; margin: 10px 0 0 0;">Encontre as melhores cotas para seu veículo</p>
254
- </div>
255
- """)
256
-
257
- with gr.Row():
258
- with gr.Column(scale=1):
259
- credito_input = gr.Number(
260
- label="💰 Crédito Desejado (mínimo)",
261
- value=100000,
262
- step=1000,
263
- precision=2
264
- )
265
- entrada_input = gr.Number(
266
- label="💵 Entrada (máximo)",
267
- value=50000,
268
- step=1000,
269
- precision=2
270
- )
271
- parcela_input = gr.Number(
272
- label="💲 Parcela (máximo)",
273
- value=2000,
274
- step=100,
275
- precision=2
276
- )
277
-
278
- # Carrega administradoras dinamicamente
279
- admin_choices = obter_administradoras()
280
- adm_input = gr.Dropdown(
281
- choices=admin_choices,
282
- label="🏢 Administradoras",
283
- multiselect=True,
284
- value=admin_choices[:5] if len(admin_choices) > 5 else admin_choices,
285
- interactive=True
286
- )
287
-
288
- buscar_btn = gr.Button("🔍 Buscar Combinações", variant="primary", size="lg")
289
-
290
- # Botão de limpar
291
- limpar_btn = gr.Button("🗑️ Limpar Filtros", variant="secondary", size="lg")
292
-
293
- with gr.Column(scale=2):
294
- output_text = gr.Markdown(
295
- value="### 🔍 Aguardando busca...\n\nPreencha os filtros ao lado e clique em 'Buscar Combinações'",
296
- label="Resultados"
297
- )
298
-
299
- # Eventos
300
- buscar_btn.click(
301
- fn=buscar_combinacoes,
302
- inputs=[credito_input, entrada_input, parcela_input, adm_input],
303
- outputs=output_text
304
- )
305
-
306
- def limpar_filtros():
307
- return [0, 0, 0, []]
308
-
309
- limpar_btn.click(
310
- fn=limpar_filtros,
311
- outputs=[credito_input, entrada_input, parcela_input, adm_input]
312
- )
313
-
314
- gr.Markdown("""
315
- ---
316
- ### 📌 Sobre a Busca
317
-
318
- - Os resultados são buscados **em tempo real** do nosso banco de dados
319
- - Valores atualizados diariamente
320
- - **Comissão de 8.5%** já incluída no valor da entrada
321
- - Entre em contato pelo WhatsApp para negociar
322
-
323
- ---
324
- **MAXCON Assessoria** - Realizando sonhos há mais de 5 anos
325
- """)
326
-
327
- return demo
328
-
329
- # ==================== INICIALIZAÇÃO ====================
330
  if __name__ == "__main__":
331
- print("🚀 Iniciando servidor MAXCON no Hugging Face...")
332
- print(f"📡 API Base: {API_BASE_URL}")
333
- demo = create_interface()
334
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
2
  os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
3
  os.environ["HF_HUB_DISABLE_TELEMETRY"] = "1"
4
 
5
+ import pandas as pd
6
  import requests
7
+ import io
8
+ import itertools
9
+ from collections import defaultdict
10
+ import gradio as gr
11
+
12
+ # 🔧 CONFIGURAÇÕES DO ARQUIVO
13
+ FILE_ID = "1EoH8V3Fyls0mNa95VcBN6ZL1B552ty3X"
14
+ URL = f"https://drive.google.com/uc?export=download&id={FILE_ID}"
15
+
16
+ # Variáveis globais
17
+ df_auto = None
18
+ grupos_auto = None
19
+ planilha_carregada = False
20
+ ADMIN_OPCOES = []
21
+
22
+
23
+ def carregar_planilha():
24
+ global df_auto, grupos_auto, planilha_carregada, ADMIN_OPCOES
25
+
26
+ if planilha_carregada:
27
+ return True
28
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  try:
30
+ print(" Carregando planilha de automóveis...")
31
+ response = requests.get(URL)
32
+ response.raise_for_status()
33
+ data = io.BytesIO(response.content)
34
+ df = pd.read_excel(data)
35
+
36
+ df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_")
37
+
38
+ colunas_numericas = ['valor_credito', 'valor_entrada', 'valor_parcela', 'saldo_devedor', 'qtd_parcelas']
39
+ for col in colunas_numericas:
40
+ if col in df.columns:
41
+ df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
42
+
43
+ if 'tipo_do_bem' not in df.columns or 'administradora' not in df.columns:
44
+ raise ValueError("Colunas essenciais não encontradas")
45
+
46
+ df.drop_duplicates(inplace=True)
47
+
48
+ df_auto = df[df['tipo_do_bem'].str.lower() == 'auto'].copy()
49
+ df_auto['administradora'] = df_auto['administradora'].astype(str).str.strip().str.lower()
50
+ df_auto = df_auto[df_auto['administradora'].notna() & (df_auto['administradora'] != '')]
51
+
52
+ grupos_auto = defaultdict(list)
53
+ for _, row in df_auto.iterrows():
54
+ grupos_auto[row['administradora']].append(row.to_dict())
55
+
56
+ ADMIN_OPCOES = sorted(df_auto['administradora'].unique())
57
+ planilha_carregada = True
58
+
59
+ print(f"✅ Total de cotas AUTO: {len(df_auto)}")
60
+ print(f"✅ Administradoras AUTO: {ADMIN_OPCOES}")
61
+ return True
62
+
63
  except Exception as e:
64
+ print(f"❌ Erro ao carregar planilha AUTO: {e}")
65
+ return False
66
+
67
+
68
+ def formatar_moeda(valor):
69
+ return f"R$ {valor:,.2f}".replace(",", "v").replace(".", ",").replace("v", ".")
70
+
71
+
72
+ def definir_margens_absolutas(credito, entrada, parcela):
73
+ margem_credito = 20_000 # ex.: 30.000 10.000–50.000
74
+ margem_entrada = 2_000
75
+ margem_parcela = 100
76
+
77
+ cred_min = max(0, credito - margem_credito)
78
+ cred_max = credito + margem_credito
79
+ ent_min = max(0, entrada - margem_entrada)
80
+ ent_max = entrada + margem_entrada
81
+ parc_min = max(0, parcela - margem_parcela)
82
+ parc_max = parcela + margem_parcela
83
+
84
+ return cred_min, cred_max, ent_min, ent_max, parc_min, parc_max
85
+
86
+
87
+ def filtrar_cotas_por_faixa(cotas, cred_min, cred_max):
88
+ return [c for c in cotas if c['valor_credito'] < cred_max * 2]
89
+
90
+
91
+ def calcular_tempo_parcelas(combinacao):
92
+ if not combinacao:
93
+ return ""
94
+
95
  try:
96
+ cotas_ordenadas = sorted(combinacao, key=lambda x: int(x.get('qtd_parcelas', 0)))
97
+ prazos = sorted(set(int(c.get('qtd_parcelas', 0)) for c in combinacao))
98
+
99
+ if not prazos or prazos[0] <= 0:
100
+ return ""
101
+
102
+ resultado = []
103
+ prazo_anterior = 0
104
+
105
+ for prazo_atual in prazos:
106
+ cotas_ativas = [c for c in cotas_ordenadas if int(c.get('qtd_parcelas', 0)) >= prazo_anterior + 1]
107
+ valor_parcela_total = sum(c.get('valor_parcela', 0) for c in cotas_ativas)
108
+
109
+ inicio = prazo_anterior + 1
110
+ fim = prazo_atual
111
+
112
+ if inicio <= fim and valor_parcela_total > 0:
113
+ resultado.append(f"{inicio}x à {fim}x: {formatar_moeda(valor_parcela_total)}/mês")
114
+
115
+ prazo_anterior = prazo_atual
116
+
117
+ if prazos and prazo_anterior < max(prazos):
118
+ cotas_ativas_finais = [c for c in cotas_ordenadas if int(c.get('qtd_parcelas', 0)) > prazo_anterior]
119
+ if cotas_ativas_finais:
120
+ valor_parcela_final = sum(c.get('valor_parcela', 0) for c in cotas_ativas_finais)
121
+ inicio_final = prazo_anterior + 1
122
+ fim_final = max(prazos)
123
+ if valor_parcela_final > 0:
124
+ resultado.append(f"{inicio_final}x à {fim_final}x: {formatar_moeda(valor_parcela_final)}/mês")
125
+
126
+ return "\\n".join(resultado) if resultado else ""
127
+
128
+ except Exception as e:
129
+ print(f"❌ Erro calcular tempo de parcelas AUTO: {e}")
130
+ return ""
131
+
132
+
133
+ def buscar_combinacoes(credito, entrada, parcela, adm_selecionadas):
134
+ if not planilha_carregada:
135
+ if not carregar_planilha():
136
+ return "❌ Erro: planilha de automóveis não carregada."
137
+
138
+ # Filtra administradoras
139
+ if adm_selecionadas:
140
+ grupos = {adm: cotas for adm, cotas in grupos_auto.items() if adm in adm_selecionadas}
141
+ else:
142
+ grupos = grupos_auto
143
+
144
+ if not grupos:
145
+ return "🚫 Nenhuma cota de automóvel encontrada com os filtros."
146
+
147
+ # Margens absolutas
148
+ cred_min, cred_max, ent_min, ent_max, parc_min, parc_max = definir_margens_absolutas(
149
+ float(credito or 0),
150
+ float(entrada or 0),
151
+ float(parcela or 0)
152
+ )
153
+
154
+ print(f"💰 AUTO - Crédito: R$ {credito:,.2f} → [{cred_min:,.2f}, {cred_max:,.2f}]")
155
+
156
+ # Limites de busca
157
+ max_cotas_combinacao = 15
158
+ max_combinacoes_por_adm = 4000
159
+
160
+ resultados = []
161
+ total_combinacoes_testadas = 0
162
+
163
+ for adm, cotas in grupos.items():
164
+ print(f"🔍 AUTO - Administradora: {adm} ({len(cotas)} cotas)")
165
+ cotas_filtradas = filtrar_cotas_por_faixa(cotas, cred_min, cred_max)
166
+
167
+ for r in range(1, min(max_cotas_combinacao + 1, len(cotas_filtradas) + 1)):
168
+ combinacoes_geradas = 0
169
+ for combinacao in itertools.combinations(cotas_filtradas, r):
170
+ if combinacoes_geradas >= max_combinacoes_por_adm:
171
  break
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
+ total_combinacoes_testadas += 1
174
+ combinacoes_geradas += 1
175
+
176
+ total_cred = sum(c['valor_credito'] for c in combinacao)
177
+ total_ent_base = sum(c['valor_entrada'] for c in combinacao)
178
+ total_ent = total_ent_base + total_cred * 0.085
179
+ total_parc = sum(c['valor_parcela'] for c in combinacao)
180
+
181
+ if (cred_min <= total_cred <= cred_max and
182
+ ent_min <= total_ent <= ent_max and
183
+ parc_min <= total_parc <= parc_max):
184
+
185
+ total_saldo = sum(c['saldo_devedor'] for c in combinacao)
186
+ valor_final = round(total_ent + total_saldo, 2)
187
+ diff = abs(valor_final - total_cred)
188
+ resultados.append((adm, combinacao, diff))
189
+
190
+ if len(resultados) >= 45:
191
+ break
192
+ if len(resultados) >= 45:
193
+ break
194
+ if len(resultados) >= 45:
195
+ break
196
+
197
+ print(f"🔍 AUTO - Total de combinações testadas: {total_combinacoes_testadas}")
198
+
199
+ if not resultados:
200
+ return "🚫 Nenhuma combinação de auto encontrada com os parâmetros fornecidos."
201
+
202
+ resultados.sort(key=lambda x: x[2])
203
+ return formatar_resultados(resultados[:15])
204
+
205
+
206
+ def formatar_resultados(resultados):
207
+ if not resultados:
208
+ return "🚫 Nenhuma combinação de auto adequada encontrada."
209
+
210
+ resposta = ""
211
+ for idx, (adm, comb, _) in enumerate(resultados, 1):
212
+ codigos = [str(c.get('codigo', 'N/A')) for c in comb]
213
+ total_cred = sum(c['valor_credito'] for c in comb)
214
+ total_ent_base = sum(c['valor_entrada'] for c in comb)
215
+ total_ent = total_ent_base + total_cred * 0.085
216
+ total_saldo = sum(c['saldo_devedor'] for c in comb)
217
+ total_parc = sum(c['valor_parcela'] for c in comb)
218
+ maior_prazo = max(int(c.get('qtd_parcelas', 0)) for c in comb)
219
+ valor_final = round(total_ent + total_saldo, 2)
220
+ cred_real = total_cred - total_ent
221
+ taxa_total = total_saldo - cred_real
222
+ taxa_perc = (taxa_total / cred_real) * 100 if cred_real > 0 else 0
223
+ taxa_mensal = taxa_perc / maior_prazo if maior_prazo > 0 else 0
224
+ tempo = calcular_tempo_parcelas(comb)
225
+
226
+ resposta += f"""
227
+ --- COMBINAÇÃO {idx} AUTO ---
228
+ 🏢 Administradora: {adm}
229
+ 🔢 Códigos: {', '.join(codigos)} ({len(comb)} cotas)
230
+ 💰 Crédito Total: {formatar_moeda(total_cred)}
231
+ 💵 Entrada (+comissão): {formatar_moeda(total_ent)}
232
+ 📉 Saldo Devedor: {formatar_moeda(total_saldo)}
233
+ 💲 Parcela: {formatar_moeda(total_parc)}
234
+ ⏳ Prazo: {maior_prazo} meses
235
+ 🔚 Valor Final: {formatar_moeda(valor_final)}
236
+ 💠 Crédito Líquido: {formatar_moeda(cred_real)}
237
+ 📊 Taxa Total: {taxa_perc:.2f}% ({formatar_moeda(taxa_total)})
238
+ 🗓️ Taxa Mensal: {taxa_mensal:.2f}%
239
+ 🗓️ Taxa Anual: {taxa_mensal * 12:.2f}%
240
+ ⏰ TEMPO DE PARCELAS:
241
+ {tempo if tempo else "Não foi possível calcular"}
242
  """
243
+ return resposta
 
244
 
245
+
246
+ # 🔁 Carregar a planilha uma vez, no início do programa
247
+ carregar_planilha()
248
+
249
+
250
+ # Interface Gradio (exatamente igual ao imóvel, com Blocks)
251
+ with gr.Blocks(title="🚗 Sistema de Busca de Consórcio Auto") as demo_auto:
252
+ gr.HTML("""
253
+ <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
254
+ <style>
255
+ * { font-family: 'Poppins', sans-serif !important; }
256
+ body { background-color: #ff8f00 !important; color: black !important; }
257
+ input[type="number"], textarea {
258
+ background-color: white !important;
259
+ border: 2px solid black !important;
260
+ border-radius: 12px !important;
261
+ color: black !important;
262
+ padding: 10px !important;
263
+ }
264
+ .gr-button {
265
+ font-weight: bold;
266
+ border-radius: 10px !important;
267
+ background-color: white !important;
268
+ color: black !important;
269
+ border: 2px solid black !important;
270
+ }
271
+ </style>
272
+ """)
273
+
274
+ gr.Markdown("# 🚗 Busca de Combinações de Consórcio Auto")
275
+ gr.Markdown("Insira os valores desejados para crédito, entrada e parcela, e filtre por administradora.")
276
+
277
+ with gr.Row():
278
+ credito_input = gr.Number(label="Crédito Desejado (R$)", value=30000, step=1000)
279
+ entrada_input = gr.Number(label="Entrada Desejada (R$)", value=3000, step=100)
280
+ parcela_input = gr.Number(label="Parcela Desejada (R$)", value=500, step=10)
281
+
282
+ adm_input = gr.Dropdown(
283
+ choices=ADMIN_OPCOES,
284
+ label="Filtrar por Administradoras",
285
+ multiselect=True,
286
+ value=ADMIN_OPCOES,
287
+ interactive=True
288
+ )
289
+
290
+ submit_btn = gr.Button("🔍 Buscar Combinações AUTO", variant="primary")
291
+ output_text = gr.Textbox(
292
+ label="Resultados AUTO",
293
+ lines=20,
294
+ max_lines=40,
295
+ interactive=False,
296
+ placeholder="Os resultados aparecerão aqui..."
297
+ )
298
+
299
+ submit_btn.click(
300
+ fn=buscar_combinacoes,
301
+ inputs=[credito_input, entrada_input, parcela_input, adm_input],
302
+ outputs=output_text
303
+ )
304
+
305
+ gr.Markdown("---")
306
+ gr.Markdown("Desenvolvido para auxiliar na busca por cotas de consórcio automotivo.")
307
+
308
+
309
+ # Executar o app
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  if __name__ == "__main__":
311
+ demo_auto.launch()
312
+ #