Arthur-Attili commited on
Commit
ef1b089
·
verified ·
1 Parent(s): 2396962

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -139
app.py CHANGED
@@ -62,8 +62,8 @@ def agrupar_por_administradora(dataframe):
62
  grupos[row['administradora']].append(row.to_dict())
63
  return grupos
64
 
65
- def buscar_combinacoes_rapido(credito_desejado, entrada_desejada, parcela_desejada, administradoras=None):
66
- """Busca combinações de forma extremamente rápida com algoritmo inteligente."""
67
  if df is None:
68
  if not carregar_planilha():
69
  return "❌ Erro: Planilha não carregada."
@@ -78,161 +78,91 @@ def buscar_combinacoes_rapido(credito_desejado, entrada_desejada, parcela_deseja
78
  if df_filtrado.empty:
79
  return "🚫 Nenhuma cota encontrada com os filtros aplicados."
80
 
81
- # Tolerâncias mais amplas para melhor diversificação
82
- credito_min, credito_max = credito_desejado * 0.85, credito_desejado * 1.15
83
- entrada_min, entrada_max = entrada_desejada * 0.80, entrada_desejada * 1.20
84
- parcela_min, parcela_max = parcela_desejada * 0.60, parcela_desejada * 1.40
85
 
86
  grupos = agrupar_por_administradora(df_filtrado)
87
  resultados = []
88
 
89
  MIN_COTAS = 3
90
  MAX_COTAS = 10
91
- MAX_RESULTADOS_POR_ADM = 30
92
- TOTAL_MAX_RESULTADOS = 100
93
 
94
  for adm, cotas in grupos.items():
95
  if len(cotas) < MIN_COTAS:
96
  continue
97
 
98
- # Ordena cotas por proximidade do valor desejado (otimização)
99
- cotas_ordenadas = sorted(cotas, key=lambda x: abs(x['valor_credito'] - credito_desejado/MAX_COTAS))
100
 
101
- # Busca usando algoritmo ganancioso com backtracking limitado
102
- encontrados = buscar_combinacoes_inteligente(
103
- cotas_ordenadas, credito_min, credito_max, entrada_min,
104
- entrada_max, parcela_min, parcela_max, MIN_COTAS, MAX_COTAS,
105
- max_resultados=MAX_RESULTADOS_POR_ADM
106
- )
107
-
108
- for combo in encontrados:
109
- total_credito = sum(c['valor_credito'] for c in combo)
110
- total_entrada_base = sum(c['valor_entrada'] for c in combo)
111
- total_entrada = total_entrada_base + (total_credito * 0.085)
112
- total_saldo = sum(c['saldo_devedor'] for c in combo)
113
- valor_final = round(total_entrada + total_saldo, 2)
114
- diferenca = abs(valor_final - total_credito)
115
-
116
- resultados.append((adm, combo, diferenca))
117
-
118
- if len(resultados) >= TOTAL_MAX_RESULTADOS:
119
- break
 
 
 
 
 
 
 
 
120
 
121
- if len(resultados) >= TOTAL_MAX_RESULTADOS:
122
- break
 
 
 
123
 
124
  if not resultados:
125
- return "🚫 Nenhuma combinação adequada encontrada. Tente ampliar os filtros."
126
 
127
  # Ordena por melhor match
128
  resultados.sort(key=lambda x: x[2])
129
 
130
- return formatar_resultados(resultados[:20])
131
 
132
- def buscar_combinacoes_inteligente(cotas, credito_min, credito_max, entrada_min,
133
- entrada_max, parcela_min, parcela_max,
134
- min_cotas, max_cotas, max_resultados=30):
135
- """Algoritmo inteligente para encontrar combinações rapidamente."""
136
- resultados = []
137
- n = len(cotas)
138
-
139
- # Pré-calcula arrays para performance
140
- creditos = np.array([c['valor_credito'] for c in cotas])
141
- entradas = np.array([c['valor_entrada'] for c in cotas])
142
- parcelas = np.array([c['valor_parcela'] for c in cotas])
143
- saldos = np.array([c['saldo_devedor'] for c in cotas])
144
-
145
- # Função de avaliação rápida
146
- def avalia_combinacao(indices):
147
- total_credito = creditos[indices].sum()
148
- total_entrada_base = entradas[indices].sum()
149
- total_entrada = total_entrada_base + (total_credito * 0.085)
150
- total_parcelas = parcelas[indices].sum()
151
 
152
- return (credito_min <= total_credito <= credito_max and
153
- entrada_min <= total_entrada <= entrada_max and
154
- parcela_min <= total_parcelas <= parcela_max)
155
-
156
- # Estratégia 1: Combinações de tamanho fixo (3-6 cotas) - mais rápido
157
- for tamanho in range(min_cotas, min(7, max_cotas + 1)):
158
- if len(resultados) >= max_resultados:
159
- break
160
-
161
- # Amostra aleatória de combinações para evitar explosão combinatória
162
- indices = list(range(n))
163
- np.random.shuffle(indices) # Embaralha para diversidade
164
 
165
- # Testa um número limitado de combinações
166
- for combo_indices in islice(combinations(indices, tamanho), 1000):
167
- if avalia_combinacao(combo_indices):
168
- combo = [cotas[i] for i in combo_indices]
169
- resultados.append(combo)
170
-
171
- if len(resultados) >= max_resultados:
172
- break
173
-
174
- # Estratégia 2: Para combinações maiores (7-10 cotas), usa algoritmo ganancioso
175
- if len(resultados) < max_resultados and max_cotas >= 7:
176
- for _ in range(min(50, max_resultados - len(resultados))):
177
- combo = []
178
- indices_usados = set()
179
-
180
- # Adiciona cotas até atingir o objetivo
181
- for tentativa in range(max_cotas):
182
- melhor_idx = None
183
- melhor_score = float('inf')
184
-
185
- # Encontra a melhor cota para adicionar
186
- for idx in range(n):
187
- if idx in indices_usados:
188
- continue
189
-
190
- combo_teste = combo + [cotas[idx]]
191
- indices_teste = list(indices_usados) + [idx]
192
-
193
- total_credito = sum(c['valor_credito'] for c in combo_teste)
194
- score = abs(total_credito - (credito_max + credito_min)/2)
195
-
196
- if score < melhor_score:
197
- melhor_score = score
198
- melhor_idx = idx
199
-
200
- if melhor_idx is not None:
201
- combo.append(cotas[melhor_idx])
202
- indices_usados.add(melhor_idx)
203
-
204
- # Verifica se a combinação atual é válida
205
- if len(combo) >= min_cotas and avalia_combinacao(list(indices_usados)):
206
- resultados.append(combo.copy())
207
- if len(resultados) >= max_resultados:
208
- break
209
-
210
- if len(resultados) >= max_resultados:
211
- break
212
-
213
- return resultados[:max_resultados]
214
-
215
- # Função principal ajustada
216
- def ajustar_e_buscar(credito_desejado, entrada_desejada, parcela_desejada, administradoras):
217
- entrada_calculada = credito_desejado * 0.085 + entrada_desejada
218
-
219
- start_time = time.time()
220
- resultado = buscar_combinacoes_rapido(
221
- credito_desejado, entrada_calculada, parcela_desejada, administradoras
222
- )
223
-
224
- elapsed = time.time() - start_time
225
- print(f"⏱️ Busca concluída em {elapsed:.2f} segundos")
226
-
227
- return resultado
228
 
229
- # Atualize a interface para mostrar estatísticas
230
  def formatar_resultados(resultados):
231
- """Formata os resultados com informações de diversificação."""
232
- if not resultados:
233
- return "🚫 Nenhuma combinação encontrada."
234
-
235
- resposta = f"📊 **Encontradas {len(resultados)} combinações**\n\n"
236
 
237
  for idx, (adm, combinacao, diferenca) in enumerate(resultados, 1):
238
  codigos = [str(c.get('codigo', 'N/A')) for c in combinacao]
@@ -250,19 +180,19 @@ def formatar_resultados(resultados):
250
  taxa_mensal = taxa_percentual / maior_prazo if maior_prazo > 0 else 0
251
 
252
  resposta += f"""
253
- --- COMBINAÇÃO {idx} ({len(combinacao)} cotas) ---
254
  🏢 Administradora: {adm}
255
  🔢 Códigos: {', '.join(codigos)}
256
  💰 Crédito Total: {formatar_moeda(total_credito)}
257
- 💵 Entrada (+comissão): {formatar_moeda(total_entrada)}
258
  📉 Saldo Devedor: {formatar_moeda(total_saldo)}
259
- 💲 Parcela: {formatar_moeda(total_parcelas)}
260
- ⏳ Prazo: {maior_prazo} meses
261
  🔚 Valor Final: {formatar_moeda(valor_final)}
262
  💠 Crédito Líquido: {formatar_moeda(credito_real)}
263
- 📊 Taxa Total: {taxa_percentual:.2f}% ({formatar_moeda(taxa_total)})
264
  🗓️ Taxa Mensal: {taxa_mensal:.2f}%
265
- 🗓️ Taxa Anual: {taxa_mensal * 12:.2f}%
266
  """
267
  return resposta
268
 
 
62
  grupos[row['administradora']].append(row.to_dict())
63
  return grupos
64
 
65
+ def buscar_combinacoes_eficiente(credito_desejado, entrada_desejada, parcela_desejada, administradoras=None):
66
+ """Busca combinações de forma eficiente e garantida."""
67
  if df is None:
68
  if not carregar_planilha():
69
  return "❌ Erro: Planilha não carregada."
 
78
  if df_filtrado.empty:
79
  return "🚫 Nenhuma cota encontrada com os filtros aplicados."
80
 
81
+ # Tolerâncias amplas para garantir resultados
82
+ credito_min, credito_max = credito_desejado * 0.80, credito_desejado * 1.20
83
+ entrada_min, entrada_max = entrada_desejada * 0.75, entrada_desejada * 1.25
84
+ parcela_min, parcela_max = parcela_desejada * 0.50, parcela_desejada * 1.50
85
 
86
  grupos = agrupar_por_administradora(df_filtrado)
87
  resultados = []
88
 
89
  MIN_COTAS = 3
90
  MAX_COTAS = 10
 
 
91
 
92
  for adm, cotas in grupos.items():
93
  if len(cotas) < MIN_COTAS:
94
  continue
95
 
96
+ # Ordena por valor de crédito (otimização)
97
+ cotas_ordenadas = sorted(cotas, key=lambda x: x['valor_credito'])
98
 
99
+ # Busca combinações de forma inteligente
100
+ for tamanho in range(MIN_COTAS, min(MAX_COTAS + 1, len(cotas_ordenadas) + 1)):
101
+ # Usa amostragem para evitar explosão combinatória
102
+ for i in range(0, len(cotas_ordenadas), max(1, len(cotas_ordenadas) // 10)):
103
+ for j in range(i + tamanho, min(i + 50, len(cotas_ordenadas))):
104
+ combinacao = cotas_ordenadas[i:j]
105
+ if len(combinacao) != tamanho:
106
+ continue
107
+
108
+ total_credito = sum(c['valor_credito'] for c in combinacao)
109
+ total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
110
+ total_entrada = total_entrada_base + (total_credito * 0.085)
111
+ total_parcelas = sum(c['valor_parcela'] for c in combinacao)
112
+
113
+ if (credito_min <= total_credito <= credito_max and
114
+ entrada_min <= total_entrada <= entrada_max and
115
+ parcela_min <= total_parcelas <= parcela_max):
116
+
117
+ total_saldo = sum(c['saldo_devedor'] for c in combinacao)
118
+ valor_final = round(total_entrada + total_saldo, 2)
119
+ diferenca = abs(valor_final - total_credito)
120
+
121
+ resultados.append((adm, combinacao, diferenca))
122
+
123
+ # Limita resultados por administradora
124
+ if len(resultados) >= 50:
125
+ break
126
 
127
+ if len(resultados) >= 50:
128
+ break
129
+
130
+ if len(resultados) >= 50:
131
+ break
132
 
133
  if not resultados:
134
+ return "🚫 Nenhuma combinação adequada encontrada. Tente ampliar os filtros ou ajustar os valores."
135
 
136
  # Ordena por melhor match
137
  resultados.sort(key=lambda x: x[2])
138
 
139
+ return formatar_resultados(resultados[:15])
140
 
141
+ # Substitua a função de busca
142
+ def ajustar_e_buscar(credito_desejado, entrada_desejada, parcela_desejada, administradoras):
143
+ try:
144
+ entrada_calculada = credito_desejado * 0.085 + entrada_desejada
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
+ start_time = time.time()
147
+ resultado = buscar_combinacoes_eficiente(
148
+ credito_desejado, entrada_calculada, parcela_desejada, administradoras
149
+ )
 
 
 
 
 
 
 
 
150
 
151
+ elapsed = time.time() - start_time
152
+ print(f"✅ Busca concluída em {elapsed:.2f} segundos")
153
+
154
+ return resultado
155
+
156
+ except Exception as e:
157
+ return f"❌ Erro durante a busca: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
+ # Função de formatação atualizada
160
  def formatar_resultados(resultados):
161
+ """Formata os resultados para exibição."""
162
+ if not resultados or isinstance(resultados, str):
163
+ return resultados
164
+
165
+ resposta = f"🎯 **{len(resultados)} combinações encontradas**\n\n"
166
 
167
  for idx, (adm, combinacao, diferenca) in enumerate(resultados, 1):
168
  codigos = [str(c.get('codigo', 'N/A')) for c in combinacao]
 
180
  taxa_mensal = taxa_percentual / maior_prazo if maior_prazo > 0 else 0
181
 
182
  resposta += f"""
183
+ --- COMBINAÇÃO {idx} ({len(combinacao)} COTAS) ---
184
  🏢 Administradora: {adm}
185
  🔢 Códigos: {', '.join(codigos)}
186
  💰 Crédito Total: {formatar_moeda(total_credito)}
187
+ 💵 Entrada (+8.5%): {formatar_moeda(total_entrada)}
188
  📉 Saldo Devedor: {formatar_moeda(total_saldo)}
189
+ 💲 Parcela Total: {formatar_moeda(total_parcelas)}
190
+ Maior Prazo: {maior_prazo} meses
191
  🔚 Valor Final: {formatar_moeda(valor_final)}
192
  💠 Crédito Líquido: {formatar_moeda(credito_real)}
193
+ 📊 Taxa Total: {taxa_percentual:.2f}%
194
  🗓️ Taxa Mensal: {taxa_mensal:.2f}%
195
+ 📈 Taxa Anual: {taxa_mensal * 12:.2f}%
196
  """
197
  return resposta
198