victormottatz commited on
Commit
7f7c7ed
·
verified ·
1 Parent(s): 8c97de6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +129 -108
app.py CHANGED
@@ -1,24 +1,34 @@
1
- # -- coding: utf-8 --
2
- """Robô de Cálculo para Consórcio de Imóveis - Versão Ajustada"""
 
 
 
 
 
 
 
 
3
  import pandas as pd
4
  import requests
5
  import io
6
  import itertools
7
  from collections import defaultdict
8
  import gradio as gr
 
9
 
10
  # 🔧 CONFIGURAÇÕES GLOBAIS
11
- FILE_ID = "1XvNz7DlWioT64uNdcfBSL8Ui2nRSi9gT" # Substitua pelo ID correto da planilha de imóveis
 
12
  URL = f"https://drive.google.com/uc?export=download&id={FILE_ID}"
13
 
14
  # Variável global para armazenar o DataFrame
15
  df = None
16
 
17
  def carregar_planilha():
18
- """Carrega e prepara a planilha para análise de consórcios de imóveis."""
19
  global df
20
  try:
21
- print("⏳ Carregando planilha de imóveis...")
22
  response = requests.get(URL)
23
  response.raise_for_status()
24
  data = io.BytesIO(response.content)
@@ -26,30 +36,23 @@ def carregar_planilha():
26
 
27
  # Padroniza nomes das colunas
28
  df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_")
 
29
 
30
- # Padroniza os nomes das administradoras
31
- if 'administradora' in df.columns:
32
- df['administradora'] = df['administradora'].astype(str).str.strip().str.lower()
33
 
34
  # Converte colunas numéricas
35
- numeric_cols = ['valor_credito', 'valor_entrada', 'valor_parcela', 'saldo_devedor', 'qtd_parcelas']
36
- for col in numeric_cols:
37
- if col in df.columns:
38
- df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
39
-
40
- # Filtra apenas imóveis (com tratamento para diferentes grafias)
41
- if 'tipo_do_bem' in df.columns:
42
- df = df[df['tipo_do_bem'].str.lower().str.contains('imóvel|imovel')]
43
-
44
  # Verifica colunas essenciais
45
- required_cols = ['tipo_do_bem', 'administradora', 'valor_credito', 'valor_entrada', 'valor_parcela']
46
- if not all(col in df.columns for col in required_cols):
47
- missing = [col for col in required_cols if col not in df.columns]
48
- raise ValueError(f"Colunas essenciais não encontradas: {', '.join(missing)}")
49
 
50
  # Remove duplicatas
51
  df.drop_duplicates(inplace=True)
52
- print("✅ Planilha de imóveis carregada com sucesso!")
 
53
  return True
54
 
55
  except Exception as e:
@@ -64,28 +67,29 @@ def agrupar_por_administradora(dataframe):
64
  return grupos
65
 
66
  def buscar_combinacoes(credito_desejado, entrada_desejada, parcela_desejada, administradoras=None):
67
- """Busca combinações de cotas para imóveis dentro dos parâmetros especificados."""
68
- global df
69
  if df is None:
 
70
  if not carregar_planilha():
71
- return "❌ Erro: Planilha não carregada. Verifique o ID do arquivo e conexão."
72
 
73
- # Filtra por tipo de bem (Imóvel) e administradoras selecionadas
74
- df_filtrado = df[df['tipo_do_bem'].str.lower().str.contains('imóvel|imovel')]
75
-
76
  if administradoras:
 
77
  if isinstance(administradoras, tuple):
78
  administradoras = list(administradoras)
79
  administradoras = [a.strip().lower() for a in administradoras]
80
  df_filtrado = df_filtrado[df_filtrado['administradora'].isin(administradoras)]
81
 
82
  if df_filtrado.empty:
83
- return "🚫 Nenhuma cota de imóvel encontrada com os filtros aplicados."
84
 
85
- # Define faixas de tolerância ajustadas para imóveis
86
- credito_min, credito_max = credito_desejado * 0.90, credito_desejado * 1.10
87
- entrada_min, entrada_max = entrada_desejada * 0.90, entrada_desejada * 1.10
88
- parcela_min, parcela_max = parcela_desejada * 0.70, parcela_desejada * 1.30
89
 
90
  grupos = agrupar_por_administradora(df_filtrado)
91
  resultados = []
@@ -95,7 +99,7 @@ def buscar_combinacoes(credito_desejado, entrada_desejada, parcela_desejada, adm
95
  for combinacao in itertools.combinations(cotas, r):
96
  total_credito = sum(c['valor_credito'] for c in combinacao)
97
  total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
98
- total_entrada = total_entrada_base + (total_credito * 0.10) # 10% de comissão para imóveis
99
  total_parcelas = sum(c['valor_parcela'] for c in combinacao)
100
 
101
  if (credito_min <= total_credito <= credito_max and
@@ -104,63 +108,29 @@ def buscar_combinacoes(credito_desejado, entrada_desejada, parcela_desejada, adm
104
 
105
  total_saldo = sum(c['saldo_devedor'] for c in combinacao)
106
  valor_final = round(total_entrada + total_saldo, 2)
107
- diferenca = abs(valor_final - total_credito)
108
 
109
  resultados.append((adm, combinacao, diferenca))
110
 
111
  if not resultados:
112
- return "🚫 Nenhuma combinação adequada encontrada para imóveis com os parâmetros fornecidos."
 
 
113
 
114
- resultados.sort(key=lambda x: x[2]) # Ordena pela diferença
115
  return formatar_resultados(resultados)
116
 
117
  def formatar_moeda(valor):
118
- """Formata valores monetários no padrão brasileiro."""
119
  return f"R$ {valor:,.2f}".replace(",", "v").replace(".", ",").replace("v", ".")
120
 
121
  def formatar_resultados(resultados):
122
- """Formata os resultados para exibição com diversificação."""
123
  resposta = ""
124
- grouped_by_adm = defaultdict(list)
125
-
126
- # Agrupa por administradora mantendo a ordenação por diferença
127
- for adm, combinacao, diferenca in resultados:
128
- grouped_by_adm[adm].append((combinacao, diferenca))
129
-
130
- # Ordena as combinações dentro de cada administradora
131
- for adm in grouped_by_adm:
132
- grouped_by_adm[adm].sort(key=lambda x: x[1])
133
-
134
- # Algoritmo de diversificação de resultados
135
- final_resultados = []
136
- adm_indices = {adm: 0 for adm in grouped_by_adm.keys()}
137
- active_adms = list(grouped_by_adm.keys())
138
- current_adm_idx = 0
139
-
140
- while len(final_resultados) < 15 and active_adms:
141
- adm_da_vez = active_adms[current_adm_idx]
142
- idx_na_adm = adm_indices[adm_da_vez]
143
-
144
- if idx_na_adm < len(grouped_by_adm[adm_da_vez]):
145
- combinacao_data, _ = grouped_by_adm[adm_da_vez][idx_na_adm]
146
- final_resultados.append((adm_da_vez, combinacao_data))
147
- adm_indices[adm_da_vez] += 1
148
- else:
149
- active_adms.pop(current_adm_idx)
150
- if current_adm_idx >= len(active_adms) and active_adms:
151
- current_adm_idx = 0
152
-
153
- if active_adms:
154
- current_adm_idx = (current_adm_idx + 1) % len(active_adms)
155
- else:
156
- break
157
-
158
- # Formatação dos resultados
159
- for idx, (adm, combinacao) in enumerate(final_resultados, 1):
160
  codigos = [str(c.get('codigo', 'N/A')) for c in combinacao]
161
  total_credito = sum(c['valor_credito'] for c in combinacao)
162
  total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
163
- total_entrada = total_entrada_base + (total_credito * 0.10) # 10% para imóveis
164
  total_saldo = sum(c['saldo_devedor'] for c in combinacao)
165
  total_parcelas = sum(c['valor_parcela'] for c in combinacao)
166
  maior_prazo = max(int(c.get('qtd_parcelas', 0)) for c in combinacao)
@@ -173,39 +143,86 @@ def formatar_resultados(resultados):
173
 
174
  resposta += f"""
175
  --- COMBINAÇÃO {idx} ---
176
- 🏠 Administradora: {adm.capitalize()}
177
  🔢 Códigos: {', '.join(codigos)}
178
  💰 Crédito Total: {formatar_moeda(total_credito)}
179
- 🏦 Entrada (+comissão): {formatar_moeda(total_entrada)}
180
  📉 Saldo Devedor: {formatar_moeda(total_saldo)}
181
  💲 Parcela: {formatar_moeda(total_parcelas)}
182
  ⏳ Prazo: {maior_prazo} meses
183
  🔚 Valor Final: {formatar_moeda(valor_final)}
184
  💠 Crédito Líquido: {formatar_moeda(credito_real)}
185
  📊 Taxa Total: {taxa_percentual:.2f}% ({formatar_moeda(taxa_total)})
186
- 🗓 Taxa Mensal: {taxa_mensal:.2f}%
187
- 🗓 Taxa Anual: {taxa_mensal * 12:.2f}%
188
  """
189
  return resposta
190
 
 
 
 
 
 
 
 
 
191
  def get_administradoras_options():
192
- """Obtém a lista de administradoras disponíveis para o filtro."""
193
  if df is not None:
194
- adm_list = df[df['tipo_do_bem'].str.lower().str.contains('imóvel|imovel')]['administradora'].unique()
195
- return sorted(adm_list.tolist())
196
  return []
197
 
198
- # Interface Gradio para Imóveis
199
- with gr.Blocks(title="Sistema de Busca de Consórcio de Imóveis", css="* {font-family: 'Poppins', sans-serif !important;}") as demo:
200
- gr.Markdown("""
 
201
  <style>
202
- body { background-color: #ff8f00 !important; color: black !important; }
203
- input[type="number"], textarea {
 
 
 
 
 
 
 
 
 
204
  background-color: white !important;
205
  border: 2px solid #000 !important;
206
  border-radius: 12px !important;
 
207
  padding: 10px !important;
 
208
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  .gr-button {
210
  font-weight: bold;
211
  border-radius: 10px !important;
@@ -213,42 +230,46 @@ with gr.Blocks(title="Sistema de Busca de Consórcio de Imóveis", css="* {font-
213
  color: black !important;
214
  border: 2px solid black !important;
215
  }
216
- .gr-button:hover { background-color: #fff3e0 !important; }
 
 
 
 
 
 
 
 
217
  </style>
218
  """)
219
-
220
- gr.Markdown("# 🏠 Sistema de Busca de Consórcio de Imóveis")
221
- gr.Markdown("Encontre as melhores combinações de cotas para seu consórcio imobiliário.")
 
222
 
223
  with gr.Row():
224
- credito_input = gr.Number(label="Crédito Desejado (R$)", value=300000, step=10000, minimum=50000)
225
- entrada_input = gr.Number(label="Entrada Desejada (R$)", value=30000, step=1000, minimum=5000)
226
- parcela_input = gr.Number(label="Parcela Desejada (R$)", value=1500, step=100, minimum=500)
227
 
228
  administradoras_multiselect = gr.CheckboxGroup(
229
  label="Filtrar por Administradoras",
230
  choices=get_administradoras_options(),
231
- value=get_administradoras_options(),
232
- interactive=True
233
  )
234
 
235
  submit_btn = gr.Button("🔍 Buscar Combinações", variant="primary")
236
- output_text = gr.Textbox(label="Resultados da Busca", lines=20, interactive=False)
 
237
 
238
  submit_btn.click(
239
- fn=buscar_combinacoes,
240
  inputs=[credito_input, entrada_input, parcela_input, administradoras_multiselect],
241
  outputs=output_text
242
  )
243
 
244
  gr.Markdown("---")
245
- gr.Markdown("*Atenção:* Valores calculados incluem comissão de 10% sobre o crédito.")
246
-
247
- # Carrega a planilha ao iniciar
248
- if carregar_planilha():
249
- print("✅ Sistema pronto para uso!")
250
- else:
251
- print("⚠ Sistema carregado com limitações - planilha não disponível")
252
 
253
- if _name_ == "_main_":
254
- demo.launch()
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """Imovel.ipynb
3
+
4
+ Automatically generated by Colab.
5
+
6
+ Original file is located at
7
+ https://colab.research.google.com/drive/1DZAQZfrXvTy358Vg2qfUg_ge6b3kcgBy
8
+ """
9
+
10
+ # app.py
11
  import pandas as pd
12
  import requests
13
  import io
14
  import itertools
15
  from collections import defaultdict
16
  import gradio as gr
17
+ import time
18
 
19
  # 🔧 CONFIGURAÇÕES GLOBAIS
20
+ # Certifique-se de que este FILE_ID esteja acessível publicamente ou para "Qualquer pessoa com o link"
21
+ FILE_ID = "1XvNz7DlWioT64uNdcfBSL8Ui2nRSi9gT"
22
  URL = f"https://drive.google.com/uc?export=download&id={FILE_ID}"
23
 
24
  # Variável global para armazenar o DataFrame
25
  df = None
26
 
27
  def carregar_planilha():
28
+ """Carrega e prepara a planilha para análise."""
29
  global df
30
  try:
31
+ print("⏳ Carregando planilha...")
32
  response = requests.get(URL)
33
  response.raise_for_status()
34
  data = io.BytesIO(response.content)
 
36
 
37
  # Padroniza nomes das colunas
38
  df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_")
39
+ df['administradora'] = df['administradora'].str.strip().str.lower()
40
 
 
 
 
41
 
42
  # Converte colunas numéricas
43
+ colunas_numericas = ['valor_credito', 'valor_entrada', 'valor_parcela', 'saldo_devedor', 'qtd_parcelas']
44
+ for coluna in colunas_numericas:
45
+ if coluna in df.columns:
46
+ df[coluna] = pd.to_numeric(df[coluna], errors='coerce').fillna(0)
47
+
 
 
 
 
48
  # Verifica colunas essenciais
49
+ if 'tipo_do_bem' not in df.columns or 'administradora' not in df.columns:
50
+ raise ValueError("Colunas essenciais não encontradas")
 
 
51
 
52
  # Remove duplicatas
53
  df.drop_duplicates(inplace=True)
54
+
55
+ print("✅ Planilha carregada com sucesso")
56
  return True
57
 
58
  except Exception as e:
 
67
  return grupos
68
 
69
  def buscar_combinacoes(credito_desejado, entrada_desejada, parcela_desejada, administradoras=None):
70
+ """Busca combinações de cotas dentro dos parâmetros especificados."""
71
+ # Garante que o DataFrame está carregado
72
  if df is None:
73
+ # Tenta carregar se ainda não foi carregado
74
  if not carregar_planilha():
75
+ return "❌ Erro: Planilha não carregada. Por favor, tente novamente."
76
 
77
+ # Filtra por tipo de bem e administradoras
78
+ df_filtrado = df[df['tipo_do_bem'].str.lower() == 'imovel']
 
79
  if administradoras:
80
+ # Certifica-se de que administradoras é uma lista (Gradio retorna tupla)
81
  if isinstance(administradoras, tuple):
82
  administradoras = list(administradoras)
83
  administradoras = [a.strip().lower() for a in administradoras]
84
  df_filtrado = df_filtrado[df_filtrado['administradora'].isin(administradoras)]
85
 
86
  if df_filtrado.empty:
87
+ return "🚫 Nenhuma cota encontrada com os filtros aplicados. Tente ajustar os parâmetros."
88
 
89
+ # Define faixas de tolerância
90
+ credito_min, credito_max = credito_desejado * 0.93, credito_desejado * 1.07
91
+ entrada_min, entrada_max = entrada_desejada * 0.93, entrada_desejada * 1.07
92
+ parcela_min, parcela_max = parcela_desejada * 0.75, parcela_desejada * 1.25
93
 
94
  grupos = agrupar_por_administradora(df_filtrado)
95
  resultados = []
 
99
  for combinacao in itertools.combinations(cotas, r):
100
  total_credito = sum(c['valor_credito'] for c in combinacao)
101
  total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
102
+ total_entrada = total_entrada_base + (total_credito * 0.085) # aplica os 8,5% sobre o crédito
103
  total_parcelas = sum(c['valor_parcela'] for c in combinacao)
104
 
105
  if (credito_min <= total_credito <= credito_max and
 
108
 
109
  total_saldo = sum(c['saldo_devedor'] for c in combinacao)
110
  valor_final = round(total_entrada + total_saldo, 2)
111
+ diferenca = abs(valor_final - total_credito) # Diferença do valor final pelo crédito (para ordenação)
112
 
113
  resultados.append((adm, combinacao, diferenca))
114
 
115
  if not resultados:
116
+ return "🚫 Nenhuma combinação adequada encontrada com os parâmetros fornecidos."
117
+
118
+ resultados.sort(key=lambda x: x[2]) # Ordena pela diferença
119
 
 
120
  return formatar_resultados(resultados)
121
 
122
  def formatar_moeda(valor):
 
123
  return f"R$ {valor:,.2f}".replace(",", "v").replace(".", ",").replace("v", ".")
124
 
125
  def formatar_resultados(resultados):
126
+ """Formata os resultados para exibição."""
127
  resposta = ""
128
+ # Limita a 15 resultados para evitar saídas muito longas
129
+ for idx, (adm, combinacao, _) in enumerate(resultados[:15], 1):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  codigos = [str(c.get('codigo', 'N/A')) for c in combinacao]
131
  total_credito = sum(c['valor_credito'] for c in combinacao)
132
  total_entrada_base = sum(c['valor_entrada'] for c in combinacao)
133
+ total_entrada = total_entrada_base + (total_credito * 0.085)
134
  total_saldo = sum(c['saldo_devedor'] for c in combinacao)
135
  total_parcelas = sum(c['valor_parcela'] for c in combinacao)
136
  maior_prazo = max(int(c.get('qtd_parcelas', 0)) for c in combinacao)
 
143
 
144
  resposta += f"""
145
  --- COMBINAÇÃO {idx} ---
146
+ 🏢 Administradora: {adm}
147
  🔢 Códigos: {', '.join(codigos)}
148
  💰 Crédito Total: {formatar_moeda(total_credito)}
149
+ 💵 Entrada (+comissão): {formatar_moeda(total_entrada)}
150
  📉 Saldo Devedor: {formatar_moeda(total_saldo)}
151
  💲 Parcela: {formatar_moeda(total_parcelas)}
152
  ⏳ Prazo: {maior_prazo} meses
153
  🔚 Valor Final: {formatar_moeda(valor_final)}
154
  💠 Crédito Líquido: {formatar_moeda(credito_real)}
155
  📊 Taxa Total: {taxa_percentual:.2f}% ({formatar_moeda(taxa_total)})
156
+ 🗓 Taxa Mensal: {taxa_mensal:.2f}%
157
+ 🗓 Taxa Anual: {taxa_mensal * 12:.2f}%
158
  """
159
  return resposta
160
 
161
+ # Carrega a planilha uma vez quando o aplicativo inicia
162
+ carregar_planilha()
163
+
164
+ def ajustar_e_buscar(credito_desejado, entrada_desejada, parcela_desejada, administradoras):
165
+ entrada_calculada = credito_desejado * 0.085 + entrada_desejada
166
+ return buscar_combinacoes(credito_desejado, entrada_calculada, parcela_desejada, administradoras)
167
+
168
+ # Prepara a lista de administradoras para o Gradio
169
  def get_administradoras_options():
 
170
  if df is not None:
171
+ adm_list = df[df['tipo_do_bem'].str.lower() == 'imovel']['administradora'].unique()
172
+ return sorted(adm_list)
173
  return []
174
 
175
+ # Criando a interface Gradio
176
+ with gr.Blocks(title="Sistema de Busca de Consórcio Imóvel") as demo:
177
+ gr.HTML("""
178
+ <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
179
  <style>
180
+ * {
181
+ font-family: 'Poppins', sans-serif !important;
182
+ }
183
+
184
+ body {
185
+ background-color: #ff8f00 !important;
186
+ color: black !important;
187
+ }
188
+
189
+ /* Inputs Numéricos: Crédito, Entrada, Parcela */
190
+ input[type="number"] {
191
  background-color: white !important;
192
  border: 2px solid #000 !important;
193
  border-radius: 12px !important;
194
+ color: black !important;
195
  padding: 10px !important;
196
+ font-weight: 500;
197
  }
198
+
199
+ /* Inputs de texto e áreas de texto (como a saída e código) */
200
+ input[type="text"], textarea {
201
+ background-color: white !important;
202
+ border: 2px solid black !important;
203
+ border-radius: 12px !important;
204
+ color: black !important;
205
+ padding: 10px !important;
206
+ }
207
+
208
+ input::placeholder, textarea::placeholder {
209
+ color: #333 !important;
210
+ opacity: 0.7;
211
+ }
212
+
213
+ .gr-checkbox label {
214
+ display: flex;
215
+ align-items: center;
216
+ gap: 8px;
217
+ font-weight: 600;
218
+ }
219
+
220
+ input[type="checkbox"] {
221
+ accent-color: black !important;
222
+ width: 18px;
223
+ height: 18px;
224
+ }
225
+
226
  .gr-button {
227
  font-weight: bold;
228
  border-radius: 10px !important;
 
230
  color: black !important;
231
  border: 2px solid black !important;
232
  }
233
+
234
+ .gr-button:hover {
235
+ background-color: #fff3e0 !important;
236
+ color: black !important;
237
+ }
238
+
239
+ label {
240
+ font-weight: 600 !important;
241
+ }
242
  </style>
243
  """)
244
+
245
+
246
+ gr.Markdown("# 🏠 Busca de Combinações de Consórcio Imóvel")
247
+ gr.Markdown("Insira os valores desejados para crédito, entrada e parcela, e filtre por administradora.")
248
 
249
  with gr.Row():
250
+ credito_input = gr.Number(label="Crédito Desejado (R$)", value=300000, step=1000)
251
+ entrada_input = gr.Number(label="Entrada Desejada (R$)", value=30000, step=1000)
252
+ parcela_input = gr.Number(label="Parcela Desejada (R$)", value=1500, step=100)
253
 
254
  administradoras_multiselect = gr.CheckboxGroup(
255
  label="Filtrar por Administradoras",
256
  choices=get_administradoras_options(),
257
+ value=get_administradoras_options() # Seleciona todas por padrão
 
258
  )
259
 
260
  submit_btn = gr.Button("🔍 Buscar Combinações", variant="primary")
261
+
262
+ output_text = gr.Textbox(label="Resultados da Busca", lines=20, max_lines=40, interactive=False, placeholder="Os resultados aparecerão aqui...")
263
 
264
  submit_btn.click(
265
+ fn=ajustar_e_buscar,
266
  inputs=[credito_input, entrada_input, parcela_input, administradoras_multiselect],
267
  outputs=output_text
268
  )
269
 
270
  gr.Markdown("---")
271
+ gr.Markdown("Desenvolvido para auxiliar na busca por cotas de consórcio ideais.")
 
 
 
 
 
 
272
 
273
+ # Inicia o aplicativo Gradio
274
+ if __name__ == "__main__":
275
+ demo.launch() # Você não precisa disso no Colab, mas sim no arquivo que você fará o deploy