Arthur-Attili commited on
Commit
3410ffa
·
verified ·
1 Parent(s): ba31397

Update app.py

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