Spaces:
Runtime error
Runtime error
| """ | |
| FastAPI Application - para.AI v3.0 | |
| Endpoint principal para processamento de acórdãos jurisprudenciais | |
| """ | |
| from fastapi import FastAPI, Request | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.middleware.gzip import GZipMiddleware | |
| from fastapi.responses import JSONResponse | |
| from contextlib import asynccontextmanager | |
| import time | |
| from datetime import datetime | |
| from api.config import get_settings | |
| from api.utils.logger import api_logger | |
| from api.utils.exceptions import ParaAIException | |
| settings = get_settings() | |
| # Variável global para tracking de uptime | |
| app_start_time = datetime.now() | |
| async def lifespan(app: FastAPI): | |
| """Lifecycle events - startup e shutdown.""" | |
| # Startup | |
| api_logger.info("=" * 70) | |
| api_logger.info(f"🚀 Starting {settings.APP_NAME} v{settings.APP_VERSION}") | |
| api_logger.info(f"📍 Environment: {settings.APP_ENV}") | |
| api_logger.info(f"🐛 Debug mode: {settings.DEBUG}") | |
| api_logger.info(f"🗄️ Database: {settings.DATABASE_URL.split('@')[-1] if '@' in settings.DATABASE_URL else 'N/A'}") | |
| api_logger.info(f"📂 Files path: {settings.FILES_BASE_PATH}") | |
| api_logger.info(f"🤖 LLM Providers:") | |
| api_logger.info(f" - Groq: {'✅' if settings.GROQ_API_KEY else '❌'}") | |
| api_logger.info(f" - OpenAI: {'✅' if settings.OPENAI_API_KEY else '❌'}") | |
| api_logger.info(f" - Anthropic: {'✅' if settings.ANTHROPIC_API_KEY else '❌'}") | |
| api_logger.info("=" * 70) | |
| yield | |
| # Shutdown | |
| api_logger.info("🛑 Shutting down para.AI API") | |
| app = FastAPI( | |
| title=settings.APP_NAME, | |
| version=settings.APP_VERSION, | |
| description=""" | |
| # para.AI - Análise Jurisprudencial com IA | |
| Sistema completo para processamento automatizado de acórdãos com 9 especialistas IA. | |
| ## Funcionalidades Principais | |
| * 📤 **Upload JSONL**: Envie lotes de acórdãos para processamento | |
| * 🤖 **9 Especialistas**: Análise por múltiplos processadores especializados | |
| * 📦 **Download TAR.GZ**: Receba resultados compactados | |
| * 🔍 **Debug Completo**: Teste cada componente isoladamente | |
| * 📊 **Métricas**: Acompanhe performance e custos | |
| ## Endpoints Principais | |
| * `/api/v1/process/upload` - Upload e processamento | |
| * `/api/v1/process/status/{task_id}` - Status da tarefa | |
| * `/api/v1/process/download/{task_id}` - Download de resultados | |
| * `/api/v1/health` - Health check | |
| ## Debug e Testes | |
| * `/api/v1/debug/*` - Informações de sistema | |
| * `/api/v1/test/llm/*` - Testar LLMs | |
| * `/api/v1/test/processors/*` - Testar processadores | |
| * `/api/v1/test/database/*` - Testar banco de dados | |
| * `/api/v1/test/files/*` - Testar gestão de arquivos | |
| """, | |
| docs_url="/api/docs", | |
| redoc_url="/api/redoc", | |
| openapi_url="/api/openapi.json", | |
| lifespan=lifespan, | |
| swagger_ui_parameters={"defaultModelsExpandDepth": -1} | |
| ) | |
| # ============================================================================ | |
| # MIDDLEWARES | |
| # ============================================================================ | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=settings.CORS_ORIGINS, | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| app.add_middleware(GZipMiddleware, minimum_size=1000) | |
| async def log_requests(request: Request, call_next): | |
| """Middleware para logging de todas as requisições.""" | |
| start_time = time.time() | |
| # Log request | |
| api_logger.info(f"➡️ {request.method} {request.url.path}") | |
| # Process | |
| response = await call_next(request) | |
| # Log response | |
| process_time = (time.time() - start_time) * 1000 | |
| api_logger.info( | |
| f"⬅️ {request.method} {request.url.path} - " | |
| f"Status: {response.status_code} - " | |
| f"Time: {process_time:.2f}ms" | |
| ) | |
| # Add headers | |
| response.headers["X-Process-Time"] = f"{process_time:.2f}" | |
| response.headers["X-API-Version"] = settings.APP_VERSION | |
| return response | |
| async def add_security_headers(request: Request, call_next): | |
| """Middleware para adicionar headers de segurança.""" | |
| response = await call_next(request) | |
| response.headers["X-Content-Type-Options"] = "nosniff" | |
| response.headers["X-Frame-Options"] = "DENY" | |
| response.headers["X-XSS-Protection"] = "1; mode=block" | |
| return response | |
| # ============================================================================ | |
| # EXCEPTION HANDLERS | |
| # ============================================================================ | |
| async def para_ai_exception_handler(request: Request, exc: ParaAIException): | |
| """Handler para exceções customizadas do para.AI.""" | |
| api_logger.error(f"ParaAIException: {exc.message} - Details: {exc.details}") | |
| return JSONResponse( | |
| status_code=500, | |
| content={ | |
| "error": exc.message, | |
| "details": exc.details, | |
| "type": exc.__class__.__name__, | |
| "timestamp": datetime.now().isoformat() | |
| } | |
| ) | |
| async def global_exception_handler(request: Request, exc: Exception): | |
| """Handler global para exceções não tratadas.""" | |
| api_logger.error(f"Unhandled exception: {str(exc)}", exc_info=True) | |
| return JSONResponse( | |
| status_code=500, | |
| content={ | |
| "error": "Internal server error", | |
| "detail": str(exc) if settings.DEBUG else "An unexpected error occurred", | |
| "timestamp": datetime.now().isoformat() | |
| } | |
| ) | |
| # ============================================================================ | |
| # ROUTERS | |
| # ============================================================================ | |
| # Import routers (fazemos lazy import para evitar dependências circulares) | |
| from api.routers import health, processing, debug, llm, database, files, processors | |
| app.include_router(health.router, prefix="/api/v1", tags=["🏥 Health"]) | |
| app.include_router(processing.router, prefix="/api/v1", tags=["🚀 Processing"]) | |
| app.include_router(debug.router, prefix="/api/v1/debug", tags=["🐛 Debug"]) | |
| app.include_router(llm.router, prefix="/api/v1/test/llm", tags=["🤖 LLM Testing"]) | |
| app.include_router(database.router, prefix="/api/v1/test/database", tags=["🗄️ Database Testing"]) | |
| app.include_router(files.router, prefix="/api/v1/test/files", tags=["📁 Files Testing"]) | |
| app.include_router(processors.router, prefix="/api/v1/test/processors", tags=["⚙️ Processors Testing"]) | |
| # ============================================================================ | |
| # ROOT ENDPOINTS | |
| # ============================================================================ | |
| async def root(): | |
| """Root endpoint - informações básicas da API.""" | |
| uptime = (datetime.now() - app_start_time).total_seconds() | |
| return { | |
| "name": settings.APP_NAME, | |
| "version": settings.APP_VERSION, | |
| "environment": settings.APP_ENV, | |
| "status": "online", | |
| "uptime_seconds": uptime, | |
| "docs": "/api/docs", | |
| "health": "/api/v1/health", | |
| "timestamp": datetime.now().isoformat() | |
| } | |
| async def api_root(): | |
| """API root - redireciona para docs.""" | |
| return { | |
| "message": "para.AI API v3.0 - Acesse /api/docs para documentação completa", | |
| "docs": "/api/docs", | |
| "endpoints": { | |
| "health": "/api/v1/health", | |
| "upload": "/api/v1/process/upload", | |
| "debug": "/api/v1/debug/info" | |
| } | |
| } | |
| # ============================================================================ | |
| # MAIN (para execução direta) | |
| # ============================================================================ | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run( | |
| "api.main:app", | |
| host=settings.HOST, | |
| port=settings.PORT, | |
| reload=settings.DEBUG, | |
| workers=1 if settings.DEBUG else settings.WORKERS, | |
| log_level=settings.LOG_LEVEL.lower(), | |
| access_log=True | |
| ) |