Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -85,16 +85,29 @@ def buscar_combinacoes_otimizado(credito_desejado, entrada_desejada, parcela_des
|
|
| 85 |
if not grupos_filtrados:
|
| 86 |
return "🚫 Nenhuma cota encontrada com os filtros aplicados. Tente ajustar os parâmetros."
|
| 87 |
|
| 88 |
-
# TOLERÂNCIAS -
|
| 89 |
-
# Para valores altos,
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
|
| 99 |
# Define faixas de tolerância
|
| 100 |
credito_min = credito_desejado * (1 - tolerancia_credito)
|
|
@@ -104,26 +117,36 @@ def buscar_combinacoes_otimizado(credito_desejado, entrada_desejada, parcela_des
|
|
| 104 |
parcela_min = parcela_desejada * (1 - tolerancia_parcela)
|
| 105 |
parcela_max = parcela_desejada * (1 + tolerancia_parcela)
|
| 106 |
|
| 107 |
-
print(f"🔧
|
| 108 |
-
print(f"🔧
|
| 109 |
|
| 110 |
resultados = []
|
| 111 |
|
| 112 |
# Para cada administradora, busca combinações
|
| 113 |
for adm, cotas in grupos_filtrados.items():
|
| 114 |
-
#
|
| 115 |
-
|
| 116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
|
| 118 |
-
#
|
| 119 |
-
|
|
|
|
| 120 |
|
| 121 |
-
|
|
|
|
| 122 |
# Limita o número de combinações testadas por administradora
|
| 123 |
-
max_combinacoes_por_adm =
|
| 124 |
combinacoes_geradas = 0
|
| 125 |
|
| 126 |
-
for combinacao in itertools.combinations(
|
| 127 |
if combinacoes_geradas >= max_combinacoes_por_adm:
|
| 128 |
break
|
| 129 |
|
|
@@ -132,7 +155,6 @@ def buscar_combinacoes_otimizado(credito_desejado, entrada_desejada, parcela_des
|
|
| 132 |
total_entrada = total_entrada_base + (total_credito * 0.085)
|
| 133 |
total_parcelas = sum(c['valor_parcela'] for c in combinacao)
|
| 134 |
|
| 135 |
-
# Verifica se a combinação está dentro das tolerâncias
|
| 136 |
if (credito_min <= total_credito <= credito_max and
|
| 137 |
entrada_min <= total_entrada <= entrada_max and
|
| 138 |
parcela_min <= total_parcelas <= parcela_max):
|
|
@@ -145,76 +167,7 @@ def buscar_combinacoes_otimizado(credito_desejado, entrada_desejada, parcela_des
|
|
| 145 |
combinacoes_geradas += 1
|
| 146 |
|
| 147 |
# Para se já encontrou combinações suficientes
|
| 148 |
-
if len(resultados) >= max_combinacoes *
|
| 149 |
-
break
|
| 150 |
-
|
| 151 |
-
if len(resultados) >= max_combinacoes * 5:
|
| 152 |
-
break
|
| 153 |
-
|
| 154 |
-
if len(resultados) >= max_combinacoes * 5:
|
| 155 |
-
break
|
| 156 |
-
|
| 157 |
-
if not resultados:
|
| 158 |
-
# Tenta uma busca mais ampla se não encontrou resultados
|
| 159 |
-
return buscar_combinacoes_amplo(credito_desejado, entrada_desejada, parcela_desejada, administradoras, max_combinacoes)
|
| 160 |
-
|
| 161 |
-
# Ordena pela diferença e pega as melhores
|
| 162 |
-
resultados.sort(key=lambda x: x[2])
|
| 163 |
-
return formatar_resultados(resultados[:max_combinacoes])
|
| 164 |
-
|
| 165 |
-
def buscar_combinacoes_amplo(credito_desejado, entrada_desejada, parcela_desejada, administradoras=None, max_combinacoes=10):
|
| 166 |
-
"""Busca combinações com tolerâncias mais amplas para valores altos."""
|
| 167 |
-
global grupos_imovel
|
| 168 |
-
|
| 169 |
-
# Filtra administradoras se especificado
|
| 170 |
-
if administradoras:
|
| 171 |
-
grupos_filtrados = {adm: cotas for adm, cotas in grupos_imovel.items() if adm in administradoras}
|
| 172 |
-
else:
|
| 173 |
-
grupos_filtrados = grupos_imovel
|
| 174 |
-
|
| 175 |
-
# Tolerâncias mais amplas para valores altos
|
| 176 |
-
tolerancia_credito = 0.20 # 20%
|
| 177 |
-
tolerancia_entrada = 0.20 # 20%
|
| 178 |
-
tolerancia_parcela = 0.50 # 50%
|
| 179 |
-
|
| 180 |
-
credito_min = credito_desejado * (1 - tolerancia_credito)
|
| 181 |
-
credito_max = credito_desejado * (1 + tolerancia_credito)
|
| 182 |
-
entrada_min = entrada_desejada * (1 - tolerancia_entrada)
|
| 183 |
-
entrada_max = entrada_desejada * (1 + tolerancia_entrada)
|
| 184 |
-
parcela_min = parcela_desejada * (1 - tolerancia_parcela)
|
| 185 |
-
parcela_max = parcela_desejada * (1 + tolerancia_parcela)
|
| 186 |
-
|
| 187 |
-
print(f"🔧 Busca ampla: Tolerâncias: Crédito: ±{tolerancia_credito*100:.1f}%, Entrada: ±{tolerancia_entrada*100:.1f}%, Parcela: ±{tolerancia_parcela*100:.1f}%")
|
| 188 |
-
|
| 189 |
-
resultados = []
|
| 190 |
-
|
| 191 |
-
for adm, cotas in grupos_filtrados.items():
|
| 192 |
-
# Gera combinações (até 6 cotas por combinação)
|
| 193 |
-
for r in range(1, min(7, len(cotas) + 1)):
|
| 194 |
-
combinacoes_geradas = 0
|
| 195 |
-
max_combinacoes_por_adm = 150
|
| 196 |
-
|
| 197 |
-
for combinacao in itertools.combinations(cotas, r):
|
| 198 |
-
if combinacoes_geradas >= max_combinacoes_por_adm:
|
| 199 |
-
break
|
| 200 |
-
|
| 201 |
-
total_credito = sum(c['valor_credito'] for c in combinacao)
|
| 202 |
-
total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
|
| 203 |
-
total_entrada = total_entrada_base + (total_credito * 0.085)
|
| 204 |
-
total_parcelas = sum(c['valor_parcela'] for c in combinacao)
|
| 205 |
-
|
| 206 |
-
if (credito_min <= total_credito <= credito_max and
|
| 207 |
-
entrada_min <= total_entrada <= entrada_max and
|
| 208 |
-
parcela_min <= total_parcelas <= parcela_max):
|
| 209 |
-
|
| 210 |
-
total_saldo = sum(c['saldo_devedor'] for c in combinacao)
|
| 211 |
-
valor_final = round(total_entrada + total_saldo, 2)
|
| 212 |
-
diferenca = abs(valor_final - total_credito)
|
| 213 |
-
|
| 214 |
-
resultados.append((adm, combinacao, diferenca))
|
| 215 |
-
combinacoes_geradas += 1
|
| 216 |
-
|
| 217 |
-
if len(resultados) >= max_combinacoes * 3:
|
| 218 |
break
|
| 219 |
|
| 220 |
if len(resultados) >= max_combinacoes * 3:
|
|
@@ -226,6 +179,7 @@ def buscar_combinacoes_amplo(credito_desejado, entrada_desejada, parcela_desejad
|
|
| 226 |
if not resultados:
|
| 227 |
return "🚫 Nenhuma combinação adequada encontrada com os parâmetros fornecidos."
|
| 228 |
|
|
|
|
| 229 |
resultados.sort(key=lambda x: x[2])
|
| 230 |
return formatar_resultados(resultados[:max_combinacoes])
|
| 231 |
|
|
|
|
| 85 |
if not grupos_filtrados:
|
| 86 |
return "🚫 Nenhuma cota encontrada com os filtros aplicados. Tente ajustar os parâmetros."
|
| 87 |
|
| 88 |
+
# TOLERÂNCIAS ADAPTATIVAS - Ajusta com base no valor
|
| 89 |
+
# Para valores altos, aumenta a tolerância percentual
|
| 90 |
+
def calcular_tolerancia(valor, tolerancia_base, tolerancia_min, tolerancia_max):
|
| 91 |
+
if valor > 1000000: # Para valores acima de 1 milhão
|
| 92 |
+
# Aumenta a tolerância para valores muito altos
|
| 93 |
+
fator = min(tolerancia_max, tolerancia_base * (1 + math.log10(valor / 1000000) * 0.2))
|
| 94 |
+
return fator
|
| 95 |
+
return tolerancia_base
|
| 96 |
+
|
| 97 |
+
# Tolerâncias base
|
| 98 |
+
tolerancia_credito_base = 0.10 # 10%
|
| 99 |
+
tolerancia_entrada_base = 0.10 # 10%
|
| 100 |
+
tolerancia_parcela_base = 0.30 # 30%
|
| 101 |
+
|
| 102 |
+
# Tolerâncias máximas
|
| 103 |
+
tolerancia_max_credito = 0.40 # 40%
|
| 104 |
+
tolerancia_max_entrada = 0.40 # 40%
|
| 105 |
+
tolerancia_max_parcela = 0.60 # 60%
|
| 106 |
+
|
| 107 |
+
# Calcula tolerâncias adaptativas
|
| 108 |
+
tolerancia_credito = calcular_tolerancia(credito_desejado, tolerancia_credito_base, tolerancia_credito_base, tolerancia_max_credito)
|
| 109 |
+
tolerancia_entrada = calcular_tolerancia(entrada_desejada, tolerancia_entrada_base, tolerancia_entrada_base, tolerancia_max_entrada)
|
| 110 |
+
tolerancia_parcela = calcular_tolerancia(parcela_desejada, tolerancia_parcela_base, tolerancia_parcela_base, tolerancia_max_parcela)
|
| 111 |
|
| 112 |
# Define faixas de tolerância
|
| 113 |
credito_min = credito_desejado * (1 - tolerancia_credito)
|
|
|
|
| 117 |
parcela_min = parcela_desejada * (1 - tolerancia_parcela)
|
| 118 |
parcela_max = parcela_desejada * (1 + tolerancia_parcela)
|
| 119 |
|
| 120 |
+
print(f"🔧 Tolerâncias aplicadas: Crédito: ±{tolerancia_credito*100:.1f}%, Entrada: ±{tolerancia_entrada*100:.1f}%, Parcela: ±{tolerancia_parcela*100:.1f}%")
|
| 121 |
+
print(f"🔧 Faixas: Crédito: {credito_min:,.0f} - {credito_max:,.0f}, Entrada: {entrada_min:,.0f} - {entrada_max:,.0f}, Parcela: {parcela_min:,.0f} - {parcela_max:,.0f}")
|
| 122 |
|
| 123 |
resultados = []
|
| 124 |
|
| 125 |
# Para cada administradora, busca combinações
|
| 126 |
for adm, cotas in grupos_filtrados.items():
|
| 127 |
+
# Pré-filtra cotas que individualmente estão dentro das faixas de tolerância
|
| 128 |
+
cotas_filtradas = []
|
| 129 |
+
for cota in cotas:
|
| 130 |
+
cota_credito = cota['valor_credito']
|
| 131 |
+
cota_entrada = cota['valor_entrada'] + (cota_credito * 0.085)
|
| 132 |
+
cota_parcela = cota['valor_parcela']
|
| 133 |
+
|
| 134 |
+
if (credito_min <= cota_credito <= credito_max and
|
| 135 |
+
entrada_min <= cota_entrada <= entrada_max and
|
| 136 |
+
parcela_min <= cota_parcela <= parcela_max):
|
| 137 |
+
cotas_filtradas.append(cota)
|
| 138 |
|
| 139 |
+
# Se não há cotas individuais dentro da tolerância, tenta combinações
|
| 140 |
+
if not cotas_filtradas:
|
| 141 |
+
cotas_filtradas = cotas # Usa todas as cotas para combinações
|
| 142 |
|
| 143 |
+
# Gera combinações (até 3 cotas por combinação para performance)
|
| 144 |
+
for r in range(1, min(4, len(cotas_filtradas) + 1)):
|
| 145 |
# Limita o número de combinações testadas por administradora
|
| 146 |
+
max_combinacoes_por_adm = 50
|
| 147 |
combinacoes_geradas = 0
|
| 148 |
|
| 149 |
+
for combinacao in itertools.combinations(cotas_filtradas, r):
|
| 150 |
if combinacoes_geradas >= max_combinacoes_por_adm:
|
| 151 |
break
|
| 152 |
|
|
|
|
| 155 |
total_entrada = total_entrada_base + (total_credito * 0.085)
|
| 156 |
total_parcelas = sum(c['valor_parcela'] for c in combinacao)
|
| 157 |
|
|
|
|
| 158 |
if (credito_min <= total_credito <= credito_max and
|
| 159 |
entrada_min <= total_entrada <= entrada_max and
|
| 160 |
parcela_min <= total_parcelas <= parcela_max):
|
|
|
|
| 167 |
combinacoes_geradas += 1
|
| 168 |
|
| 169 |
# Para se já encontrou combinações suficientes
|
| 170 |
+
if len(resultados) >= max_combinacoes * 3: # Coleta mais para depois filtrar as melhores
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
break
|
| 172 |
|
| 173 |
if len(resultados) >= max_combinacoes * 3:
|
|
|
|
| 179 |
if not resultados:
|
| 180 |
return "🚫 Nenhuma combinação adequada encontrada com os parâmetros fornecidos."
|
| 181 |
|
| 182 |
+
# Ordena pela diferença e pega as melhores
|
| 183 |
resultados.sort(key=lambda x: x[2])
|
| 184 |
return formatar_resultados(resultados[:max_combinacoes])
|
| 185 |
|