File size: 7,110 Bytes
f801f42 00a925e f801f42 00a925e f801f42 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
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
# --- 1. DEFINIÇÃO DA ARQUITETURA DO MODELO ---
# Colocamos a classe aqui para que a aplicação seja autocontida.
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)
# --- 2. CARREGAMENTO DOS ARTEFATOS GLOBAIS ---
# Esta seção é executada uma vez quando a aplicação inicia no Hugging Face Spaces.
print("Carregando artefatos do modelo...")
device = torch.device("cpu")
CACHE_DIR = "./huggingface_cache"
try:
# Carrega o tokenizador
TOKENIZER_NAME = 'neuralmind/bert-base-portuguese-cased'
tokenizer = AutoTokenizer.from_pretrained(TOKENIZER_NAME, cache_dir=CACHE_DIR)
print("Tokenizador carregado.")
# Carrega o modelo treinado
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.")
# Carrega a lista de features que o modelo espera
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
# --- 3. FUNÇÃO DE LÓGICA / PREVISÃO ---
# Esta função contém a "inteligência" do back-end.
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")
# Converte os inputs da interface em um DataFrame de uma linha
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])
# Aplica a mesma engenharia de features do treinamento
ano_referencia = 2024
input_df['age'] = ano_referencia - input_df['year']
input_df['sale_month'] = 0 # Placeholder
input_df['sale_dayofweek'] = 0 # Placeholder
input_df['sale_dayofyear'] = 0
input_df['make_popularity'] = 0
input_df['model_popularity'] = 0
input_df['km_per_year'] = 0
# Cria a "frase" textual
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]
# Tokeniza e prepara os tensores
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)
# Faz a inferência
with torch.no_grad():
prediction_log = model(input_ids, attention_mask)
# Pós-processa o resultado
predicted_price = np.expm1(prediction_log.cpu().numpy()[0][0])
# Formata a string de saída para o usuário
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."
# --- 4. DEFINIÇÃO DA INTERFACE COM GRADIO ---
# Esta seção define a aparência do "front-end".
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]
)
# --- Lançamento da Interface ---
if __name__ == "__main__":
demo.launch() |