caarleexx commited on
Commit
53fdb6d
·
verified ·
1 Parent(s): ea6f8e9

Upload 3 files

Browse files
Files changed (3) hide show
  1. api/routers/database.py +143 -0
  2. api/routers/files.py +170 -0
  3. api/routers/llm.py +141 -0
api/routers/database.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Router de testes de database
3
+ Endpoints para verificar conexão e estatísticas do banco
4
+ """
5
+ from fastapi import APIRouter, HTTPException
6
+ from api.models.responses import DatabaseStatsResponse, MessageResponse
7
+ from api.utils.logger import setup_logger
8
+
9
+ router = APIRouter()
10
+ logger = setup_logger(__name__)
11
+
12
+
13
+ @router.get("/health")
14
+ async def database_health():
15
+ """
16
+ **Verifica saúde da conexão com banco de dados.**
17
+
18
+ Retorna status da conexão e informações básicas.
19
+ """
20
+ try:
21
+ from database.db_manager import get_db_manager
22
+
23
+ db = get_db_manager()
24
+ is_healthy = db.health_check()
25
+
26
+ if is_healthy:
27
+ return {
28
+ "status": "healthy",
29
+ "message": "Database connection OK",
30
+ "database_url": db.get_connection_info()
31
+ }
32
+ else:
33
+ return {
34
+ "status": "unhealthy",
35
+ "message": "Database connection failed"
36
+ }
37
+
38
+ except Exception as e:
39
+ logger.error(f"Database health check error: {e}")
40
+ return {
41
+ "status": "error",
42
+ "message": str(e)
43
+ }
44
+
45
+
46
+ @router.get("/stats", response_model=DatabaseStatsResponse)
47
+ async def database_stats():
48
+ """
49
+ **Estatísticas do banco de dados.**
50
+
51
+ Retorna contagem de registros nas principais tabelas.
52
+ """
53
+ try:
54
+ from database.db_manager import get_db_manager
55
+
56
+ db = get_db_manager()
57
+
58
+ stats = {
59
+ "total_acordaos": db.count_records("acordaos"),
60
+ "total_tribunais": db.count_records("tribunais"),
61
+ "total_usuarios": db.count_records("usuarios"),
62
+ "total_decisoes": db.count_records("decisoes"),
63
+ }
64
+
65
+ # Tentar pegar tamanho do banco
66
+ try:
67
+ size_mb = db.get_database_size_mb()
68
+ stats["database_size_mb"] = size_mb
69
+ except:
70
+ stats["database_size_mb"] = None
71
+
72
+ return DatabaseStatsResponse(**stats)
73
+
74
+ except Exception as e:
75
+ logger.error(f"Error getting database stats: {e}")
76
+ raise HTTPException(status_code=500, detail=str(e))
77
+
78
+
79
+ @router.get("/tables")
80
+ async def list_tables():
81
+ """
82
+ **Lista todas as tabelas do banco.**
83
+
84
+ Útil para verificar se DDL foi executado corretamente.
85
+ """
86
+ try:
87
+ from database.db_manager import get_db_manager
88
+
89
+ db = get_db_manager()
90
+ tables = db.list_tables()
91
+
92
+ return {
93
+ "tables": tables,
94
+ "total": len(tables)
95
+ }
96
+
97
+ except Exception as e:
98
+ logger.error(f"Error listing tables: {e}")
99
+ raise HTTPException(status_code=500, detail=str(e))
100
+
101
+
102
+ @router.post("/test-insert")
103
+ async def test_insert():
104
+ """
105
+ **Testa inserção no banco de dados.**
106
+
107
+ Insere um registro de teste e depois remove.
108
+ Útil para verificar permissões de escrita.
109
+ """
110
+ try:
111
+ from database.db_manager import get_db_manager
112
+ import uuid
113
+
114
+ db = get_db_manager()
115
+
116
+ # Tentar inserir um tribunal de teste
117
+ test_id = str(uuid.uuid4())
118
+
119
+ success = db.execute_query(
120
+ """
121
+ INSERT INTO tribunais (id, nome, sigla, uf, tipo, created_at, updated_at)
122
+ VALUES (%s, %s, %s, %s, %s, NOW(), NOW())
123
+ """,
124
+ (test_id, "Tribunal Teste", "TEST", "DF", "Teste")
125
+ )
126
+
127
+ if success:
128
+ # Remover registro de teste
129
+ db.execute_query(
130
+ "DELETE FROM tribunais WHERE id = %s",
131
+ (test_id,)
132
+ )
133
+
134
+ return MessageResponse(
135
+ message="Test insert/delete successful",
136
+ details={"test_id": test_id}
137
+ )
138
+ else:
139
+ raise Exception("Insert failed")
140
+
141
+ except Exception as e:
142
+ logger.error(f"Test insert error: {e}")
143
+ raise HTTPException(status_code=500, detail=str(e))
api/routers/files.py ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Router de testes de gestão de arquivos
3
+ Endpoints para testar criação, listagem e download de arquivos
4
+ """
5
+ from fastapi import APIRouter, HTTPException
6
+ from typing import List
7
+ from pathlib import Path
8
+
9
+ from api.models.requests import FileCreateRequest
10
+ from api.models.responses import FileInfoResponse, MessageResponse
11
+ from api.utils.logger import setup_logger
12
+
13
+ router = APIRouter()
14
+ logger = setup_logger(__name__)
15
+
16
+
17
+ @router.post("/create", response_model=MessageResponse)
18
+ async def create_test_file(request: FileCreateRequest):
19
+ """
20
+ **Cria arquivo de teste.**
21
+
22
+ Útil para testar sistema de arquivos e permissões.
23
+ """
24
+ try:
25
+ from files.files_manager import FilesManager
26
+
27
+ fm = FilesManager()
28
+
29
+ # Criar arquivo
30
+ filepath = fm.save_text_file(
31
+ content=request.content,
32
+ filename=request.filename,
33
+ acordao_id=request.acordao_id
34
+ )
35
+
36
+ logger.info(f"✅ Test file created: {filepath}")
37
+
38
+ return MessageResponse(
39
+ message="File created successfully",
40
+ details={
41
+ "filepath": str(filepath),
42
+ "filename": request.filename,
43
+ "size": len(request.content)
44
+ }
45
+ )
46
+
47
+ except Exception as e:
48
+ logger.error(f"Error creating file: {e}")
49
+ raise HTTPException(status_code=500, detail=str(e))
50
+
51
+
52
+ @router.get("/list", response_model=List[FileInfoResponse])
53
+ async def list_files(acordao_id: str = None, limit: int = 100):
54
+ """
55
+ **Lista arquivos.**
56
+
57
+ Args:
58
+ acordao_id: Filtrar por ID de acórdão (opcional)
59
+ limit: Limite de resultados
60
+ """
61
+ try:
62
+ from files.files_manager import FilesManager
63
+
64
+ fm = FilesManager()
65
+
66
+ files = fm.list_files(
67
+ acordao_id=acordao_id,
68
+ limit=limit
69
+ )
70
+
71
+ return [
72
+ FileInfoResponse(
73
+ filename=f["filename"],
74
+ size_bytes=f["size_bytes"],
75
+ hash_sha256=f.get("hash", "unknown"),
76
+ created_at=f.get("created_at")
77
+ )
78
+ for f in files
79
+ ]
80
+
81
+ except Exception as e:
82
+ logger.error(f"Error listing files: {e}")
83
+ raise HTTPException(status_code=500, detail=str(e))
84
+
85
+
86
+ @router.get("/info/{filename}")
87
+ async def get_file_info(filename: str):
88
+ """
89
+ **Informações sobre um arquivo específico.**
90
+ """
91
+ try:
92
+ from files.files_manager import FilesManager
93
+
94
+ fm = FilesManager()
95
+
96
+ info = fm.get_file_info(filename)
97
+
98
+ if not info:
99
+ raise HTTPException(status_code=404, detail="File not found")
100
+
101
+ return info
102
+
103
+ except HTTPException:
104
+ raise
105
+ except Exception as e:
106
+ logger.error(f"Error getting file info: {e}")
107
+ raise HTTPException(status_code=500, detail=str(e))
108
+
109
+
110
+ @router.delete("/{filename}")
111
+ async def delete_file(filename: str):
112
+ """
113
+ **Deleta arquivo.**
114
+
115
+ Args:
116
+ filename: Nome do arquivo a deletar
117
+ """
118
+ try:
119
+ from files.files_manager import FilesManager
120
+
121
+ fm = FilesManager()
122
+
123
+ success = fm.delete_file(filename)
124
+
125
+ if success:
126
+ logger.info(f"🗑️ File deleted: {filename}")
127
+ return MessageResponse(
128
+ message="File deleted successfully",
129
+ details={"filename": filename}
130
+ )
131
+ else:
132
+ raise HTTPException(status_code=404, detail="File not found")
133
+
134
+ except HTTPException:
135
+ raise
136
+ except Exception as e:
137
+ logger.error(f"Error deleting file: {e}")
138
+ raise HTTPException(status_code=500, detail=str(e))
139
+
140
+
141
+ @router.get("/storage/info")
142
+ async def storage_info():
143
+ """
144
+ **Informações sobre armazenamento.**
145
+
146
+ Retorna uso de disco e estatísticas.
147
+ """
148
+ try:
149
+ from files.files_manager import FilesManager
150
+ import shutil
151
+
152
+ fm = FilesManager()
153
+
154
+ # Pegar info de disco
155
+ total, used, free = shutil.disk_usage(fm.base_path)
156
+
157
+ return {
158
+ "base_path": str(fm.base_path),
159
+ "storage": {
160
+ "total_gb": total / (1024**3),
161
+ "used_gb": used / (1024**3),
162
+ "free_gb": free / (1024**3),
163
+ "percent_used": (used / total) * 100
164
+ },
165
+ "total_files": len(list(Path(fm.base_path).rglob("*.*")))
166
+ }
167
+
168
+ except Exception as e:
169
+ logger.error(f"Error getting storage info: {e}")
170
+ raise HTTPException(status_code=500, detail=str(e))
api/routers/llm.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Router de testes de LLM
3
+ Endpoints para testar providers e modelos LLM
4
+ """
5
+ from fastapi import APIRouter, HTTPException
6
+ from datetime import datetime
7
+ import time
8
+
9
+ from api.models.requests import LLMGenerateRequest
10
+ from api.models.responses import LLMTestResponse, MessageResponse
11
+ from api.utils.logger import setup_logger
12
+
13
+ router = APIRouter()
14
+ logger = setup_logger(__name__)
15
+
16
+
17
+ @router.post("/generate", response_model=LLMTestResponse)
18
+ async def test_llm_generate(request: LLMGenerateRequest):
19
+ """
20
+ **Testa geração de texto com LLM.**
21
+
22
+ Útil para:
23
+ - Verificar se API keys estão funcionando
24
+ - Testar diferentes modelos
25
+ - Medir latência e tokens
26
+ """
27
+ start_time = time.time()
28
+
29
+ try:
30
+ # Importar LLM manager
31
+ from llm.llm_manager import LLMManager
32
+
33
+ llm = LLMManager()
34
+
35
+ # Verificar se provider está disponível
36
+ if not llm.is_provider_available(request.provider):
37
+ raise HTTPException(
38
+ status_code=503,
39
+ detail=f"Provider '{request.provider}' não disponível ou não configurado"
40
+ )
41
+
42
+ # Gerar texto
43
+ result = await llm.generate(
44
+ prompt=request.prompt,
45
+ provider=request.provider,
46
+ model=request.model,
47
+ temperature=request.temperature,
48
+ max_tokens=request.max_tokens
49
+ )
50
+
51
+ duration_ms = (time.time() - start_time) * 1000
52
+
53
+ logger.info(
54
+ f"✅ LLM test [{request.provider}] - "
55
+ f"Tokens: {result.get('tokens', 0)} - "
56
+ f"Duration: {duration_ms:.2f}ms"
57
+ )
58
+
59
+ return LLMTestResponse(
60
+ provider=request.provider,
61
+ model=result.get("model", request.model or "default"),
62
+ success=True,
63
+ response=result.get("text", ""),
64
+ tokens_used=result.get("tokens"),
65
+ duration_ms=duration_ms
66
+ )
67
+
68
+ except Exception as e:
69
+ duration_ms = (time.time() - start_time) * 1000
70
+
71
+ logger.error(f"❌ LLM test error: {str(e)}")
72
+
73
+ return LLMTestResponse(
74
+ provider=request.provider,
75
+ model=request.model or "unknown",
76
+ success=False,
77
+ duration_ms=duration_ms,
78
+ error=str(e)
79
+ )
80
+
81
+
82
+ @router.get("/providers")
83
+ async def list_providers():
84
+ """
85
+ **Lista providers LLM disponíveis.**
86
+
87
+ Mostra quais providers estão configurados e prontos para uso.
88
+ """
89
+ try:
90
+ from llm.llm_manager import LLMManager
91
+
92
+ llm = LLMManager()
93
+ providers = llm.list_providers()
94
+
95
+ return {
96
+ "providers": providers,
97
+ "total": len(providers),
98
+ "default": llm.default_provider
99
+ }
100
+
101
+ except Exception as e:
102
+ logger.error(f"Error listing providers: {e}")
103
+ return {
104
+ "providers": [],
105
+ "total": 0,
106
+ "error": str(e)
107
+ }
108
+
109
+
110
+ @router.get("/models/{provider}")
111
+ async def list_models(provider: str):
112
+ """
113
+ **Lista modelos disponíveis de um provider.**
114
+
115
+ Args:
116
+ provider: Nome do provider (groq/openai/anthropic)
117
+ """
118
+ try:
119
+ from llm.llm_manager import LLMManager
120
+
121
+ llm = LLMManager()
122
+
123
+ if not llm.is_provider_available(provider):
124
+ raise HTTPException(
125
+ status_code=404,
126
+ detail=f"Provider '{provider}' não disponível"
127
+ )
128
+
129
+ models = llm.get_available_models(provider)
130
+
131
+ return {
132
+ "provider": provider,
133
+ "models": models,
134
+ "total": len(models)
135
+ }
136
+
137
+ except HTTPException:
138
+ raise
139
+ except Exception as e:
140
+ logger.error(f"Error listing models: {e}")
141
+ raise HTTPException(status_code=500, detail=str(e))