|
import gradio as gr |
|
import pandas as pd |
|
import numpy as np |
|
import torch |
|
import joblib |
|
import json |
|
import os |
|
import traceback |
|
from transformers import AutoTokenizer, AutoModel |
|
from torch import nn |
|
|
|
|
|
|
|
class RegressionTransformer(nn.Module): |
|
def __init__(self, model_name='neuralmind/bert-base-portuguese-cased'): |
|
super(RegressionTransformer, self).__init__() |
|
self.bert = AutoModel.from_pretrained(model_name) |
|
self.regressor = nn.Sequential( |
|
nn.Dropout(p=0.2), |
|
nn.Linear(self.bert.config.hidden_size, 128), |
|
nn.ReLU(), |
|
nn.Dropout(p=0.2), |
|
nn.Linear(128, 1) |
|
) |
|
def forward(self, input_ids, attention_mask): |
|
outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask) |
|
pooled_output = outputs.pooler_output |
|
return self.regressor(pooled_output) |
|
|
|
|
|
|
|
print("Carregando artefatos do modelo...") |
|
device = torch.device("cpu") |
|
CACHE_DIR = "./huggingface_cache" |
|
|
|
try: |
|
|
|
TOKENIZER_NAME = 'neuralmind/bert-base-portuguese-cased' |
|
tokenizer = AutoTokenizer.from_pretrained(TOKENIZER_NAME, cache_dir=CACHE_DIR) |
|
print("Tokenizador carregado.") |
|
|
|
|
|
MODEL_PATH = './model/best_model_state.pth' |
|
model = RegressionTransformer(model_name=TOKENIZER_NAME) |
|
model.load_state_dict(torch.load(MODEL_PATH, map_location=device)) |
|
model.to(device) |
|
model.eval() |
|
print("Modelo carregado.") |
|
|
|
|
|
FEATURES_PATH = './model/model_features.json' |
|
with open(FEATURES_PATH, 'r') as f: |
|
features_dict = json.load(f) |
|
model_features = features_dict['numeric'] + features_dict['categorical'] |
|
print("Features do modelo carregadas.") |
|
|
|
except Exception as e: |
|
print("!!!!!! ERRO FATAL AO CARREGAR ARTEFATOS !!!!!!") |
|
traceback.print_exc() |
|
raise e |
|
|
|
|
|
|
|
def predict_price(make, model_name, year, odometer, trim, body, transmission, color, interior): |
|
try: |
|
print(f"Recebida nova predição: {make}, {model_name}, {year}, {odometer}km") |
|
|
|
|
|
input_data_dict = { |
|
'make': make, 'model': model_name, 'year': int(year), 'odometer': float(odometer), |
|
'trim': trim, 'body': body, 'transmission': transmission, |
|
'color': color, 'interior': interior |
|
} |
|
input_df = pd.DataFrame([input_data_dict]) |
|
|
|
|
|
ano_referencia = 2024 |
|
input_df['age'] = ano_referencia - input_df['year'] |
|
input_df['sale_month'] = 0 |
|
input_df['sale_dayofweek'] = 0 |
|
input_df['sale_dayofyear'] = 0 |
|
input_df['make_popularity'] = 0 |
|
input_df['model_popularity'] = 0 |
|
input_df['km_per_year'] = 0 |
|
|
|
|
|
def criar_representacao_textual(row): |
|
partes = [f"{coluna}[{str(row[coluna])}]" for coluna in model_features if coluna in row] |
|
return " | ".join(partes) |
|
text_input = input_df.apply(criar_representacao_textual, axis=1).iloc[0] |
|
|
|
|
|
encoded_text = tokenizer.encode_plus( |
|
text_input, max_length=128, return_tensors='pt', |
|
padding='max_length', truncation=True |
|
) |
|
input_ids = encoded_text['input_ids'].to(device) |
|
attention_mask = encoded_text['attention_mask'].to(device) |
|
|
|
|
|
with torch.no_grad(): |
|
prediction_log = model(input_ids, attention_mask) |
|
|
|
|
|
predicted_price = np.expm1(prediction_log.cpu().numpy()[0][0]) |
|
|
|
|
|
return f"R$ {predicted_price:,.2f}".replace(",", "X").replace(".", ",").replace("X", ".") |
|
|
|
except Exception as e: |
|
print("!!!!!! ERRO DURANTE A PREVISÃO !!!!!!") |
|
traceback.print_exc() |
|
return "Ocorreu um erro. Verifique os logs." |
|
|
|
|
|
|
|
with gr.Blocks(theme=gr.themes.Soft(), css="footer {display: none !important}") as demo: |
|
gr.Markdown("# 🚗 FipeFinder AI: Previsão de Preços de Carros Usados") |
|
gr.Markdown("Preencha as características do veículo para receber uma estimativa de preço de mercado baseada em nosso modelo de IA. Este projeto demonstra um pipeline completo de Machine Learning, desde a análise de dados e treinamento de um modelo Transformer até o deploy de uma aplicação interativa.") |
|
|
|
with gr.Row(): |
|
with gr.Column(scale=1): |
|
make_input = gr.Dropdown(label="Marca", choices=["Ford", "Chevrolet", "Honda", "Toyota", "Nissan", "Hyundai", "Kia", "BMW", "Mercedes-Benz", "Volkswagen"]) |
|
model_input = gr.Textbox(label="Modelo", placeholder="Ex: Ka, Onix, Civic, Corolla...") |
|
year_input = gr.Slider(label="Ano do Modelo", minimum=2000, maximum=2024, step=1, value=2015) |
|
|
|
with gr.Column(scale=1): |
|
odo_input = gr.Number(label="Quilometragem (km)", value=80000) |
|
trim_input = gr.Textbox(label="Versão", placeholder="Ex: SE 1.0, LTZ, EXL...") |
|
body_input = gr.Dropdown(label="Carroceria", choices=["Sedan", "SUV", "Hatchback", "Pickup", "Minivan", "Coupe", "Wagon"]) |
|
|
|
with gr.Column(scale=1): |
|
trans_input = gr.Radio(label="Transmissão", choices=["automatic", "manual"], value="automatic") |
|
color_input = gr.Textbox(label="Cor Externa", placeholder="Ex: preto, branco, prata...") |
|
interior_input = gr.Textbox(label="Cor Interior", placeholder="Ex: preto, cinza, bege...") |
|
|
|
predict_btn = gr.Button("Estimar Preço", variant="primary") |
|
output_price = gr.Label(label="Preço Estimado") |
|
|
|
predict_btn.click( |
|
fn=predict_price, |
|
inputs=[make_input, model_input, year_input, odo_input, trim_input, body_input, trans_input, color_input, interior_input], |
|
outputs=output_price |
|
) |
|
|
|
gr.Examples( |
|
examples=[ |
|
["Ford", "Focus", 2013, 75000.0, "SE 2.0", "Hatchback", "automatic", "prata", "preto"], |
|
["Chevrolet", "Onix", 2018, 90000.0, "LT 1.0", "Hatchback", "manual", "branco", "cinza"], |
|
["Toyota", "Corolla", 2020, 40000.0, "XEi", "Sedan", "automatic", "preto", "preto"], |
|
], |
|
inputs=[make_input, model_input, year_input, odo_input, trim_input, body_input, trans_input, color_input, interior_input] |
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
demo.launch() |