Coverage for src / main.py: 77%
35 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-26 08:30 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-26 08:30 +0000
1import logging
2from contextlib import asynccontextmanager
4from fastapi import APIRouter, FastAPI, HTTPException
5from fastapi.responses import JSONResponse
7from src.models.predict_model import load_artifacts, predict_churn
8from src.schemas.api_schema import CustomerRequest
10# Instancia o logger configurado na Etapa 3
11logger = logging.getLogger(__name__)
14@asynccontextmanager
15async def lifespan(app: FastAPI):
16 """
17 O Lifespan Events do FastAPI nos permite executar código ANTES de aceitar a primeira requisição.
18 Isso é crítico em MLOps (Cold Start). Vamos carregar as pesadas matrizes do PyTorch (.pth)
19 e o Scikit-Learn (.joblib) diretamente na RAM do servidor aqui.
20 """
21 logger.info(
22 "Iniciando FastAPI... Puxando pesos do PyTorch para a RAM (Cold Start Optimization)"
23 )
24 try:
25 load_artifacts()
26 logger.info("Artefatos de Inteligência Artificial carregados com sucesso!")
27 except Exception as e:
28 logger.error(f"Falha Crítica ao carregar os modelos: {e}")
29 # A API pode subir mesmo falhando, mas o /health alertará sobre o erro.
31 yield # O servidor passa a aceitar requisições
33 logger.info("Desligando API. Liberando memória RAM.")
36# Instancia a aplicação FastAPI injetando o Lifespan
37app = FastAPI(
38 title="Telco Churn API",
39 description="API de Inferência de Churn baseada em Redes Neurais Densa (PyTorch)",
40 version="1.0.0",
41 lifespan=lifespan,
42)
45# Cria o Router da Versão 1 (v1)
46v1_router = APIRouter(prefix="/v1")
49@app.get("/health", tags=["Monitoring"])
50def health_check():
51 """
52 Rota de monitoramento de saúde do microsserviço.
53 Utilizada por Load Balancers e Kubernetes para atestar se a API está viva.
54 """
55 return {"status": "healthy", "service": "telco-churn-api"}
58@v1_router.post("/predict", tags=["Inference"])
59def predict(customer: CustomerRequest):
60 """
61 Rota de Predição em Tempo Real (Versão 1).
62 Recebe o JSON do cliente (validado pelo Pydantic), injeta no modelo (Pandera + PyTorch),
63 e retorna o booleano de churn considerando o Custo Financeiro (Threshold 30%).
64 """
65 try:
66 # Pydantic converte a entrada em dicionário python nativo
67 raw_dict = customer.model_dump()
69 # Envia para o motor de inferência que desenhamos na Etapa 3.1
70 resultado = predict_churn(raw_dict)
71 return JSONResponse(content=resultado)
73 except ValueError as ve:
74 # Erros mapeados (ex: Schema Pandera falhou) viram Bad Request ou Unprocessable Entity
75 logger.warning(f"Requisição rejeitada por validação do Motor ML: {ve}")
76 raise HTTPException(status_code=422, detail=str(ve))
77 except Exception as e:
78 # Erros não mapeados (ex: PyTorch quebrou a matriz) viram Internal Server Error 500
79 logger.error(f"Internal Server Error no Forward Pass: {e}")
80 raise HTTPException(status_code=500, detail="Erro interno no Motor de Predição")
83# Registra o Router v1 no App Principal
84app.include_router(v1_router)