caarleexx commited on
Commit
320f736
·
verified ·
1 Parent(s): 738bba6

Update api/main.py

Browse files
Files changed (1) hide show
  1. api/main.py +253 -85
api/main.py CHANGED
@@ -1,107 +1,275 @@
 
1
  """
2
- FastAPI Application Factory
3
- Main entry point for para.AI API
4
  """
5
- from fastapi import FastAPI, Request
6
- from fastapi.middleware.cors import CORSMiddleware
7
- from fastapi.responses import JSONResponse
8
- from contextlib import asynccontextmanager
9
  import logging
10
- import time
11
  from datetime import datetime
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
- from api.config import settings
14
- from api.routes import debug_routes, process_routes, status_routes, health_routes
15
 
 
 
 
16
 
17
  logging.basicConfig(
18
- level=settings.LOG_LEVEL,
19
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
 
20
  )
21
  logger = logging.getLogger(__name__)
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
- @asynccontextmanager
25
- async def lifespan(app: FastAPI):
26
- """Lifespan events"""
27
- logger.info(f"🚀 Starting {settings.APP_NAME} v{settings.APP_VERSION}")
28
- logger.info(f"📊 Environment: {'DEBUG' if settings.DEBUG else 'PRODUCTION'}")
29
- logger.info(f"🤖 LLM Model: {settings.LLM_MODEL}")
30
-
31
- yield
32
-
33
- logger.info("🛑 Shutting down API")
34
-
35
-
36
- def create_app() -> FastAPI:
37
- """Factory function to create FastAPI app"""
38
-
39
- app = FastAPI(
40
- title=settings.APP_NAME,
41
- version=settings.APP_VERSION,
42
- description="API para análise jurisprudencial com LLMs - Sistema de 9 Especialistas",
43
- lifespan=lifespan,
44
- docs_url="/docs" if settings.DEBUG else None,
45
- redoc_url="/redoc" if settings.DEBUG else None,
46
- )
47
-
48
- app.add_middleware(
49
- CORSMiddleware,
50
- allow_origins=settings.CORS_ORIGINS,
51
- allow_credentials=True,
52
- allow_methods=["*"],
53
- allow_headers=["*"],
54
- )
55
-
56
- @app.middleware("http")
57
- async def add_process_time_header(request: Request, call_next):
58
- start_time = time.time()
59
- response = await call_next(request)
60
- process_time = time.time() - start_time
61
- response.headers["X-Process-Time"] = str(process_time)
62
- return response
63
-
64
- @app.exception_handler(Exception)
65
- async def global_exception_handler(request: Request, exc: Exception):
66
- logger.error(f"Global exception: {exc}", exc_info=True)
67
- return JSONResponse(
68
- status_code=500,
69
- content={
70
- "error": "Internal Server Error",
71
- "detail": str(exc) if settings.DEBUG else "An error occurred",
72
- "timestamp": datetime.now().isoformat(),
73
- "path": str(request.url)
74
- }
75
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
- app.include_router(health_routes.router, prefix="/health", tags=["Health"])
78
- app.include_router(process_routes.router, prefix="/process", tags=["Process"])
79
- app.include_router(status_routes.router, prefix="/status", tags=["Status"])
80
-
81
- if settings.DEBUG:
82
- app.include_router(debug_routes.router, prefix="/debug", tags=["Debug"])
83
-
84
- @app.get("/")
85
- async def root():
86
- return {
87
- "app": settings.APP_NAME,
88
- "version": settings.APP_VERSION,
89
- "status": "running",
90
- "timestamp": datetime.now().isoformat(),
91
- "docs": "/docs" if settings.DEBUG else "disabled"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  }
 
 
93
 
94
- return app
 
 
95
 
 
 
 
 
 
 
 
 
 
96
 
97
- app = create_app()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
 
 
 
99
 
100
  if __name__ == "__main__":
101
- import uvicorn
 
 
 
 
 
102
  uvicorn.run(
103
- "api.main:app",
104
- host=settings.API_HOST,
105
- port=settings.API_PORT,
106
- reload=settings.DEBUG
107
- )
 
 
1
+ #!/usr/bin/env python3
2
  """
3
+ ParaAi - FastAPI Main Application v2.0
4
+ Inicializa aplicação FastAPI com integração de TODOS os módulos
5
  """
6
+
7
+ import os
 
 
8
  import logging
 
9
  from datetime import datetime
10
+ from pathlib import Path
11
+ from typing import Dict, List, Optional
12
+
13
+ from fastapi import FastAPI, HTTPException, BackgroundTasks
14
+ from fastapi.middleware.cors import CORSMiddleware
15
+ from fastapi.responses import JSONResponse, FileResponse
16
+ from pydantic import BaseModel
17
+ import uvicorn
18
+
19
+ # ============================================================================
20
+ # IMPORTS DO PROJETO (FASE 1 + FASE 2)
21
+ # ============================================================================
22
+
23
+ # FASE 1: APIs e Database
24
+ from api.llm_client import APILLMClient
25
+ from data.db.postgres_manager import PostgreSQLManager
26
+
27
+ # FASE 2: Context e Files
28
+ from data.context.context_engine import ContextEngine
29
+ from files_manager.files_manager import FilesManager
30
+
31
+ # FASE 2: Workers (refatorado)
32
+ from workers.llm_worker_hybrid import LLMWorkerHybrid
33
 
34
+ # API Routes (próximos arquivos)
35
+ from api.routes import debug_routes, process_routes, status_routes
36
 
37
+ # ============================================================================
38
+ # CONFIGURAÇÃO E LOGGING
39
+ # ============================================================================
40
 
41
  logging.basicConfig(
42
+ level=logging.INFO,
43
+ format='%(asctime)s [%(levelname)-5s] %(name)s - %(message)s',
44
+ datefmt='%Y-%m-%d %H:%M:%S'
45
  )
46
  logger = logging.getLogger(__name__)
47
 
48
+ # ============================================================================
49
+ # PYDANTIC MODELS (Request/Response)
50
+ # ============================================================================
51
+
52
+ class ProcessRequest(BaseModel):
53
+ """Request para processar um lote de acórdãos"""
54
+ jsonl_path: str
55
+ batch_id: Optional[str] = None
56
+ num_workers: int = 10
57
+ timeout_seconds: int = 300
58
+ enable_cache: bool = True
59
+
60
+ class ProcessResponse(BaseModel):
61
+ """Response do processamento"""
62
+ status: str # pending, processing, completed, failed
63
+ batch_id: str
64
+ total_records: int
65
+ processed_records: int
66
+ failed_records: int
67
+ output_path: Optional[str] = None
68
+ download_url: Optional[str] = None
69
+ timestamp: str
70
+
71
+ class StatusResponse(BaseModel):
72
+ """Response de status"""
73
+ batch_id: str
74
+ status: str
75
+ progress_percent: float
76
+ processed: int
77
+ total: int
78
+ timestamp: str
79
+
80
+ # ============================================================================
81
+ # INICIALIZAÇÃO DA APLICAÇÃO
82
+ # ============================================================================
83
+
84
+ app = FastAPI(
85
+ title="ParaAi - Sistema de Análise Jurídica com IA",
86
+ description="Pipeline multidisciplinar de processamento de acórdãos",
87
+ version="2.0.0"
88
+ )
89
+
90
+ # CORS
91
+ app.add_middleware(
92
+ CORSMiddleware,
93
+ allow_origins=["*"],
94
+ allow_credentials=True,
95
+ allow_methods=["*"],
96
+ allow_headers=["*"],
97
+ )
98
+
99
+ # ============================================================================
100
+ # COMPONENTES GLOBAIS (Inicializados uma vez)
101
+ # ============================================================================
102
+
103
+ # FASE 1
104
+ llm_client: APILLMClient = None
105
+ db_manager: PostgreSQLManager = None
106
+
107
+ # FASE 2
108
+ context_engine: ContextEngine = None
109
+ files_manager: FilesManager = None
110
+
111
+ # Workers
112
+ workers: List[LLMWorkerHybrid] = []
113
 
114
+ # ============================================================================
115
+ # STARTUP / SHUTDOWN
116
+ # ============================================================================
117
+
118
+ @app.on_event("startup")
119
+ async def startup_event():
120
+ """Inicializa todos os componentes"""
121
+ global llm_client, db_manager, context_engine, files_manager, workers
122
+
123
+ logger.info("=" * 80)
124
+ logger.info("🚀 ParaAi Starting Up...")
125
+ logger.info("=" * 80)
126
+
127
+ try:
128
+ # FASE 1: Inicializar APIs
129
+ logger.info("📡 Inicializando APILLMClient...")
130
+ llm_client = APILLMClient(
131
+ configpath=".apiLLMst2t/configllms.yaml"
132
+ )
133
+ logger.info("✅ APILLMClient inicializado")
134
+
135
+ # FASE 1: Inicializar Database
136
+ logger.info("🗄️ Inicializando PostgreSQL...")
137
+ db_manager = PostgreSQLManager(
138
+ dbname=os.getenv("PGDB", "paraai"),
139
+ user=os.getenv("PGUSER", "postgres"),
140
+ password=os.getenv("PGPASSWORD", ""),
141
+ host=os.getenv("PGHOST", "localhost"),
142
+ port=int(os.getenv("PGPORT", 5432))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  )
144
+
145
+ # Criar tabelas
146
+ if db_manager.criar_tabelas():
147
+ logger.info("✅ Banco de dados pronto")
148
+ else:
149
+ logger.warning("⚠️ Erro ao criar tabelas, continuando...")
150
+
151
+ # FASE 2: Inicializar Context Engine
152
+ logger.info("🔗 Inicializando ContextEngine...")
153
+ context_engine = ContextEngine()
154
+ logger.info("✅ ContextEngine inicializado")
155
+
156
+ # FASE 2: Inicializar Files Manager
157
+ logger.info("📦 Inicializando FilesManager...")
158
+ files_manager = FilesManager(
159
+ basedir=os.path.expanduser(os.getenv("WORKDIR", "../trabalho")),
160
+ ano="2024"
161
+ )
162
+ logger.info("✅ FilesManager inicializado")
163
+
164
+ # Inicializar workers
165
+ num_workers = int(os.getenv("NUMWORKERS", 10))
166
+ logger.info(f"👷 Criando {num_workers} workers...")
167
+ for i in range(num_workers):
168
+ worker = LLMWorkerHybrid(
169
+ worker_id=i,
170
+ configpath=".apiLLMst2t/configllms.yaml"
171
+ )
172
+ workers.append(worker)
173
+ logger.info(f"✅ {num_workers} workers criados")
174
+
175
+ logger.info("=" * 80)
176
+ logger.info("✅ ParaAi iniciada com sucesso!")
177
+ logger.info("=" * 80)
178
+
179
+ except Exception as e:
180
+ logger.error(f"❌ Erro na inicialização: {e}")
181
+ raise
182
+
183
+ @app.on_event("shutdown")
184
+ async def shutdown_event():
185
+ """Limpa recursos"""
186
+ logger.info("🛑 ParaAi Shutting Down...")
187
+ if db_manager:
188
+ db_manager.fechar()
189
+ logger.info("✅ Shutdown completo")
190
 
191
+ # ============================================================================
192
+ # ROTAS RAIZ
193
+ # ============================================================================
194
+
195
+ @app.get("/")
196
+ async def root():
197
+ """Rota raiz - informações da API"""
198
+ return {
199
+ "status": "running",
200
+ "name": "ParaAi",
201
+ "version": "2.0.0",
202
+ "endpoints": {
203
+ "health": "/health",
204
+ "process": "/process (POST)",
205
+ "status": "/status/{batch_id} (GET)",
206
+ "debug": "/debug/* (GET)",
207
+ "docs": "/docs"
208
+ }
209
+ }
210
+
211
+ @app.get("/health")
212
+ async def health_check():
213
+ """Health check de todos os componentes"""
214
+ health_status = {
215
+ "status": "healthy",
216
+ "timestamp": datetime.now().isoformat(),
217
+ "components": {
218
+ "llm_client": "OK" if llm_client else "FAIL",
219
+ "db_manager": "OK" if db_manager else "FAIL",
220
+ "context_engine": "OK" if context_engine else "FAIL",
221
+ "files_manager": "OK" if files_manager else "FAIL",
222
+ "workers": f"{len(workers)}/OK" if workers else "FAIL"
223
  }
224
+ }
225
+ return health_status
226
 
227
+ # ============================================================================
228
+ # INCLUIR ROUTERS
229
+ # ============================================================================
230
 
231
+ # Rotas de Debug
232
+ debug_router = debug_routes.create_debug_router(
233
+ llm_client=llm_client,
234
+ db_manager=db_manager,
235
+ context_engine=context_engine,
236
+ files_manager=files_manager,
237
+ workers=workers
238
+ )
239
+ app.include_router(debug_router, prefix="/debug", tags=["debug"])
240
 
241
+ # Rotas de Processamento
242
+ process_router = process_routes.create_process_router(
243
+ llm_client=llm_client,
244
+ db_manager=db_manager,
245
+ context_engine=context_engine,
246
+ files_manager=files_manager,
247
+ workers=workers
248
+ )
249
+ app.include_router(process_router, prefix="/process", tags=["processing"])
250
+
251
+ # Rotas de Status
252
+ status_router = status_routes.create_status_router(
253
+ context_engine=context_engine,
254
+ files_manager=files_manager
255
+ )
256
+ app.include_router(status_router, prefix="/status", tags=["status"])
257
 
258
+ # ============================================================================
259
+ # EXECUÇÃO
260
+ # ============================================================================
261
 
262
  if __name__ == "__main__":
263
+ host = os.getenv("FASTAPIHOST", "0.0.0.0")
264
+ port = int(os.getenv("FASTAPIPORT", 7860)
265
+ reload = os.getenv("FASTAPIreload", "true").lower() == "true"
266
+
267
+ logger.info(f"🌐 Iniciando servidor em http://{host}:{port}")
268
+
269
  uvicorn.run(
270
+ "main:app",
271
+ host=host,
272
+ port=port,
273
+ reload=reload,
274
+ log_level=os.getenv("LOGLEVEL", "debug").lower()
275
+ )