Spaces:
Running
Running
Isaac Quarenta commited on
Commit ·
5491f79
1
Parent(s): 0a5646b
fix(api): NameError explicit_mention_pattern em _build_context_isolation_layer
Browse files- api.py:7311 define _explicit_mention_local via re.search local em vez de free variable (causava NameError: cannot access free variable em _build_prompt:7326 ao processar reply grupo)
- api.py:7334 usa _explicit_mention_local no state_msg
- Corrige crash 15:02:08 akira tenho duvida... que retornava 200 mas sem resposta
- modules/api.py +11 -2
- modules/listen_engine.py +34 -9
modules/api.py
CHANGED
|
@@ -4241,6 +4241,14 @@ class AkiraAPI:
|
|
| 4241 |
"quoted_type": quoted_type,
|
| 4242 |
"context_hint": context_hint,
|
| 4243 |
"mensagem_citada": mensagem_citada,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4244 |
"replied_to_author": reply_metadata.get('replied_to_author_name', ''),
|
| 4245 |
"replied_to_content": reply_metadata.get('replied_to_text', '')
|
| 4246 |
})
|
|
@@ -7300,7 +7308,8 @@ class AkiraAPI:
|
|
| 7300 |
isolation_parts.append(reply_section)
|
| 7301 |
|
| 7302 |
# SECAO 2: LSTM CONTEXT (Peso 0.8) — REPLY LOCK: suprime quando reply_to_bot sem menção explícita (evita contaminação ISPETEC vs ditado)
|
| 7303 |
-
|
|
|
|
| 7304 |
if unified_context:
|
| 7305 |
if _lstm_locked:
|
| 7306 |
# Reply citado já tem peso 1.0 — não poluir com tópicos antigos do LSTM
|
|
@@ -7323,7 +7332,7 @@ class AkiraAPI:
|
|
| 7323 |
lstm_section += "\n--- Topicos por Participante ---"
|
| 7324 |
for speaker, msgs in speakers_topics.items():
|
| 7325 |
lstm_section += f"\n[{speaker}]: {' | '.join(msgs[:3])}"
|
| 7326 |
-
state_msg = f" - reply_to_bot={reply_to_bot}, explicit_mention={
|
| 7327 |
self.logger.info(f"✔... [LSTM INJETADO COM FOCO reply_to_bot={reply_to_bot}] topic={lstm_ctx.get('topic_principal')}{state_msg}")
|
| 7328 |
isolation_parts.append(lstm_section)
|
| 7329 |
|
|
|
|
| 4241 |
"quoted_type": quoted_type,
|
| 4242 |
"context_hint": context_hint,
|
| 4243 |
"mensagem_citada": mensagem_citada,
|
| 4244 |
+
# novos campos emissor / receptor
|
| 4245 |
+
"emissor_nome": reply_metadata.get('emissor_nome', ''),
|
| 4246 |
+
"emissor_numero": reply_metadata.get('emissor_numero', ''),
|
| 4247 |
+
"emissor_jid": reply_metadata.get('emissor_jid', ''),
|
| 4248 |
+
"receptor_nome": reply_metadata.get('receptor_nome', ''),
|
| 4249 |
+
"receptor_numero": reply_metadata.get('receptor_numero', ''),
|
| 4250 |
+
"receptor_jid": reply_metadata.get('receptor_jid', ''),
|
| 4251 |
+
"is_inter_user_reply": reply_metadata.get('is_inter_user_reply', False),
|
| 4252 |
"replied_to_author": reply_metadata.get('replied_to_author_name', ''),
|
| 4253 |
"replied_to_content": reply_metadata.get('replied_to_text', '')
|
| 4254 |
})
|
|
|
|
| 7308 |
isolation_parts.append(reply_section)
|
| 7309 |
|
| 7310 |
# SECAO 2: LSTM CONTEXT (Peso 0.8) — REPLY LOCK: suprime quando reply_to_bot sem menção explícita (evita contaminação ISPETEC vs ditado)
|
| 7311 |
+
_explicit_mention_local = bool(re.search(r'você falou|daquela conversa|anteriormente|você disse|você mencionou', mensagem, re.IGNORECASE))
|
| 7312 |
+
_lstm_locked = is_reply and reply_to_bot and not _explicit_mention_local
|
| 7313 |
if unified_context:
|
| 7314 |
if _lstm_locked:
|
| 7315 |
# Reply citado já tem peso 1.0 — não poluir com tópicos antigos do LSTM
|
|
|
|
| 7332 |
lstm_section += "\n--- Topicos por Participante ---"
|
| 7333 |
for speaker, msgs in speakers_topics.items():
|
| 7334 |
lstm_section += f"\n[{speaker}]: {' | '.join(msgs[:3])}"
|
| 7335 |
+
state_msg = f" - reply_to_bot={reply_to_bot}, explicit_mention={_explicit_mention_local}"
|
| 7336 |
self.logger.info(f"✔... [LSTM INJETADO COM FOCO reply_to_bot={reply_to_bot}] topic={lstm_ctx.get('topic_principal')}{state_msg}")
|
| 7337 |
isolation_parts.append(lstm_section)
|
| 7338 |
|
modules/listen_engine.py
CHANGED
|
@@ -22,14 +22,14 @@ class MensagemMetadata:
|
|
| 22 |
# Identificadores (sem default — obrigatórios)
|
| 23 |
msg_id: str # ID único da mensagem
|
| 24 |
timestamp: float # Unix timestamp
|
| 25 |
-
|
| 26 |
# Autoria (sem default — obrigatórios)
|
| 27 |
author_id: str # Quem enviou (número/ID)
|
| 28 |
author_nome: str # Nome do autor
|
| 29 |
-
|
| 30 |
# Contexto de localização (sem default — obrigatório)
|
| 31 |
grupo_id: str # ID do grupo (remoteJid)
|
| 32 |
-
|
| 33 |
# Conteúdo (sem default — obrigatório)
|
| 34 |
texto_original: str # Mensagem bruta
|
| 35 |
|
|
@@ -37,30 +37,38 @@ class MensagemMetadata:
|
|
| 37 |
grupo_nome: str = "" # Nome do grupo (opcional)
|
| 38 |
texto_processado: str = "" # Msg processada (se houver)
|
| 39 |
tipo_mensagem: str = "texto" # texto, media, reply, mention, command
|
| 40 |
-
|
| 41 |
# FLAGS CRÍTICAS - DETERMINAM RESPOSTA
|
| 42 |
is_directed_to_bot: bool = False # Mensagem direcionada ao bot?
|
| 43 |
is_mention_to_bot: bool = False # Menciona "@Akira" ou "Akira, "
|
| 44 |
is_reply_to_bot: bool = False # Resposta (reply) à mensagem anterior do bot
|
| 45 |
is_command_to_bot: bool = False # Começa com #, /, $
|
| 46 |
is_privileged_user: bool = False # Usuário privilegiado (Isaac)
|
| 47 |
-
|
| 48 |
# RESPOSTA REQUERIDA? (ANY of above flags)
|
| 49 |
requer_resposta: bool = field(default=False, init=False)
|
| 50 |
-
|
| 51 |
# ℹ CONTEXTO PURO - Sempre armazenar
|
| 52 |
reply_to_msg_id: Optional[str] = None # Se é reply, ID da msg anterior
|
| 53 |
reply_to_author_id: Optional[str] = None # Quem enviou a msg anterior
|
| 54 |
reply_to_texto: Optional[str] = None # Preview do texto anterior
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
# Análise
|
| 57 |
emocao_detectada: str = "neutral"
|
| 58 |
confianca_emocao: float = 0.5
|
| 59 |
nivel_importancia: str = "low" # low, medium, high
|
| 60 |
-
|
| 61 |
# Proatividade
|
| 62 |
should_proact: bool = False # Mensagem precisa de ação proativa do bot?
|
| 63 |
-
|
| 64 |
# Privacidade
|
| 65 |
eh_privado: bool = False
|
| 66 |
eh_grupo: bool = True
|
|
@@ -72,6 +80,23 @@ class MensagemMetadata:
|
|
| 72 |
self.is_mention_to_bot or
|
| 73 |
self.is_reply_to_bot
|
| 74 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
|
| 76 |
@dataclass
|
| 77 |
class ContextoGrupo:
|
|
|
|
| 22 |
# Identificadores (sem default — obrigatórios)
|
| 23 |
msg_id: str # ID único da mensagem
|
| 24 |
timestamp: float # Unix timestamp
|
| 25 |
+
|
| 26 |
# Autoria (sem default — obrigatórios)
|
| 27 |
author_id: str # Quem enviou (número/ID)
|
| 28 |
author_nome: str # Nome do autor
|
| 29 |
+
|
| 30 |
# Contexto de localização (sem default — obrigatório)
|
| 31 |
grupo_id: str # ID do grupo (remoteJid)
|
| 32 |
+
|
| 33 |
# Conteúdo (sem default — obrigatório)
|
| 34 |
texto_original: str # Mensagem bruta
|
| 35 |
|
|
|
|
| 37 |
grupo_nome: str = "" # Nome do grupo (opcional)
|
| 38 |
texto_processado: str = "" # Msg processada (se houver)
|
| 39 |
tipo_mensagem: str = "texto" # texto, media, reply, mention, command
|
| 40 |
+
|
| 41 |
# FLAGS CRÍTICAS - DETERMINAM RESPOSTA
|
| 42 |
is_directed_to_bot: bool = False # Mensagem direcionada ao bot?
|
| 43 |
is_mention_to_bot: bool = False # Menciona "@Akira" ou "Akira, "
|
| 44 |
is_reply_to_bot: bool = False # Resposta (reply) à mensagem anterior do bot
|
| 45 |
is_command_to_bot: bool = False # Começa com #, /, $
|
| 46 |
is_privileged_user: bool = False # Usuário privilegiado (Isaac)
|
| 47 |
+
|
| 48 |
# RESPOSTA REQUERIDA? (ANY of above flags)
|
| 49 |
requer_resposta: bool = field(default=False, init=False)
|
| 50 |
+
|
| 51 |
# ℹ CONTEXTO PURO - Sempre armazenar
|
| 52 |
reply_to_msg_id: Optional[str] = None # Se é reply, ID da msg anterior
|
| 53 |
reply_to_author_id: Optional[str] = None # Quem enviou a msg anterior
|
| 54 |
reply_to_texto: Optional[str] = None # Preview do texto anterior
|
| 55 |
+
|
| 56 |
+
# EMISSOR → RECEPTOR (Inter-user reply / passive listen)
|
| 57 |
+
# Quem enviou a msg atual (emissor) e a quem ela responde (receptor)
|
| 58 |
+
emissor_nome: Optional[str] = None # Nome do remetente da mensagem atual
|
| 59 |
+
emissor_id: Optional[str] = None # ID do remetente da mensagem atual
|
| 60 |
+
receptor_nome: Optional[str] = None # Nome de quem recebe o reply (autor msg citada)
|
| 61 |
+
receptor_id: Optional[str] = None # ID de quem recebe o reply
|
| 62 |
+
is_inter_user_reply: bool = False # True se é reply entre usuários (não ao bot)
|
| 63 |
+
|
| 64 |
# Análise
|
| 65 |
emocao_detectada: str = "neutral"
|
| 66 |
confianca_emocao: float = 0.5
|
| 67 |
nivel_importancia: str = "low" # low, medium, high
|
| 68 |
+
|
| 69 |
# Proatividade
|
| 70 |
should_proact: bool = False # Mensagem precisa de ação proativa do bot?
|
| 71 |
+
|
| 72 |
# Privacidade
|
| 73 |
eh_privado: bool = False
|
| 74 |
eh_grupo: bool = True
|
|
|
|
| 80 |
self.is_mention_to_bot or
|
| 81 |
self.is_reply_to_bot
|
| 82 |
)
|
| 83 |
+
# Se for reply inter‑user (não ao bot), garantir que os campos emissor/receptor estejam preenchidos
|
| 84 |
+
if self.is_reply_to_bot is False and self.reply_to_author_id:
|
| 85 |
+
# emissor = autor da mensagem atual
|
| 86 |
+
self.emissor_nome = self.emissor_nome or self.author_nome
|
| 87 |
+
self.emissor_id = self.emissor_id or self.author_id
|
| 88 |
+
# receptor = autor da mensagem citada
|
| 89 |
+
self.receptor_nome = self.receptor_nome # name lookup via dict (já temos o ID)
|
| 90 |
+
self.receptor_id = self.receptor_id or self.reply_to_author_id
|
| 91 |
+
self.is_inter_user_reply = True
|
| 92 |
+
else:
|
| 93 |
+
self.is_inter_user_reply = False
|
| 94 |
+
# Para mensagens que não são reply, deixar emissor/receptor como None
|
| 95 |
+
if not self.reply_to_author_id:
|
| 96 |
+
self.emissor_nome = self.emissor_nome or self.author_nome
|
| 97 |
+
self.emissor_id = self.emissor_id or self.author_id
|
| 98 |
+
self.receptor_nome = None
|
| 99 |
+
self.receptor_id = None
|
| 100 |
|
| 101 |
@dataclass
|
| 102 |
class ContextoGrupo:
|