Dissertaai / api.py
Mftoneto's picture
Upload 6 files
48c7fa7 verified
"""
API HTTP do corretor de redacao ENEM.
Endpoints:
GET /health -> {"status": "ok"}
POST /corrigir -> body {"texto": "..."}, retorna notas C1..C5 + total
"""
from __future__ import annotations
from contextlib import asynccontextmanager
from typing import Optional
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
from corretor import corrigir, diagnosticar, load_models
@asynccontextmanager
async def lifespan(app: FastAPI):
# Pre-carrega os 5 modelos no startup para a primeira request nao pagar o custo.
load_models()
yield
app = FastAPI(
title="Dissero - Corretor ENEM",
description="API de correcao automatica de redacao ENEM (modelos kamel-usp).",
version="0.1.0",
lifespan=lifespan,
)
# CORS restrito: Vite local + deploys do Vercel (production + previews).
ALLOWED_ORIGINS = [
"http://localhost:5173",
"http://localhost:4173",
"https://dissero.vercel.app",
"https://dissertaai.vercel.app",
"https://dissero-git-main-tonetos-projects.vercel.app",
]
app.add_middleware(
CORSMiddleware,
allow_origins=ALLOWED_ORIGINS,
allow_origin_regex=r"^https://dissero-[a-z0-9-]+-tonetos-projects\.vercel\.app$",
allow_credentials=True,
allow_methods=["POST", "GET", "OPTIONS"],
allow_headers=["*"],
)
class RedacaoRequest(BaseModel):
texto: str = Field(..., min_length=1, description="Texto da redacao em portugues.")
class C5Boost(BaseModel):
de: int
para: int
elementos: int
class CorrecaoResponse(BaseModel):
C1: int
C2: int
C3: int
C4: int
C5: int
total: int
# Metadados (transparencia da decisao)
modelo_usado: Optional[str] = None
jbcs_total: Optional[int] = None
local_total: Optional[int] = None
c5_boost: Optional[C5Boost] = None
@app.get("/health")
def health() -> dict:
return {"status": "ok"}
@app.post("/corrigir", response_model=CorrecaoResponse)
def corrigir_endpoint(req: RedacaoRequest) -> dict:
raw = corrigir(req.texto)
# Mapeia underscores internos pra nomes publicos do schema
out = {
"C1": raw["C1"], "C2": raw["C2"], "C3": raw["C3"],
"C4": raw["C4"], "C5": raw["C5"], "total": raw["total"],
"modelo_usado": raw.get("_modelo_usado"),
"jbcs_total": raw.get("_jbcs_total"),
"local_total": raw.get("_local_total"),
}
boost = raw.get("_c5_heuristica_boost")
if boost:
out["c5_boost"] = {
"de": boost["de"], "para": boost["para"],
"elementos": boost["elementos"],
}
return out
@app.post("/debug")
def debug_endpoint(req: RedacaoRequest) -> dict:
"""Diagnostico completo: logits, softmax, e varias estrategias de decoding."""
return diagnosticar(req.texto)