Arthur-Attili commited on
Commit
e638816
·
verified ·
1 Parent(s): 356e1a4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +59 -196
app.py CHANGED
@@ -1,10 +1,4 @@
1
- """Imovel.ipynb
2
- Automatically generated by Colab.
3
- Original file is located at
4
- https://colab.research.google.com/drive/1DZAQZfrXvTy358Vg2qfUg_ge6b3kcgBy
5
- """
6
-
7
- # app.py
8
  import pandas as pd
9
  import requests
10
  import io
@@ -12,18 +6,20 @@ import itertools
12
  from collections import defaultdict
13
  import gradio as gr
14
  import time
 
15
 
16
  # 🔧 CONFIGURAÇÕES GLOBAIS
17
- # Certifique-se de que este FILE_ID esteja acessível publicamente ou para "Qualquer pessoa com o link"
18
  FILE_ID = "1XvNz7DlWioT64uNdcfBSL8Ui2nRSi9gT"
19
  URL = f"https://drive.google.com/uc?export=download&id={FILE_ID}"
20
 
21
- # Variável global para armazenar o DataFrame
22
  df = None
 
 
23
 
24
  def carregar_planilha():
25
  """Carrega e prepara a planilha para análise."""
26
- global df
27
  try:
28
  print("⏳ Carregando planilha...")
29
  response = requests.get(URL)
@@ -46,8 +42,12 @@ def carregar_planilha():
46
 
47
  # Remove duplicatas
48
  df.drop_duplicates(inplace=True)
 
 
 
 
49
 
50
- print("✅ Planilha carregada com sucesso")
51
  return True
52
 
53
  except Exception as e:
@@ -61,83 +61,56 @@ def agrupar_por_administradora(dataframe):
61
  grupos[row['administradora']].append(row.to_dict())
62
  return grupos
63
 
64
- def buscar_combinacoes(credito_desejado, entrada_desejada, parcela_desejada, administradoras=None):
65
- """Busca combinações de cotas dentro dos parâmetros especificados."""
 
 
66
  # Garante que o DataFrame está carregado
67
- if df is None:
68
  if not carregar_planilha():
69
  return "❌ Erro: Planilha não carregada. Por favor, tente novamente."
70
 
71
- # Filtra por tipo de bem e administradoras
72
- df_filtrado = df[df['tipo_do_bem'].str.lower() == 'imovel']
73
  if administradoras:
74
- if isinstance(administradoras, tuple):
75
- administradoras = list(administradoras)
76
- df_filtrado = df_filtrado[df_filtrado['administradora'].isin(administradoras)]
77
 
78
- if df_filtrado.empty:
79
  return "🚫 Nenhuma cota encontrada com os filtros aplicados. Tente ajustar os parâmetros."
80
 
81
- # TOLERÂNCIAS INTELIGENTES BASEADAS NO VALOR
82
- if credito_desejado > 2000000:
83
- # Para valores MUITO altos (> 2M): tolerâncias ainda mais amplas
84
- credito_min, credito_max = credito_desejado * 0.85, credito_desejado * 1.15
85
- entrada_min, entrada_max = entrada_desejada * 0.85, entrada_desejada * 1.15
86
- parcela_min, parcela_max = parcela_desejada * 0.60, parcela_desejada * 1.40
87
- elif credito_desejado > 1000000:
88
- # Para valores altos (1M-2M): tolerâncias mais amplas
89
- credito_min, credito_max = credito_desejado * 0.90, credito_desejado * 1.10
90
- entrada_min, entrada_max = entrada_desejada * 0.90, entrada_desejada * 1.10
91
- parcela_min, parcela_max = parcela_desejada * 0.70, parcela_desejada * 1.30
92
- else:
93
- # Para valores normais (< 1M): tolerâncias padrão
94
- credito_min, credito_max = credito_desejado * 0.93, credito_desejado * 1.07
95
- entrada_min, entrada_max = entrada_desejada * 0.93, entrada_desejada * 1.07
96
- parcela_min, parcela_max = parcela_desejada * 0.75, parcela_desejada * 1.25
97
 
98
- grupos = agrupar_por_administradora(df_filtrado)
99
  resultados = []
100
 
101
- # OTIMIZAÇÃO: Timeout de 30 segundos
102
- start_time = time.time()
103
- TIME_LIMIT = 30 # segundos
104
-
105
- for adm, cotas in grupos.items():
106
- if time.time() - start_time > TIME_LIMIT:
107
- break
108
-
109
- # ⚡ OTIMIZAÇÃO: Pré-filtra cotas que individualmente já estão dentro dos limites
110
  cotas_filtradas = []
111
  for cota in cotas:
112
- credito = cota.get('valor_credito', 0)
113
- parcela = cota.get('valor_parcela', 0)
114
- if (credito_min <= credito <= credito_max and
115
- parcela_min <= parcela <= parcela_max):
 
 
 
116
  cotas_filtradas.append(cota)
117
 
 
118
  if not cotas_filtradas:
119
- continue
120
-
121
- # ⚡ OTIMIZAÇÃO: Limita para 12 cotas por administradora
122
- if len(cotas_filtradas) > 12:
123
- # Pega as cotas mais próximas do valor desejado
124
- cotas_filtradas.sort(key=lambda x: abs(x.get('valor_credito', 0) - credito_desejado/3))
125
- cotas_filtradas = cotas_filtradas[:12]
126
 
127
- # OTIMIZAÇÃO: Busca primeiro combinações menores (mais rápidas)
128
- for r in range(1, min(10, len(cotas_filtradas)) + 1):
129
- if time.time() - start_time > TIME_LIMIT:
130
- break
131
-
132
- # ⚡ OTIMIZAÇÃO: Amostragem inteligente - não testa todas as combinações
133
- max_combinations = 100 # Limite de combinações por tamanho
134
- count = 0
135
 
136
  for combinacao in itertools.combinations(cotas_filtradas, r):
137
- if time.time() - start_time > TIME_LIMIT:
138
- break
139
-
140
- if count >= max_combinations:
141
  break
142
 
143
  total_credito = sum(c['valor_credito'] for c in combinacao)
@@ -154,44 +127,35 @@ def buscar_combinacoes(credito_desejado, entrada_desejada, parcela_desejada, adm
154
  diferenca = abs(valor_final - total_credito)
155
 
156
  resultados.append((adm, combinacao, diferenca))
 
157
 
158
- # OTIMIZAÇÃO: Limita resultados por administradora
159
- if len([r for r in resultados if r[0] == adm]) >= 5:
160
  break
161
-
162
- count += 1
163
-
164
- if time.time() - start_time > TIME_LIMIT:
165
  break
 
 
 
166
 
167
  if not resultados:
168
  return "🚫 Nenhuma combinação adequada encontrada com os parâmetros fornecidos."
169
 
170
- resultados.sort(key=lambda x: x[2]) # Ordena pela diferença
171
-
172
- return formatar_resultados(resultados[:10]) # Limita a 10 resultados
173
-
174
- # ✅ MODIFIQUE A FUNÇÃO PRINCIPAL PARA USAR FALLBACK
175
- def ajustar_e_buscar(credito_desejado, entrada_desejada, parcela_desejada, administradoras):
176
- entrada_calculada = credito_desejado * 0.085 + entrada_desejada
177
-
178
- # Primeiro tenta busca normal
179
- resultado = buscar_combinacoes(credito_desejado, entrada_calculada, parcela_desejada, administradoras)
180
-
181
- # Se não encontrar, usa fallback
182
- if "Nenhuma combinação" in resultado or "Erro" in resultado:
183
- return buscar_combinacoes_emergencia(credito_desejado, entrada_calculada, parcela_desejada, administradoras)
184
-
185
- return resultado
186
 
187
  def formatar_moeda(valor):
188
  return f"R$ {valor:,.2f}".replace(",", "v").replace(".", ",").replace("v", ".")
189
 
190
  def formatar_resultados(resultados):
191
  """Formata os resultados para exibição."""
 
 
 
192
  resposta = ""
193
- # Limita a 15 resultados para evitar saídas muito longas
194
- for idx, (adm, combinacao, _) in enumerate(resultados[:15], 1):
195
  codigos = [str(c.get('codigo', 'N/A')) for c in combinacao]
196
  total_credito = sum(c['valor_credito'] for c in combinacao)
197
  total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
@@ -220,7 +184,6 @@ def formatar_resultados(resultados):
220
  📊 Taxa Total: {taxa_percentual:.2f}% ({formatar_moeda(taxa_total)})
221
  🗓️ Taxa Mensal: {taxa_mensal:.2f}%
222
  🗓️ Taxa Anual: {taxa_mensal * 12:.2f}%
223
- 📈 Nº de Cotas: {len(combinacao)}
224
  """
225
  return resposta
226
 
@@ -229,7 +192,7 @@ carregar_planilha()
229
 
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 a lista de administradoras para o Gradio
235
  def get_administradoras_options():
@@ -238,104 +201,4 @@ def get_administradoras_options():
238
  return sorted(adm_list)
239
  return []
240
 
241
- # Criando a interface Gradio
242
- with gr.Blocks(title="Sistema de Busca de Consórcio Imóvel") as demo:
243
- gr.HTML("""
244
- <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
245
- <style>
246
- * {
247
- font-family: 'Poppins', sans-serif !important;
248
- }
249
-
250
- body {
251
- background-color: #ff8f00 !important;
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;
259
- border-radius: 12px !important;
260
- color: black !important;
261
- padding: 10px !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;
269
- border-radius: 12px !important;
270
- color: black !important;
271
- padding: 10px !important;
272
- }
273
-
274
- input::placeholder, textarea::placeholder {
275
- color: #333 !important;
276
- opacity: 0.7;
277
- }
278
-
279
- .gr-checkbox label {
280
- display: flex;
281
- align-items: center;
282
- gap: 8px;
283
- font-weight: 600;
284
- }
285
-
286
- input[type="checkbox"] {
287
- accent-color: black !important;
288
- width: 18px;
289
- height: 18px;
290
- }
291
-
292
- .gr-button {
293
- font-weight: bold;
294
- border-radius: 10px !important;
295
- background-color: white !important;
296
- color: black !important;
297
- border: 2px solid black !important;
298
- }
299
-
300
- .gr-button:hover {
301
- background-color: #fff3e0 !important;
302
- color: black !important;
303
- }
304
-
305
- label {
306
- font-weight: 600 !important;
307
- }
308
- </style>
309
- """)
310
-
311
-
312
- gr.Markdown("# 🏠 Busca de Combinações de Consórcio Imóvel")
313
- gr.Markdown("Insira os valores desejados para crédito, entrada e parcela, e filtre por administradora.")
314
-
315
- with gr.Row():
316
- credito_input = gr.Number(label="Crédito Desejado (R$)", value=500000, step=1000)
317
- entrada_input = gr.Number(label="Entrada Desejada (R$)", value=75000, step=1000)
318
- parcela_input = gr.Number(label="Parcela Desejada (R$)", value=3500, step=100)
319
-
320
- administradoras_multiselect = gr.CheckboxGroup(
321
- label="Filtrar por Administradoras",
322
- choices=get_administradoras_options(),
323
- value=get_administradoras_options() # Seleciona todas por padrão
324
- )
325
-
326
- submit_btn = gr.Button("🔍 Buscar Combinações", variant="primary")
327
-
328
- output_text = gr.Textbox(label="Resultados da Busca", lines=20, max_lines=40, interactive=False, placeholder="Os resultados aparecerão aqui...")
329
-
330
- submit_btn.click(
331
- fn=ajustar_e_buscar,
332
- inputs=[credito_input, entrada_input, parcela_input, administradoras_multiselect],
333
- outputs=output_text
334
- )
335
-
336
- gr.Markdown("---")
337
- gr.Markdown("Desenvolvido para auxiliar na busca por cotas de consórcio ideais.")
338
-
339
- # Inicia o aplicativo Gradio
340
- if __name__ == "__main__":
341
- demo.launch() # Você não precisa disso no Colab, mas sim no arquivo que você fará o deploy
 
1
+ # app.py OTIMIZADO
 
 
 
 
 
 
2
  import pandas as pd
3
  import requests
4
  import io
 
6
  from collections import defaultdict
7
  import gradio as gr
8
  import time
9
+ import math
10
 
11
  # 🔧 CONFIGURAÇÕES GLOBAIS
 
12
  FILE_ID = "1XvNz7DlWioT64uNdcfBSL8Ui2nRSi9gT"
13
  URL = f"https://drive.google.com/uc?export=download&id={FILE_ID}"
14
 
15
+ # Variáveis globais para armazenamento
16
  df = None
17
+ df_imovel = None
18
+ grupos_imovel = None
19
 
20
  def carregar_planilha():
21
  """Carrega e prepara a planilha para análise."""
22
+ global df, df_imovel, grupos_imovel
23
  try:
24
  print("⏳ Carregando planilha...")
25
  response = requests.get(URL)
 
42
 
43
  # Remove duplicatas
44
  df.drop_duplicates(inplace=True)
45
+
46
+ # Pré-filtra e pré-processa dados de imóvel
47
+ df_imovel = df[df['tipo_do_bem'].str.lower() == 'imovel'].copy()
48
+ grupos_imovel = agrupar_por_administradora(df_imovel)
49
 
50
+ print("✅ Planilha carregada e pré-processada com sucesso")
51
  return True
52
 
53
  except Exception as e:
 
61
  grupos[row['administradora']].append(row.to_dict())
62
  return grupos
63
 
64
+ def buscar_combinacoes_otimizado(credito_desejado, entrada_desejada, parcela_desejada, administradoras=None, max_combinacoes=10):
65
+ """Busca combinações de cotas dentro dos parâmetros especificados de forma otimizada."""
66
+ global df_imovel, grupos_imovel
67
+
68
  # Garante que o DataFrame está carregado
69
+ if df_imovel is None or grupos_imovel is None:
70
  if not carregar_planilha():
71
  return "❌ Erro: Planilha não carregada. Por favor, tente novamente."
72
 
73
+ # Filtra administradoras se especificado
74
+ grupos_filtrados = grupos_imovel
75
  if administradoras:
76
+ grupos_filtrados = {adm: cotas for adm, cotas in grupos_imovel.items() if adm in administradoras}
 
 
77
 
78
+ if not grupos_filtrados:
79
  return "🚫 Nenhuma cota encontrada com os filtros aplicados. Tente ajustar os parâmetros."
80
 
81
+ # Define faixas de tolerância (ligeiramente mais amplas para melhor performance)
82
+ credito_min, credito_max = credito_desejado * 0.90, credito_desejado * 1.10
83
+ entrada_min, entrada_max = entrada_desejada * 0.90, entrada_desejada * 1.10
84
+ parcela_min, parcela_max = parcela_desejada * 0.70, parcela_desejada * 1.30
 
 
 
 
 
 
 
 
 
 
 
 
85
 
 
86
  resultados = []
87
 
88
+ # Para cada administradora, busca combinações
89
+ for adm, cotas in grupos_filtrados.items():
90
+ # Pré-filtra cotas que individualmente estão dentro das faixas de tolerância
 
 
 
 
 
 
91
  cotas_filtradas = []
92
  for cota in cotas:
93
+ cota_credito = cota['valor_credito']
94
+ cota_entrada = cota['valor_entrada'] + (cota_credito * 0.085)
95
+ cota_parcela = cota['valor_parcela']
96
+
97
+ if (credito_min <= cota_credito <= credito_max and
98
+ entrada_min <= cota_entrada <= entrada_max and
99
+ parcela_min <= cota_parcela <= parcela_max):
100
  cotas_filtradas.append(cota)
101
 
102
+ # Se não há cotas individuais dentro da tolerância, tenta combinações
103
  if not cotas_filtradas:
104
+ cotas_filtradas = cotas # Usa todas as cotas para combinações
 
 
 
 
 
 
105
 
106
+ # Gera combinações (até 3 cotas por combinação para performance)
107
+ for r in range(1, min(4, len(cotas_filtradas) + 1)):
108
+ # Limita o número de combinações testadas por administradora
109
+ max_combinacoes_por_adm = 50
110
+ combinacoes_geradas = 0
 
 
 
111
 
112
  for combinacao in itertools.combinations(cotas_filtradas, r):
113
+ if combinacoes_geradas >= max_combinacoes_por_adm:
 
 
 
114
  break
115
 
116
  total_credito = sum(c['valor_credito'] for c in combinacao)
 
127
  diferenca = abs(valor_final - total_credito)
128
 
129
  resultados.append((adm, combinacao, diferenca))
130
+ combinacoes_geradas += 1
131
 
132
+ # Para se encontrou combinações suficientes
133
+ if len(resultados) >= max_combinacoes * 3: # Coleta mais para depois filtrar as melhores
134
  break
135
+
136
+ if len(resultados) >= max_combinacoes * 3:
 
 
137
  break
138
+
139
+ if len(resultados) >= max_combinacoes * 3:
140
+ break
141
 
142
  if not resultados:
143
  return "🚫 Nenhuma combinação adequada encontrada com os parâmetros fornecidos."
144
 
145
+ # Ordena pela diferença e pega as melhores
146
+ resultados.sort(key=lambda x: x[2])
147
+ return formatar_resultados(resultados[:max_combinacoes])
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
  def formatar_moeda(valor):
150
  return f"R$ {valor:,.2f}".replace(",", "v").replace(".", ",").replace("v", ".")
151
 
152
  def formatar_resultados(resultados):
153
  """Formata os resultados para exibição."""
154
+ if not resultados:
155
+ return "🚫 Nenhuma combinação adequada encontrada com os parâmetros fornecidos."
156
+
157
  resposta = ""
158
+ for idx, (adm, combinacao, _) in enumerate(resultados, 1):
 
159
  codigos = [str(c.get('codigo', 'N/A')) for c in combinacao]
160
  total_credito = sum(c['valor_credito'] for c in combinacao)
161
  total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
 
184
  📊 Taxa Total: {taxa_percentual:.2f}% ({formatar_moeda(taxa_total)})
185
  🗓️ Taxa Mensal: {taxa_mensal:.2f}%
186
  🗓️ Taxa Anual: {taxa_mensal * 12:.2f}%
 
187
  """
188
  return resposta
189
 
 
192
 
193
  def ajustar_e_buscar(credito_desejado, entrada_desejada, parcela_desejada, administradoras):
194
  entrada_calculada = credito_desejado * 0.085 + entrada_desejada
195
+ return buscar_combinacoes_otimizado(credito_desejado, entrada_calculada, parcela_desejada, administradoras, max_combinacoes=10)
196
 
197
  # Prepara a lista de administradoras para o Gradio
198
  def get_administradoras_options():
 
201
  return sorted(adm_list)
202
  return []
203
 
204
+ # O restante do código da interface Gradio permanece igual...