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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -205
app.py CHANGED
@@ -1,21 +1,13 @@
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
11
- import numpy as np
12
- from itertools import combinations, islice
13
  import gradio as gr
14
  import time
15
- import heapq
16
- from typing import List, Dict, Tuple
17
  # 🔧 CONFIGURAÇÕES GLOBAIS
18
- # Certifique-se de que este FILE_ID esteja acessível publicamente ou para "Qualquer pessoa com o link"
19
  FILE_ID = "1XvNz7DlWioT64uNdcfBSL8Ui2nRSi9gT"
20
  URL = f"https://drive.google.com/uc?export=download&id={FILE_ID}"
21
 
@@ -27,7 +19,7 @@ def carregar_planilha():
27
  global df
28
  try:
29
  print("⏳ Carregando planilha...")
30
- response = requests.get(URL)
31
  response.raise_for_status()
32
  data = io.BytesIO(response.content)
33
  df = pd.read_excel(data)
@@ -42,8 +34,10 @@ def carregar_planilha():
42
  df[coluna] = pd.to_numeric(df[coluna], errors='coerce').fillna(0)
43
 
44
  # Verifica colunas essenciais
45
- if 'tipo_do_bem' not in df.columns or 'administradora' not in df.columns:
46
- raise ValueError("Colunas essenciais não encontradas")
 
 
47
 
48
  # Remove duplicatas
49
  df.drop_duplicates(inplace=True)
@@ -62,101 +56,90 @@ def agrupar_por_administradora(dataframe):
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."
70
-
71
- # Filtra as cotas
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."
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):
@@ -165,21 +148,22 @@ def formatar_resultados(resultados):
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]
169
- total_credito = sum(c['valor_credito'] for c in combinacao)
170
- total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
171
- total_entrada = total_entrada_base + (total_credito * 0.085)
172
- total_saldo = sum(c['saldo_devedor'] for c in combinacao)
173
- total_parcelas = sum(c['valor_parcela'] for c in combinacao)
174
- maior_prazo = max(int(c.get('qtd_parcelas', 0)) for c in combinacao)
175
-
176
- valor_final = round(total_entrada + total_saldo, 2)
177
- credito_real = round(total_credito - total_entrada, 2)
178
- taxa_total = total_saldo - credito_real
179
- taxa_percentual = (taxa_total / credito_real) * 100 if credito_real > 0 else 0
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)}
@@ -194,110 +178,59 @@ def formatar_resultados(resultados):
194
  🗓️ Taxa Mensal: {taxa_mensal:.2f}%
195
  📈 Taxa Anual: {taxa_mensal * 12:.2f}%
196
  """
 
 
 
 
197
  return resposta
198
 
199
- # Carrega a planilha uma vez quando o aplicativo inicia
200
- carregar_planilha()
201
-
202
  def ajustar_e_buscar(credito_desejado, entrada_desejada, parcela_desejada, administradoras):
203
- entrada_calculada = credito_desejado * 0.085 + entrada_desejada
204
- return buscar_combinacoes(credito_desejado, entrada_calculada, parcela_desejada, administradoras)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
 
206
  # Prepara a lista de administradoras para o Gradio
207
  def get_administradoras_options():
208
- if df is not None:
209
- adm_list = df[df['tipo_do_bem'].str.lower() == 'imovel']['administradora'].unique()
210
- return sorted(adm_list)
211
- return []
212
-
213
- # Criando a interface Gradio
214
- with gr.Blocks(title="Sistema de Busca de Consórcio Imóvel") as demo:
215
- gr.HTML("""
216
- <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
217
- <style>
218
- * {
219
- font-family: 'Poppins', sans-serif !important;
220
- }
221
-
222
- body {
223
- background-color: #ff8f00 !important;
224
- color: black !important;
225
- }
226
-
227
- /* Inputs Numéricos: Crédito, Entrada, Parcela */
228
- input[type="number"] {
229
- background-color: white !important;
230
- border: 2px solid #000 !important;
231
- border-radius: 12px !important;
232
- color: black !important;
233
- padding: 10px !important;
234
- font-weight: 500;
235
- }
236
-
237
- /* Inputs de texto e áreas de texto (como a saída e código) */
238
- input[type="text"], textarea {
239
- background-color: white !important;
240
- border: 2px solid black !important;
241
- border-radius: 12px !important;
242
- color: black !important;
243
- padding: 10px !important;
244
- }
245
-
246
- input::placeholder, textarea::placeholder {
247
- color: #333 !important;
248
- opacity: 0.7;
249
- }
250
-
251
- .gr-checkbox label {
252
- display: flex;
253
- align-items: center;
254
- gap: 8px;
255
- font-weight: 600;
256
- }
257
-
258
- input[type="checkbox"] {
259
- accent-color: black !important;
260
- width: 18px;
261
- height: 18px;
262
- }
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
-
272
- .gr-button:hover {
273
- background-color: #fff3e0 !important;
274
- color: black !important;
275
- }
276
-
277
- label {
278
- font-weight: 600 !important;
279
- }
280
- </style>
281
- """)
282
-
283
-
284
  gr.Markdown("# 🏠 Busca de Combinações de Consórcio Imóvel")
285
- gr.Markdown("Insira os valores desejados para crédito, entrada e parcela, e filtre por administradora.")
286
-
287
  with gr.Row():
288
- credito_input = gr.Number(label="Crédito Desejado (R$)", value=300000, step=1000)
289
- entrada_input = gr.Number(label="Entrada Desejada (R$)", value=30000, step=1000)
290
- parcela_input = gr.Number(label="Parcela Desejada (R$)", value=1500, step=100)
291
 
292
  administradoras_multiselect = gr.CheckboxGroup(
293
  label="Filtrar por Administradoras",
294
  choices=get_administradoras_options(),
295
- value=get_administradoras_options() # Seleciona todas por padrão
296
  )
297
 
298
  submit_btn = gr.Button("🔍 Buscar Combinações", variant="primary")
299
-
300
- output_text = gr.Textbox(label="Resultados da Busca", lines=20, max_lines=40, interactive=False, placeholder="Os resultados aparecerão aqui...")
301
 
302
  submit_btn.click(
303
  fn=ajustar_e_buscar,
@@ -305,9 +238,6 @@ with gr.Blocks(title="Sistema de Busca de Consórcio Imóvel") as demo:
305
  outputs=output_text
306
  )
307
 
308
- gr.Markdown("---")
309
- gr.Markdown("Desenvolvido para auxiliar na busca por cotas de consórcio ideais.")
310
-
311
- # Inicia o aplicativo Gradio
312
  if __name__ == "__main__":
313
- demo.launch() # Você não precisa disso no Colab, mas sim no arquivo que você fará o deploy
 
 
 
 
 
 
 
 
1
  import pandas as pd
2
  import requests
3
  import io
4
+ import itertools
5
+ from collections import defaultdict
6
  import gradio as gr
7
  import time
8
+ import random
9
+
10
  # 🔧 CONFIGURAÇÕES GLOBAIS
 
11
  FILE_ID = "1XvNz7DlWioT64uNdcfBSL8Ui2nRSi9gT"
12
  URL = f"https://drive.google.com/uc?export=download&id={FILE_ID}"
13
 
 
19
  global df
20
  try:
21
  print("⏳ Carregando planilha...")
22
+ response = requests.get(URL, timeout=30)
23
  response.raise_for_status()
24
  data = io.BytesIO(response.content)
25
  df = pd.read_excel(data)
 
34
  df[coluna] = pd.to_numeric(df[coluna], errors='coerce').fillna(0)
35
 
36
  # Verifica colunas essenciais
37
+ colunas_necessarias = ['tipo_do_bem', 'administradora', 'valor_credito', 'valor_entrada', 'valor_parcela']
38
+ for coluna in colunas_necessarias:
39
+ if coluna not in df.columns:
40
+ raise ValueError(f"Coluna essencial não encontrada: {coluna}")
41
 
42
  # Remove duplicatas
43
  df.drop_duplicates(inplace=True)
 
56
  grupos[row['administradora']].append(row.to_dict())
57
  return grupos
58
 
59
+ def formatar_moeda(valor):
60
+ """Formata valor como moeda brasileira."""
61
+ try:
62
+ return f"R$ {valor:,.2f}".replace(",", "v").replace(".", ",").replace("v", ".")
63
+ except:
64
+ return f"R$ {valor}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
+ def buscar_combinacoes_rapido(credito_desejado, entrada_desejada, parcela_desejada, administradoras=None):
67
+ """Busca combinações de forma rápida e eficiente."""
68
+ try:
69
+ if df is None:
70
+ if not carregar_planilha():
71
+ return "❌ Erro: Planilha não carregada."
72
+
73
+ # Filtra por tipo de bem
74
+ df_filtrado = df[df['tipo_do_bem'].str.lower() == 'imovel']
75
+
76
+ if administradoras:
77
+ if isinstance(administradoras, tuple):
78
+ administradoras = list(administradoras)
79
+ df_filtrado = df_filtrado[df_filtrado['administradora'].isin(administradoras)]
80
+
81
+ if df_filtrado.empty:
82
+ return "🚫 Nenhuma cota encontrada com os filtros aplicados."
83
+
84
+ # Tolerâncias amplas
85
+ credito_min, credito_max = credito_desejado * 0.85, credito_desejado * 1.15
86
+ entrada_min, entrada_max = entrada_desejada * 0.80, entrada_desejada * 1.20
87
+ parcela_min, parcela_max = parcela_desejada * 0.60, parcela_desejada * 1.40
88
+
89
+ grupos = agrupar_por_administradora(df_filtrado)
90
+ resultados = []
91
 
92
+ MIN_COTAS = 3
93
+ MAX_COTAS = 10
94
+
95
+ for adm, cotas in grupos.items():
96
+ if len(cotas) < MIN_COTAS:
97
+ continue
98
+
99
+ # Amostra aleatória para performance
100
+ if len(cotas) > 20:
101
+ cotas = random.sample(cotas, 20)
102
+
103
+ # Busca combinações de 3 a 10 cotas
104
+ for r in range(MIN_COTAS, min(MAX_COTAS + 1, len(cotas) + 1)):
105
+ for combinacao in itertools.combinations(cotas, r):
106
+ try:
107
+ total_credito = sum(c['valor_credito'] for c in combinacao)
108
+ total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
109
+ total_entrada = total_entrada_base + (total_credito * 0.085)
110
+ total_parcelas = sum(c['valor_parcela'] for c in combinacao)
111
+
112
+ if (credito_min <= total_credito <= credito_max and
113
+ entrada_min <= total_entrada <= entrada_max and
114
+ parcela_min <= total_parcelas <= parcela_max):
115
+
116
+ total_saldo = sum(c['saldo_devedor'] for c in combinacao)
117
+ valor_final = round(total_entrada + total_saldo, 2)
118
+ diferenca = abs(valor_final - total_credito)
119
+
120
+ resultados.append((adm, combinacao, diferenca))
121
+
122
+ if len(resultados) >= 50: # Limite seguro
123
+ break
124
+ except KeyError as e:
125
+ print(f"⚠️ Coluna não encontrada: {e}")
126
  continue
127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  if len(resultados) >= 50:
129
  break
130
 
131
  if len(resultados) >= 50:
132
  break
133
 
134
+ if not resultados:
135
+ return "🚫 Nenhuma combinação adequada encontrada. Tente ajustar os valores."
 
 
 
 
 
136
 
137
+ resultados.sort(key=lambda x: x[2])
138
+ return formatar_resultados(resultados[:15])
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
  except Exception as e:
141
+ return f"❌ Erro inesperado: {str(e)}"
142
 
 
143
  def formatar_resultados(resultados):
144
  """Formata os resultados para exibição."""
145
  if not resultados or isinstance(resultados, str):
 
148
  resposta = f"🎯 **{len(resultados)} combinações encontradas**\n\n"
149
 
150
  for idx, (adm, combinacao, diferenca) in enumerate(resultados, 1):
151
+ try:
152
+ codigos = [str(c.get('codigo', 'N/A')) for c in combinacao]
153
+ total_credito = sum(c['valor_credito'] for c in combinacao)
154
+ total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
155
+ total_entrada = total_entrada_base + (total_credito * 0.085)
156
+ total_saldo = sum(c['saldo_devedor'] for c in combinacao)
157
+ total_parcelas = sum(c['valor_parcela'] for c in combinacao)
158
+ maior_prazo = max(int(c.get('qtd_parcelas', 0)) for c in combinacao)
159
+
160
+ valor_final = round(total_entrada + total_saldo, 2)
161
+ credito_real = round(total_credito - total_entrada, 2)
162
+ taxa_total = total_saldo - credito_real
163
+ taxa_percentual = (taxa_total / credito_real) * 100 if credito_real > 0 else 0
164
+ taxa_mensal = taxa_percentual / maior_prazo if maior_prazo > 0 else 0
165
+
166
+ resposta += f"""
167
  --- COMBINAÇÃO {idx} ({len(combinacao)} COTAS) ---
168
  🏢 Administradora: {adm}
169
  🔢 Códigos: {', '.join(codigos)}
 
178
  🗓️ Taxa Mensal: {taxa_mensal:.2f}%
179
  📈 Taxa Anual: {taxa_mensal * 12:.2f}%
180
  """
181
+ except Exception as e:
182
+ print(f"⚠️ Erro ao formatar resultado: {e}")
183
+ continue
184
+
185
  return resposta
186
 
 
 
 
187
  def ajustar_e_buscar(credito_desejado, entrada_desejada, parcela_desejada, administradoras):
188
+ """Função principal ajustada para a interface."""
189
+ try:
190
+ if credito_desejado is None or entrada_desejada is None or parcela_desejada is None:
191
+ return "⚠️ Preencha todos os valores corretamente."
192
+
193
+ entrada_calculada = credito_desejado * 0.085 + entrada_desejada
194
+
195
+ resultado = buscar_combinacoes_rapido(
196
+ credito_desejado, entrada_calculada, parcela_desejada, administradoras
197
+ )
198
+
199
+ return resultado
200
+
201
+ except Exception as e:
202
+ return f"❌ Erro na busca: {str(e)}"
203
+
204
+ # Carrega a planilha ao iniciar
205
+ carregar_planilha()
206
 
207
  # Prepara a lista de administradoras para o Gradio
208
  def get_administradoras_options():
209
+ try:
210
+ if df is not None and 'administradora' in df.columns and 'tipo_do_bem' in df.columns:
211
+ adm_list = df[df['tipo_do_bem'].str.lower() == 'imovel']['administradora'].unique()
212
+ return sorted([adm for adm in adm_list if pd.notna(adm)])
213
+ return []
214
+ except:
215
+ return []
216
+
217
+ # Interface Gradio simplificada
218
+ with gr.Blocks(title="Sistema de Busca de Consórcio", theme=gr.themes.Default()) as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  gr.Markdown("# 🏠 Busca de Combinações de Consórcio Imóvel")
220
+
 
221
  with gr.Row():
222
+ credito_input = gr.Number(label="Crédito Desejado (R$)", value=2000000, step=1000)
223
+ entrada_input = gr.Number(label="Entrada Desejada (R$)", value=300000, step=1000)
224
+ parcela_input = gr.Number(label="Parcela Desejada (R$)", value=20000, step=100)
225
 
226
  administradoras_multiselect = gr.CheckboxGroup(
227
  label="Filtrar por Administradoras",
228
  choices=get_administradoras_options(),
229
+ value=get_administradoras_options()
230
  )
231
 
232
  submit_btn = gr.Button("🔍 Buscar Combinações", variant="primary")
233
+ output_text = gr.Textbox(label="Resultados da Busca", lines=20, max_lines=40)
 
234
 
235
  submit_btn.click(
236
  fn=ajustar_e_buscar,
 
238
  outputs=output_text
239
  )
240
 
241
+ # Inicia o aplicativo
 
 
 
242
  if __name__ == "__main__":
243
+ demo.launch(server_name="0.0.0.0", server_port=7860, share=False)