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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +220 -1
app.py CHANGED
@@ -32,4 +32,223 @@ def carregar_planilha():
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_deve
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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:
56
+ print(f"❌ Erro ao carregar planilha: {str(e)}")
57
+ return False
58
+
59
+ def agrupar_por_administradora(dataframe):
60
+ """Agrupa cotas por administradora."""
61
+ grupos = defaultdict(list)
62
+ for _, row in dataframe.iterrows():
63
+ grupos[row['administradora']].append(row.to_dict())
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 = []
92
+
93
+ for adm, cotas in grupos.items():
94
+ for r in range(1, min(3, len(cotas)) + 1): # Máximo 3 cotas por combinação
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
102
+ entrada_min <= total_entrada <= entrada_max and
103
+ parcela_min <= total_parcelas <= parcela_max):
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)
167
+
168
+ valor_final = round(total_entrada + total_saldo, 2)
169
+ credito_real = round(total_credito - total_entrada, 2)
170
+ taxa_total = total_saldo - credito_real
171
+ taxa_percentual = (taxa_total / credito_real) * 100 if credito_real > 0 else 0
172
+ taxa_mensal = taxa_percentual / maior_prazo if maior_prazo > 0 else 0
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;
212
+ background-color: white !important;
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()