Arthur-Attili commited on
Commit
fd52550
·
verified ·
1 Parent(s): 3b50042

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -19
app.py CHANGED
@@ -3,16 +3,19 @@ import requests
3
  import io
4
  import itertools
5
  from collections import defaultdict
6
- import gradio as gr
7
- import os
8
 
9
  # 🔧 CONFIGURAÇÕES GLOBAIS
 
 
10
  FILE_ID = "1EoH8V3Fyls0mNa95VcBN6ZL1B552ty3X"
11
  URL = f"https://drive.google.com/uc?export=download&id={FILE_ID}"
12
 
13
  # Variável global para armazenar o DataFrame
14
  df = None
15
 
 
16
  def carregar_planilha():
17
  """Carrega e prepara a planilha para análise de consórcios de automóveis."""
18
  global df
@@ -30,6 +33,7 @@ def carregar_planilha():
30
  if 'administradora' in df.columns:
31
  df['administradora'] = df['administradora'].astype(str).str.strip().str.lower()
32
 
 
33
  # Converte colunas numéricas
34
  numeric_cols = ['valor_credito', 'valor_entrada', 'valor_parcela', 'saldo_devedor', 'qtd_parcelas']
35
  for col in numeric_cols:
@@ -47,6 +51,7 @@ def carregar_planilha():
47
 
48
  except Exception as e:
49
  print(f"❌ Erro ao carregar planilha: {str(e)}")
 
50
  return False
51
 
52
  def agrupar_por_administradora(dataframe):
@@ -81,14 +86,13 @@ def buscar_combinacoes(credito_desejado, entrada_desejada, parcela_desejada, adm
81
 
82
  grupos = agrupar_por_administradora(df_filtrado)
83
  resultados = []
84
- MAX_COMBINACOES_POR_ADM = 2000 # Aumentado para permitir mais combinações
85
 
86
  for adm, cotas in grupos.items():
87
- cotas = cotas[:25] # Aumentado para 25 cotas por administradora
88
  combinacoes_validas = 0
89
 
90
- # ALTERAÇÃO PRINCIPAL: Aumentado de 5 para 10 cotas por combinação
91
- for r in range(1, min(10, len(cotas)) + 1): # Agora até 10 cotas por combinação
92
  for combinacao in itertools.combinations(cotas, r):
93
  if combinacoes_validas >= MAX_COMBINACOES_POR_ADM:
94
  break
@@ -116,7 +120,7 @@ def buscar_combinacoes(credito_desejado, entrada_desejada, parcela_desejada, adm
116
  resultados.sort(key=lambda x: x[2])
117
 
118
  # Limita o número total de resultados para evitar sobrecarga
119
- resultados = resultados[:800] # Aumentado para mostrar mais resultados
120
 
121
  return formatar_resultados(resultados)
122
 
@@ -127,37 +131,60 @@ def formatar_resultados(resultados):
127
  """Formata os resultados para exibição."""
128
  resposta = ""
129
 
 
 
 
130
  grouped_by_adm = defaultdict(list)
131
  for adm, combinacao, diferenca in resultados:
132
  grouped_by_adm[adm].append((combinacao, diferenca))
133
 
 
134
  for adm in grouped_by_adm:
135
- grouped_by_adm[adm].sort(key=lambda x: x[1])
136
 
137
  final_resultados_diversificados = []
138
 
 
 
139
  adm_indices = {adm: 0 for adm in grouped_by_adm.keys()}
 
 
140
  active_adms = list(grouped_by_adm.keys())
141
- current_adm_idx = 0
142
 
143
- while len(final_resultados_diversificados) < 20 and active_adms: # Aumentado para 20 resultados
 
 
 
 
144
  adm_da_vez = active_adms[current_adm_idx]
 
 
145
  idx_na_adm = adm_indices[adm_da_vez]
146
 
 
147
  if idx_na_adm < len(grouped_by_adm[adm_da_vez]):
 
148
  combinacao_data, _ = grouped_by_adm[adm_da_vez][idx_na_adm]
 
 
149
  final_resultados_diversificados.append((adm_da_vez, combinacao_data))
 
 
150
  adm_indices[adm_da_vez] += 1
151
  else:
 
152
  active_adms.pop(current_adm_idx)
 
153
  if current_adm_idx >= len(active_adms) and active_adms:
154
- current_adm_idx = 0
155
 
156
- if active_adms:
 
157
  current_adm_idx = (current_adm_idx + 1) % len(active_adms)
158
  else:
159
- break
160
 
 
161
  for idx, (adm, combinacao) in enumerate(final_resultados_diversificados, 1):
162
  codigos = [str(c.get('codigo', 'N/A')) for c in combinacao]
163
  total_credito = sum(c['valor_credito'] for c in combinacao)
@@ -173,12 +200,14 @@ def formatar_resultados(resultados):
173
  taxa_percentual = (taxa_total / credito_real) * 100 if credito_real > 0 else 0
174
  taxa_mensal = taxa_percentual / maior_prazo if maior_prazo > 0 else 0
175
 
 
 
176
  resposta += f"""
177
  --- COMBINAÇÃO {idx} ---
178
- 🏢 Administradora: {adm.upper()}
179
  🔢 Códigos: {', '.join(codigos)}
180
  💰 Crédito Total: {formatar_moeda(total_credito)}
181
- 💵 Entrada (+comissão): {formatar_moeda(total_entrada)}
182
  📉 Saldo Devedor: {formatar_moeda(total_saldo)}
183
  💲 Parcela: {formatar_moeda(total_parcelas)}
184
  ⏳ Prazo: {maior_prazo} meses
@@ -192,17 +221,21 @@ def formatar_resultados(resultados):
192
  return resposta
193
 
194
  # --- INICIALIZAÇÃO PARA GRADIO ---
 
 
195
  if not carregar_planilha():
196
  print("⚠️ Aviso: Planilha não carregada na inicialização. Tentará carregar na primeira busca.")
197
 
 
198
  def ajustar_e_buscar(credito_desejado, entrada_desejada, parcela_desejada, administradoras):
199
  entrada_calculada = credito_desejado * 0.085 + entrada_desejada
200
  return buscar_combinacoes(credito_desejado, entrada_calculada, parcela_desejada, administradoras)
201
 
 
202
  def get_administradoras_options():
203
  if df is not None:
204
  adm_list = df[df['tipo_do_bem'].str.lower() == 'auto']['administradora'].unique()
205
- return sorted(adm_list.tolist())
206
  return []
207
 
208
  # --- Interface Gradio ---
@@ -219,6 +252,7 @@ with gr.Blocks(title="Sistema de Busca de Consórcio de Automóveis") as demo:
219
  color: black !important;
220
  }
221
 
 
222
  input[type="number"] {
223
  background-color: white !important;
224
  border: 2px solid #000 !important;
@@ -228,6 +262,7 @@ with gr.Blocks(title="Sistema de Busca de Consórcio de Automóveis") as demo:
228
  font-weight: 500;
229
  }
230
 
 
231
  input[type="text"], textarea {
232
  background-color: white !important;
233
  border: 2px solid black !important;
@@ -285,22 +320,24 @@ with gr.Blocks(title="Sistema de Busca de Consórcio de Automóveis") as demo:
285
  administradoras_multiselect = gr.CheckboxGroup(
286
  label="Filtrar por Administradoras",
287
  choices=administradoras_options,
288
- value=administradoras_options,
289
  interactive=True
290
  )
291
 
292
  submit_btn = gr.Button("🔍 Buscar Combinações", variant="primary")
293
 
294
- output_text = gr.Textbox(label="Resultados da Busca", lines=25, max_lines=50, interactive=False, placeholder="Os resultados aparecerão aqui...")
295
 
 
296
  submit_btn.click(
297
  fn=ajustar_e_buscar,
298
  inputs=[credito_input, entrada_input, parcela_input, administradoras_multiselect],
299
  outputs=output_text
300
  )
301
 
 
302
  gr.Markdown("---")
303
  gr.Markdown("Ferramenta desenvolvida para otimizar a busca por consórcios de automóveis.")
304
 
305
  if __name__ == "__main__":
306
- demo.launch()
 
3
  import io
4
  import itertools
5
  from collections import defaultdict
6
+ import gradio as gr # Importação principal para Gradio
7
+ import os # Para variáveis de ambiente, se necessário
8
 
9
  # 🔧 CONFIGURAÇÕES GLOBAIS
10
+ # O ID da planilha para Consórcio de Automóveis
11
+ # Certifique-se de que este FILE_ID esteja acessível publicamente ou para "Qualquer pessoa com o link"
12
  FILE_ID = "1EoH8V3Fyls0mNa95VcBN6ZL1B552ty3X"
13
  URL = f"https://drive.google.com/uc?export=download&id={FILE_ID}"
14
 
15
  # Variável global para armazenar o DataFrame
16
  df = None
17
 
18
+
19
  def carregar_planilha():
20
  """Carrega e prepara a planilha para análise de consórcios de automóveis."""
21
  global df
 
33
  if 'administradora' in df.columns:
34
  df['administradora'] = df['administradora'].astype(str).str.strip().str.lower()
35
 
36
+
37
  # Converte colunas numéricas
38
  numeric_cols = ['valor_credito', 'valor_entrada', 'valor_parcela', 'saldo_devedor', 'qtd_parcelas']
39
  for col in numeric_cols:
 
51
 
52
  except Exception as e:
53
  print(f"❌ Erro ao carregar planilha: {str(e)}")
54
+ # Retorne uma mensagem de erro mais útil para o usuário
55
  return False
56
 
57
  def agrupar_por_administradora(dataframe):
 
86
 
87
  grupos = agrupar_por_administradora(df_filtrado)
88
  resultados = []
89
+ MAX_COMBINACOES_POR_ADM = 1000 # Limite para evitar processamento excessivo
90
 
91
  for adm, cotas in grupos.items():
92
+ cotas = cotas[:20] # Limita a 20 cotas por administradora para evitar combinações explosivas
93
  combinacoes_validas = 0
94
 
95
+ for r in range(1, min(5, len(cotas)) + 1): # Agora até 5 cotas
 
96
  for combinacao in itertools.combinations(cotas, r):
97
  if combinacoes_validas >= MAX_COMBINACOES_POR_ADM:
98
  break
 
120
  resultados.sort(key=lambda x: x[2])
121
 
122
  # Limita o número total de resultados para evitar sobrecarga
123
+ resultados = resultados[:500]
124
 
125
  return formatar_resultados(resultados)
126
 
 
131
  """Formata os resultados para exibição."""
132
  resposta = ""
133
 
134
+ # 1. Agrupar os resultados por administradora, mantendo a diferença para ordenação interna
135
+ # grouped_by_adm = {'Administradora X': [(combinacao_A, 100), (combinacao_C, 180), ...],
136
+ # 'Administradora Y': [(combinacao_B, 150), ...]}
137
  grouped_by_adm = defaultdict(list)
138
  for adm, combinacao, diferenca in resultados:
139
  grouped_by_adm[adm].append((combinacao, diferenca))
140
 
141
+ # 2. Ordenar as combinações dentro de cada administradora pela diferença (do menor para o maior)
142
  for adm in grouped_by_adm:
143
+ grouped_by_adm[adm].sort(key=lambda x: x[1]) # x[1] é a diferença
144
 
145
  final_resultados_diversificados = []
146
 
147
+ # Dicionário para acompanhar o índice da próxima combinação a ser pega de cada administradora
148
+ # Ex: {'Itau': 0, 'Bradesco': 0, 'Caixa': 0}
149
  adm_indices = {adm: 0 for adm in grouped_by_adm.keys()}
150
+
151
+ # Lista de administradoras ativas (que ainda têm combinações disponíveis)
152
  active_adms = list(grouped_by_adm.keys())
 
153
 
154
+ current_adm_idx = 0 # Índice para ciclar entre as administradoras ativas
155
+
156
+ # Loop para selecionar até 15 combinações, garantindo diversidade
157
+ while len(final_resultados_diversificados) < 15 and active_adms:
158
+ # Pega a administradora da vez para selecionar uma combinação
159
  adm_da_vez = active_adms[current_adm_idx]
160
+
161
+ # Pega o índice da próxima combinação para essa administradora
162
  idx_na_adm = adm_indices[adm_da_vez]
163
 
164
+ # Verifica se essa administradora ainda tem combinações disponíveis
165
  if idx_na_adm < len(grouped_by_adm[adm_da_vez]):
166
+ # Pega a combinação (ignorando a diferença, que já foi usada para ordenar internamente)
167
  combinacao_data, _ = grouped_by_adm[adm_da_vez][idx_na_adm]
168
+
169
+ # Adiciona à lista de resultados final (com a administradora e a combinação)
170
  final_resultados_diversificados.append((adm_da_vez, combinacao_data))
171
+
172
+ # Incrementa o índice para a próxima vez que pegarmos dessa administradora
173
  adm_indices[adm_da_vez] += 1
174
  else:
175
+ # Se essa administradora não tem mais combinações, remove ela da lista de ativas
176
  active_adms.pop(current_adm_idx)
177
+ # Ajusta o current_adm_idx se a lista diminuiu e estamos no limite
178
  if current_adm_idx >= len(active_adms) and active_adms:
179
+ current_adm_idx = 0 # Volta para o início da lista se removemos o último
180
 
181
+ # Move para a próxima administradora no ciclo (garantindo que não estouramos o índice da lista active_adms)
182
+ if active_adms: # Só avança se ainda houver administradoras ativas
183
  current_adm_idx = (current_adm_idx + 1) % len(active_adms)
184
  else:
185
+ break # Não há mais administradoras ativas, sai do loop
186
 
187
+ # Agora, itera sobre os resultados diversificados para formatar a resposta
188
  for idx, (adm, combinacao) in enumerate(final_resultados_diversificados, 1):
189
  codigos = [str(c.get('codigo', 'N/A')) for c in combinacao]
190
  total_credito = sum(c['valor_credito'] for c in combinacao)
 
200
  taxa_percentual = (taxa_total / credito_real) * 100 if credito_real > 0 else 0
201
  taxa_mensal = taxa_percentual / maior_prazo if maior_prazo > 0 else 0
202
 
203
+ #comissao = total_entrada * (8.5 / 108.5)
204
+
205
  resposta += f"""
206
  --- COMBINAÇÃO {idx} ---
207
+ �� Administradora: {adm}
208
  🔢 Códigos: {', '.join(codigos)}
209
  💰 Crédito Total: {formatar_moeda(total_credito)}
210
+ �� Entrada (+comissão): {formatar_moeda(total_entrada)}
211
  📉 Saldo Devedor: {formatar_moeda(total_saldo)}
212
  💲 Parcela: {formatar_moeda(total_parcelas)}
213
  ⏳ Prazo: {maior_prazo} meses
 
221
  return resposta
222
 
223
  # --- INICIALIZAÇÃO PARA GRADIO ---
224
+ # Carrega a planilha UMA VEZ no início do aplicativo
225
+ # Se der erro, a função de busca tentará carregar novamente.
226
  if not carregar_planilha():
227
  print("⚠️ Aviso: Planilha não carregada na inicialização. Tentará carregar na primeira busca.")
228
 
229
+ # Calcula a entrada adicionando 8,5% ao valor final da entrada.
230
  def ajustar_e_buscar(credito_desejado, entrada_desejada, parcela_desejada, administradoras):
231
  entrada_calculada = credito_desejado * 0.085 + entrada_desejada
232
  return buscar_combinacoes(credito_desejado, entrada_calculada, parcela_desejada, administradoras)
233
 
234
+ # Prepara as opções para o seletor de administradoras do Gradio
235
  def get_administradoras_options():
236
  if df is not None:
237
  adm_list = df[df['tipo_do_bem'].str.lower() == 'auto']['administradora'].unique()
238
+ return sorted(adm_list.tolist()) # Converter para lista, pois .unique() pode retornar um numpy array
239
  return []
240
 
241
  # --- Interface Gradio ---
 
252
  color: black !important;
253
  }
254
 
255
+ /* Inputs Numéricos: Crédito, Entrada, Parcela */
256
  input[type="number"] {
257
  background-color: white !important;
258
  border: 2px solid #000 !important;
 
262
  font-weight: 500;
263
  }
264
 
265
+ /* Inputs de texto e áreas de texto (como a saída e código) */
266
  input[type="text"], textarea {
267
  background-color: white !important;
268
  border: 2px solid black !important;
 
320
  administradoras_multiselect = gr.CheckboxGroup(
321
  label="Filtrar por Administradoras",
322
  choices=administradoras_options,
323
+ value=administradoras_options, # Seleciona todas por padrão
324
  interactive=True
325
  )
326
 
327
  submit_btn = gr.Button("🔍 Buscar Combinações", variant="primary")
328
 
329
+ output_text = gr.Textbox(label="Resultados da Busca", lines=20, max_lines=40, interactive=False, placeholder="Os resultados aparecerão aqui...")
330
 
331
+ # Conecta o botão à função de busca
332
  submit_btn.click(
333
  fn=ajustar_e_buscar,
334
  inputs=[credito_input, entrada_input, parcela_input, administradoras_multiselect],
335
  outputs=output_text
336
  )
337
 
338
+
339
  gr.Markdown("---")
340
  gr.Markdown("Ferramenta desenvolvida para otimizar a busca por consórcios de automóveis.")
341
 
342
  if __name__ == "__main__":
343
+ demo.launch() # Você não precisa disso no Colab, mas sim no arquivo que você fará o deploy