File size: 15,628 Bytes
bbbdd24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
"""
═══════════════════════════════════════════════════════════════════════
PATCH ESPECÍFICO PARA api.py β€” APLICAR LINHA POR LINHA
═══════════════════════════════════════════════════════════════════════

Este arquivo mostra as MODIFICAÇÕES EXATAS no api.py existente.

Arquivo: i:\\Isaac Quarenta\\ProgramaΓ§Γ£o\\AKIRA-SOFTEDGE\\modules\\api.py

MODIFICATIONS:
1. Adicionar imports (top do arquivo)
2. Modificar _get_user_context() (line 2311)

3. Modificar _get_history_for_llm() (line 2320+)

4. Modificar akira_endpoint() - parte de obtΓ©m histΓ³rico

═══════════════════════════════════════════════════════════════════════
"""

# ═══════════════════════════════════════════════════════════════════════
# MODIFICATION 1: ADICIONAR IMPORTS (TOP DO ARQUIVO)
# ═══════════════════════════════════════════════════════════════════════

"""
LocalizaΓ§Γ£o: PrΓ³ximo aos outros imports do modules/

ANTES:
────────────────────────────────────────────────────────────────
import json
import hashlib
import logging
from skills_registry import SkillsRegistry

...



DEPOIS (ADICIONAR ESTAS LINHAS):

────────────────────────────────────────────────────────────────

import json

import hashlib

import logging

from skills_registry import SkillsRegistry

# βœ… NOVOS IMPORTS PARA CONTEXT V2
from modules.context_manager_v2 import (
    ContextManagerV2,

    get_context_manager,

    MessageType,

    ContextType

)

from modules.listen_stream_processor import (

    ListenStreamProcessor,

    get_listen_processor

)


# Inicializa singletons
ctx_manager = get_context_manager()

listen_processor = get_listen_processor()
...
"""

# ═══════════════════════════════════════════════════════════════════════
# MODIFICATION 2: ATUALIZAR _get_user_context (line 2311)

# ═══════════════════════════════════════════════════════════════════════



"""

LocalizaΓ§Γ£o: api.py::_get_user_context (line 2311)

ANTES:
────────────────────────────────────────────────────────────────
    def _get_user_context(self, usuario, conversation_id=None):

        # πŸ”§ FIX: Usa conversation_id como chave primΓ‘ria para isolamento total

        cache_key = conversation_id if conversation_id else usuario

        if cache_key not in self.contexto_cache:

            db_path = getattr(self.config, 'DB_PATH', 'akira.db')

            db = Database(db_path)

            # Passa conversation_id para o objeto Contexto para persistΓͺncia isolada

            self.contexto_cache[cache_key] = Contexto(db, usuario=usuario, conversation_id=conversation_id)

        return self.contexto_cache[cache_key]


DEPOIS:
────────────────────────────────────────────────────────────────
    def _get_user_context(self, usuario, numero, conversation_id=None, 

                          tipo_conversa='pv', grupo_id=None):

        # πŸ”§ FIX V2: Usa novo ContextManagerV2 para isolamento robusto

        

        # Legacy: mantΓ©m cache para compatibilidade

        cache_key = conversation_id if conversation_id else usuario

        if cache_key not in self.contexto_cache:

            db_path = getattr(self.config, 'DB_PATH', 'akira.db')

            db = Database(db_path)

            self.contexto_cache[cache_key] = Contexto(db, usuario=usuario, conversation_id=conversation_id)

        

        # NOVO: Retorna contexto isolado via ContextManagerV2

        contexto_isolado = ctx_manager.obter_ou_criar_contexto(

            numero=numero,

            tipo_conversa=tipo_conversa,

            grupo_id=grupo_id,

            usuario=usuario

        )

        

        # Retorna ambos para compatibilidade backward

        return {

            'legacy_contexto': self.contexto_cache[cache_key],  # Compatibilidade

            'novo_contexto_manager': contexto_isolado,

            'numero': numero,

            'tipo_conversa': tipo_conversa,

            'grupo_id': grupo_id,

        }


NOTA: A assinatura da funΓ§Γ£o MUDA. Precisa ser atualizada
      em TODOS os lugares que chamam _get_user_context()

"""


# ═══════════════════════════════════════════════════════════════════════
# MODIFICATION 3: INTEGRAR LISTEN STREAM EM akira_endpoint

# ═══════════════════════════════════════════════════════════════════════



"""

LocalizaΓ§Γ£o: api.py::akira_endpoint() - apΓ³s extrair dados (line ~1250)

ANTES (buggy):
────────────────────────────────────────────────────────────────
                usuario = validate_sender_name(usuario, numero, "usuario_principal")

                ...

                # Captura contexto aqui (BUGGY - sem isolaΓ§Γ£o)

                contexto = self._get_user_context(usuario)

                

                # HistΓ³rico SEM FILTRO (PROBLEMA!)

                historico = contexto.obter_historico()

                

                # Process LLM...


DEPOIS (robusto):
────────────────────────────────────────────────────────────────
                usuario = validate_sender_name(usuario, numero, "usuario_principal")

                ...

                

                # βœ… NOVO: PROCESSA VIA LISTEN STREAM

                evento = {

                    'usuario': usuario,

                    'numero': numero,

                    'texto': mensagem,

                    'tipo_conversa': tipo_conversa,

                    'grupo_id': grupo_id,

                    'referenced_message_author': quoted_author_name,

                    'referenced_message_texto': mensagem_citada,

                    'referenced_message_id': data.get('message_id_citada', ''),

                }

                

                resultado_processamento = listen_processor.processar_mensagem_chegando(evento)

                

                self.logger.info(

                    f"πŸ” ClassificaΓ§Γ£o Listen: {resultado_processamento['tipo_message']} | "

                    f"Deve processar: {resultado_processamento['deve_processar']}"

                )

                

                # βœ… SE NΓƒO FOR DIRETO, NΓƒO PROCESSA

                if not resultado_processamento['deve_processar']:

                    self.logger.info(f"πŸ“š Mensagem contextual (escuta). NΓ£o respondendo.")

                    return jsonify({

                        'resposta': '',

                        'status': 'context_registered',

                        'tipo': 'contextual',

                        'modelo_usado': 'listen_stream',

                        'conversation_id': resultado_processamento['conversation_id']

                    })

                

                # βœ… Γ‰ DIRETO: ObtΓ©m contexto ISOLADO

                conversation_id = resultado_processamento['conversation_id']

                contexto_data = listen_processor.obter_contexto_para_resposta(

                    numero=numero,

                    tipo_conversa=tipo_conversa,

                    grupo_id=grupo_id,

                    include_contextual=True

                )

                

                # Extrai histΓ³rico ISOLADO

                historico = contexto_data['direct_messages']

                

                # Context enriquecido com fluxo do grupo

                contexto_grupo_info = contexto_data.get('grupo_flow', {})

                participants = contexto_data.get('participants', [])

                

                # Se em grupo, inclui info de participantes

                if tipo_conversa == "grupo":

                    self.logger.info(f"πŸ‘₯ Contexto grupo: {len(participants)} participantes")

                

                # LEGACY: obtΓ©m tambΓ©m via contexto_cache para compatibilidade

                contexto = self._get_user_context(

                    usuario=usuario,

                    numero=numero,

                    conversation_id=conversation_id,

                    tipo_conversa=tipo_conversa,

                    grupo_id=grupo_id

                )

                

                # Process LLM...

"""


# ═══════════════════════════════════════════════════════════════════════
# MODIFICATION 4: ACEITAR NOVOS CAMPOS NO PAYLOAD
# ═══════════════════════════════════════════════════════════════════════

"""
LocalizaΓ§Γ£o: api.py::akira_endpoint() - seΓ§Γ£o data extraction (line ~1240)



ANTES:

────────────────────────────────────────────────────────────────

                usuario = data.get('usuario', 'anonimo')

                numero = data.get('numero', '')

                mensagem = data.get('mensagem', '')

                message_id = data.get('message_id', '')

                tipo_conversa = data.get('tipo_conversa', 'pv')

                grupo_id = data.get('grupo_id') or data.get('contexto_grupo') or ''
                

                imagem_dados = data.get('imagem', {})

                ...


DEPOIS (adiciona suporte):
────────────────────────────────────────────────────────────────
                usuario = data.get('usuario', 'anonimo')

                numero = data.get('numero', '')

                mensagem = data.get('mensagem', '')

                message_id = data.get('message_id', '')

                tipo_conversa = data.get('tipo_conversa', 'pv')

                grupo_id = data.get('grupo_id') or data.get('contexto_grupo') or ''

                

                # βœ… NOVOS CAMPOS PARA LISTEN STREAM

                # ReferΓͺncia a outra mensagem (reply)

                referenced_message_author = data.get('referenced_message_author', 

                                                    data.get('quoted_author_name', ''))

                referenced_message_texto = data.get('referenced_message_texto',

                                                   data.get('mensagem_citada', ''))

                referenced_message_id = data.get('referenced_message_id',

                                                data.get('message_id_citada', ''))

                

                imagem_dados = data.get('imagem', {})

                ...

"""


# ═══════════════════════════════════════════════════════════════════════
# MODIFICATION 5: ATUALIZAR PAYLOAD DO RESPOSTA
# ═══════════════════════════════════════════════════════════════════════

"""
LocalizaΓ§Γ£o: api.py::akira_endpoint() - retorno jsonify (line ~1400+)



ADICIONAR CAMPO:

────────────────────────────────────────────────────────────────

                return jsonify({

                    'resposta': resposta,

                    'modelo_usado': modelo,
                    'confidence': confidence,

                    'conversation_id': conversation_id,  # βœ… NOVO

                    'tipo_message': resultado_processamento['tipo_message'],  # βœ… NOVO

                    'participants': participants if tipo_conversa == 'grupo' else [],  # βœ… NOVO

                    ...

                })

"""


# ═══════════════════════════════════════════════════════════════════════
# QUICK CHECKLIST
# ═══════════════════════════════════════════════════════════════════════

"""
ANTES DE APLICAR ESTAS MUDANÇAS:

β–‘ Verificar que context_manager_v2.py existe e estΓ‘ correto
β–‘ Verificar que listen_stream_processor.py existe e estΓ‘ correto
β–‘ Fazer BACKUP do api.py ANTES DE MODIFICAR
β–‘ Testar com um grupo de teste (nΓ£o produΓ§Γ£o)

APΓ“S APLICAR:

β–‘ Testar endpoint POST /akira com payload novo
β–‘ Testar com tipo_conversa='pv' (deve ser DIRECT)

β–‘ Testar com tipo_conversa='grupo' sem @AKIRA (deve ser CONTEXTUAL)
β–‘ Testar com tipo_conversa='grupo' com @AKIRA (deve ser DIRECT)

β–‘ Verificar logs para "πŸ” ClassificaΓ§Γ£o Listen"

β–‘ Verificar que histΓ³rico Γ© isolado por conversation_id
β–‘ Monitorar para memory leaks no context_manager (stats)



TROUBLESHOOTING:



❌ ImportError: context_manager_v2

   β†’ Verificar que arquivo estΓ‘ em modules/

   β†’ Verificar import path



❌ NameError: ctx_manager not defined
   β†’ Verificar que get_context_manager() foi chamado no top
   β†’ Verificar que imports foram adicionados

❌ Contexto ainda estÑ misturado
   β†’ Verificar que listen_processor.processar_mensagem_chegando() foi integrado

   β†’ Verificar que resultado_processamento['deve_processar'] Γ© respeitado

   β†’ Verificar conversation_id estΓ‘ sendo passado corretamente
"""

__all__ = [
    'PATCH_INSTRUCTIONS'

]