File size: 6,769 Bytes
e2a60cf
d19c70e
 
e2a60cf
d19c70e
e2a60cf
 
ae2014a
e78ccf9
d19c70e
77f0bb6
e2a60cf
 
 
124d299
ae2014a
e78ccf9
d19c70e
 
 
e78ccf9
d19c70e
e78ccf9
 
 
d19c70e
 
e78ccf9
 
 
 
d19c70e
 
e78ccf9
e2a60cf
 
d19c70e
 
 
 
 
 
 
 
 
e78ccf9
d19c70e
e78ccf9
 
d19c70e
 
 
 
 
 
 
 
e78ccf9
d19c70e
 
e78ccf9
d19c70e
e78ccf9
d19c70e
e2a60cf
e78ccf9
d19c70e
e78ccf9
 
d19c70e
e78ccf9
d19c70e
e78ccf9
d19c70e
e78ccf9
d19c70e
e78ccf9
d19c70e
e78ccf9
 
 
 
 
 
 
d19c70e
e78ccf9
d19c70e
 
e78ccf9
d19c70e
e78ccf9
 
 
d19c70e
 
e78ccf9
e2a60cf
d19c70e
e2a60cf
d19c70e
e2a60cf
d19c70e
 
e78ccf9
 
d19c70e
 
e78ccf9
 
d19c70e
 
e78ccf9
d19c70e
 
 
 
e78ccf9
d19c70e
e78ccf9
d19c70e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e78ccf9
 
d19c70e
 
e78ccf9
 
 
d19c70e
e78ccf9
 
d19c70e
 
 
e78ccf9
 
 
e2a60cf
d19c70e
 
e2a60cf
d19c70e
 
 
 
 
 
 
e78ccf9
d19c70e
 
 
 
 
 
ae2014a
e2a60cf
 
d19c70e
 
 
 
e78ccf9
 
d19c70e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
"""
ProcessingService - Usa ProcessorManager REAL
Integração correta com os 9 especialistas existentes
"""
import os
import logging
from typing import Dict, Any, List, Optional
from datetime import datetime

from llm.llm_manager import LLMManager, LLMProvider
from processors.processor_manager import ProcessorManager

logger = logging.getLogger(__name__)


class ProcessingService:
    """
    Serviço que coordena processamento via ProcessorManager REAL.
    
    NÃO cria processors novos - usa os 9 especialistas existentes!
    """
    
    def __init__(
        self,
        llm_provider: str = "groq",
        api_key: Optional[str] = None,
        max_workers: int = 3
    ):
        """
        Args:
            llm_provider: Provider LLM (groq, openai, anthropic)
            api_key: API key (opcional, usa env var se não fornecido)
            max_workers: Workers paralelos
        """
        self.llm_provider = llm_provider
        self.api_key = api_key
        self.max_workers = max_workers
        
        # Configurar API key no ambiente se fornecida
        if self.api_key:
            env_key = f"{llm_provider.upper()}_API_KEY"
            os.environ[env_key] = self.api_key
            logger.info(f"✅ API key configurada para {env_key}")
        
        # Criar LLMManager (inicializa clients via env vars)
        self.llm_manager = self._create_llm_manager()
        
        # Obter client específico do provider
        self.llm_client = self._get_provider_client()
        
        # Criar ProcessorManager com LLM client
        # ProcessorManager já inicializa os 9 especialistas!
        self.processor_manager = ProcessorManager(
            llm_model=self.llm_client,
            max_workers=max_workers
        )
        
        logger.info(
            f"✅ ProcessingService inicializado "
            f"(provider={llm_provider}, 9 especialistas prontos)"
        )
    
    def _create_llm_manager(self) -> Optional[LLMManager]:
        """Cria LLMManager."""
        try:
            manager = LLMManager()
            logger.info("✅ LLMManager inicializado")
            return manager
        except Exception as e:
            logger.error(f"❌ Erro ao criar LLMManager: {e}", exc_info=True)
            return None
    
    def _get_provider_client(self):
        """Obtém client do provider selecionado."""
        if not self.llm_manager:
            logger.warning("⚠️ LLMManager não disponível")
            return None
        
        try:
            # Mapear string para enum
            provider_map = {
                "groq": LLMProvider.GROQ,
                "openai": LLMProvider.OPENAI,
                "anthropic": LLMProvider.ANTHROPIC
            }
            
            provider_enum = provider_map.get(self.llm_provider.lower())
            
            if provider_enum and provider_enum in self.llm_manager.clients:
                client = self.llm_manager.clients[provider_enum]
                logger.info(f"✅ Client obtido: {type(client).__name__}")
                return client
            else:
                logger.warning(
                    f"⚠️ Client {self.llm_provider} não disponível. "
                    "Verifique API key no ambiente."
                )
                return None
                
        except Exception as e:
            logger.error(f"❌ Erro ao obter client: {e}", exc_info=True)
            return None
    
    async def process_acordao(
        self,
        acordao_data: Dict[str, Any],
        specialist_ids: Optional[List[int]] = None,
        enable_parallel: bool = False
    ) -> Dict[str, Any]:
        """
        Processa 1 acórdão usando ProcessorManager.
        
        Args:
            acordao_data: Dados do acórdão
            specialist_ids: IDs dos especialistas (default: todos)
            enable_parallel: Executar em paralelo
        
        Returns:
            Resultado consolidado dos 9 especialistas
        """
        try:
            logger.info(
                f"🚀 Processando acórdão {acordao_data.get('acordao_id', 'unknown')} "
                f"com ProcessorManager"
            )
            
            # Usar ProcessorManager REAL para processar
            if enable_parallel:
                result = await self.processor_manager.process_acordao_parallel(
                    acordao_data=acordao_data,
                    specialist_ids=specialist_ids
                )
            else:
                result = await self.processor_manager.process_acordao_sequential(
                    acordao_data=acordao_data,
                    specialist_ids=specialist_ids
                )
            
            logger.info(
                f"✅ Acórdão processado em {result.get('execution_time', 0):.2f}s"
            )
            
            return result
            
        except Exception as e:
            logger.error(f"❌ Erro ao processar acórdão: {e}", exc_info=True)
            return {
                "acordao_id": acordao_data.get("acordao_id", "unknown"),
                "status": "error",
                "error": str(e),
                "timestamp": datetime.now().isoformat()
            }
    
    async def process_batch(
        self,
        acordaos: List[Dict[str, Any]],
        specialist_ids: Optional[List[int]] = None,
        enable_parallel: bool = False
    ) -> Dict[str, Any]:
        """
        Processa lote de acórdãos.
        
        Args:
            acordaos: Lista de acórdãos
            specialist_ids: IDs dos especialistas
            enable_parallel: Processar cada acórdão em paralelo
        
        Returns:
            Resultados consolidados
        """
        results = []
        start_time = datetime.now()
        
        for idx, acordao in enumerate(acordaos, 1):
            logger.info(f"📄 Processando acórdão {idx}/{len(acordaos)}...")
            
            result = await self.process_acordao(
                acordao_data=acordao,
                specialist_ids=specialist_ids,
                enable_parallel=enable_parallel
            )
            results.append(result)
        
        elapsed = (datetime.now() - start_time).total_seconds()
        
        successful = len([r for r in results if r.get("status") != "error"])
        failed = len(results) - successful
        
        return {
            "batch_size": len(acordaos),
            "processed": len(results),
            "successful": successful,
            "failed": failed,
            "total_execution_time": elapsed,
            "avg_time_per_acordao": elapsed / len(acordaos) if acordaos else 0,
            "results": results,
            "timestamp": datetime.now().isoformat()
        }