Spaces:
Sleeping
Sleeping
| import pandas as pd | |
| import numpy as np | |
| import joblib | |
| import seaborn as sns | |
| import matplotlib.pyplot as plt | |
| import xgboost as xgb | |
| import warnings | |
| import gradio as gr | |
| from reportlab.lib.pagesizes import A4 | |
| from reportlab.platypus import Spacer, Frame, PageTemplate, BaseDocTemplate, Paragraph | |
| from reportlab.lib.styles import getSampleStyleSheet | |
| inf_scaler_in = joblib.load("dados/apartamentos/input_scaler_ape_DEZ2024.save") | |
| inf_scaler_out = joblib.load("dados/apartamentos/output_scaler_ape_DEZ2024.save") | |
| inf_model_v1 = xgb.Booster(); inf_model_v1.load_model("dados/apartamentos/APARTAMENTO_2020_a_2025.model") | |
| inf_model_v2 = xgb.Booster(); inf_model_v2.load_model("dados/apartamentos/APARTAMENTOS_RESIDUAL_2026.model") | |
| # Função para gerar PDF | |
| def gerar_pdf(dados_imovel, valor_unit, valor_total): | |
| filename = 'relatorio.pdf' | |
| doc = BaseDocTemplate(filename, pagesize=A4) | |
| styles = getSampleStyleSheet() | |
| story = [ | |
| Paragraph("Relatório - Modelo Híbrido 2026", styles['Title']), | |
| Spacer(1, 12), | |
| Paragraph(f"<b>Ano Base:</b> {dados_imovel['ano_ref']}", styles['Normal']), | |
| Paragraph(f"<b>Características:</b> {dados_imovel['area']} m², Padrão {dados_imovel['padrao']}, Ano Const. {dados_imovel['ano_c']}", styles['Normal']), | |
| Paragraph(f"<b>Localização (UTM):</b> X={dados_imovel['x']}, Y={dados_imovel['y']}", styles['Normal']), | |
| Spacer(1, 20), | |
| Paragraph(f"<b>Valor Unitário Calculado:</b> R$ {valor_unit:,.2f}/m²", styles['Heading2']), | |
| Paragraph(f"<b>Valor Total Estimado:</b> R$ {valor_total:,.2f}", styles['Heading2']), | |
| ] | |
| frame = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height, id='normal') | |
| template = PageTemplate(id='base', frames=frame) | |
| doc.addPageTemplates([template]) | |
| doc.build(story) | |
| return filename | |
| # FUNÇÃO PRINCIPAL DA INTERFACE | |
| def avaliar_imovel(fon_str, x, y, rh, ano_c, atotal, andar, padrao, ano_ref): | |
| # 1. Mapeamento de Features (Feature Engineering em Tempo Real) | |
| is_oferta = 1 if fon_str == "Oferta" else 0 | |
| # Padrão (One Hot Encoding manual) | |
| # Se for A ou B, C/D/E permanecem 0 | |
| dummies_padrao = {'C': 0, 'D': 0, 'E': 0} | |
| if padrao in dummies_padrao: | |
| dummies_padrao[padrao] = 1 | |
| # Dummies de Ano V1 (2019-2024) | |
| anos_v1 = {f'ANO_{a}': (1 if str(ano_ref) == str(a) else 0) for a in range(2019, 2025)} | |
| # Dummy de Ano V2 (2025) | |
| is_2025 = 1 if str(ano_ref) == '2025' else 0 | |
| # Montagem do DataFrame Input (Single Row) | |
| # Atenção aos Logs! | |
| input_dict = { | |
| 'FON': [is_oferta], | |
| 'ANO_CONST': [float(ano_c)], | |
| 'ANDAR': [float(andar)], | |
| 'X': [float(x)], | |
| 'Y': [float(y)], | |
| 'ATOTAL': [np.log(float(atotal))], # Log Transform | |
| 'RH': [np.log(float(rh))], # Log Transform | |
| **dummies_padrao, | |
| **anos_v1 | |
| } | |
| # Lista de colunas na ordem correta do V1 | |
| cols_v1 = [ | |
| 'FON', 'ANO_CONST', 'ANDAR', 'X', 'Y', 'ATOTAL', 'RH', | |
| 'ANO_2019', 'ANO_2020', 'ANO_2021', 'ANO_2022', 'ANO_2023', 'ANO_2024', | |
| 'C', 'D', 'E' | |
| ] | |
| df_inferencia = pd.DataFrame(input_dict) | |
| # Garante ordem e preenche ausentes se houver | |
| for c in cols_v1: | |
| if c not in df_inferencia.columns: df_inferencia[c] = 0 | |
| df_inferencia = df_inferencia[cols_v1] | |
| try: | |
| # 2. Escalonamento V1 | |
| array_scaled = inf_scaler_in.transform(df_inferencia) | |
| # 3. Predição Baseline (V1) | |
| dmatrix_base = xgb.DMatrix(array_scaled, feature_names=cols_v1) | |
| pred_base = inf_model_v1.predict(dmatrix_base) | |
| # 4. Lógica de Decisão Temporal (Compatibilidade Reversa) | |
| # Se o ano for anterior a 2025, não usamos o modelo residual para manter consistência histórica. | |
| final_pred_scaled = pred_base | |
| if int(ano_ref) >= 2025: | |
| # Prepara entrada V2 (V1 Scaled + Coluna ANO_2025) | |
| # Adiciona a coluna 2025 (que é 1 neste caso) | |
| input_v2 = np.hstack([array_scaled, [[is_2025]]]) | |
| dmatrix_v2 = xgb.DMatrix(input_v2) | |
| dmatrix_v2.set_base_margin(pred_base) | |
| # Predição Híbrida | |
| final_pred_scaled = inf_model_v2.predict(dmatrix_v2) | |
| # 5. Pós-Processamento (Inverse Transform) | |
| # Inverte Scaler de Output | |
| pred_log = inf_scaler_out.inverse_transform(np.array(final_pred_scaled).reshape(-1,1)) | |
| # Inverte Log (Exp) | |
| val_unit_real = np.exp(pred_log).flatten()[0] | |
| # Cálculos Finais | |
| total_val = val_unit_real * float(atotal) | |
| # Gera PDF | |
| dados_contexto = { | |
| 'ano_ref': ano_ref, 'area': atotal, 'padrao': padrao, | |
| 'ano_c': ano_c, 'x': x, 'y': y | |
| } | |
| path_pdf = gerar_pdf(dados_contexto, val_unit_real, total_val) | |
| msg = f"Valor Unitário: R$ {val_unit_real:,.2f}/m²\nValor Total: R$ {total_val:,.2f}" | |
| return msg, path_pdf | |
| except Exception as e: | |
| return f"Erro Crítico: {str(e)}", None | |
| def load_inputs(): | |
| in_fon = gr.Radio(["Transação", "Oferta"], label="Fonte de Dados", value="Transação") | |
| in_x = gr.Number(label="Coord X (UTM)", value=281554) | |
| in_y = gr.Number(label="Coord Y (UTM)", value=1675418) | |
| in_rh = gr.Number(label="Região Homogênea", value=120) | |
| in_area = gr.Number(label="Área Total (m²)", value=60) | |
| in_andar = gr.Number(label="Andar", value=4) | |
| in_ano_c = gr.Number(label="Ano Construção", value=2020) | |
| in_padrao = gr.Dropdown(["C", "D", "E"], label="Padrão", value="C") | |
| in_ano_ref = gr.Dropdown([str(i) for i in range(2019, 2026)], label="Ano Base", value="2025") | |
| return [in_fon, in_x, in_y, in_rh, in_ano_c, in_area, in_andar, in_padrao, in_ano_ref] | |
| title = 'Apartamentos - XGBoost Regressor - 2026' | |
| description = f""" | |
| # <p style="text-align: center;">Modelo para Apartamentos - XGBoost Regressor - 2026</p> | |
| <p style="text-align: center;">Dados referentes aos anos 2019 a 2025.</p> | |
| <hr style="color: #333; background-color: #333; height: 1px; border: none;"> | |
| """ |