Spaces:
Running
""" βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ INTEGRATION GUIDE β COMO INTEGRAR NO api.py EXISTENTE βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Este arquivo mostra:
- Como modificar o endpoint POST /akira existente
- Como usar ContextManagerV2
- Como usar ListenStreamProcessor
- Exemplos prΓ‘ticos de fluxo
IMPORTANTE: Isso SUBSTITUI o sistema antigo de context, mantendo compatibilidade com code existente. βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ """
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π¦ IMPORTS NECESSΓRIOS
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
from modules.context_manager_v2 import ( ContextManagerV2, get_context_manager, MessageType ) from modules.listen_stream_processor import ( ListenStreamProcessor, get_listen_processor ) from typing import Dict, Any import logging
logger = logging.getLogger(name)
ctx_manager = get_context_manager() listen_processor = get_listen_processor()
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π NOVO FLUXO DO ENDPOINT /akira
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""" ANTES (buggy): ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ POST /akira { "usuario": "Isaac", "numero": "202391978787009", "texto": "@AKIRA qual Γ© a capital?" }
β api.py chama obter_historico() β PROBLEMA: Retorna ALL mensagens, misturando grupos β AKIRA responde sem isolaΓ§Γ£o
DEPOIS (robusto): ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ POST /akira { "usuario": "Isaac", "numero": "202391978787009", "texto": "@AKIRA qual Γ© a capital?", "tipo_conversa": "grupo" | "pv", "grupo_id": "g120363392399993499" (opcional), "referenced_message_author": "AKIRA", (opcional) }
β listen_processor.processar_mensagem_chegando() β Classifica como DIRECT ou CONTEXTUAL β Adiciona Γ context_manager isolado por conversation_id
β Se DIRECT (true): β ctx_manager.obter_historico_direto() β APENAS mensagens direcionadas a AKIRA β Isolado por conversation_id β AKIRA responde
β Se CONTEXTUAL (false): β Registra mas NΓO processa β AKIRA entende fluxo via obter_contexto_grupo_amplificado() """
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π§ MODIFICAΓΓO NO ENDPOINT /akira
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def novo_akira_endpoint_handler(request_data: Dict[str, Any]) -> Dict[str, Any]: """ Novo handler para POST /akira com isolaΓ§Γ£o de contexto.
Substitui a lΓ³gica antiga em api.py:akira_endpoint()
"""
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PASSO 1: EXTRAI DADOS CHEGANDO
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
usuario = request_data.get('usuario', 'desconhecido')
numero = request_data.get('numero', '')
texto = request_data.get('texto', '')
tipo_conversa = request_data.get('tipo_conversa', 'pv')
grupo_id = request_data.get('grupo_id')
# ReferΓͺncia (se Γ© resposta a outra mensagem)
referenced_author = request_data.get('referenced_message_author')
referenced_texto = request_data.get('referenced_message_texto')
referenced_id = request_data.get('referenced_message_id')
logger.info(
f"π¨ Mensagem chegando: {usuario} ({numero}) em {tipo_conversa} | "
f"Texto: {texto[:50]}..."
)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PASSO 2: PROCESSA VIA LISTEN STREAM
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
evento = {
'usuario': usuario,
'numero': numero,
'texto': texto,
'tipo_conversa': tipo_conversa,
'grupo_id': grupo_id,
'referenced_message_author': referenced_author,
'referenced_message_texto': referenced_texto,
'referenced_message_id': referenced_id,
}
resultado_processamento = listen_processor.processar_mensagem_chegando(evento)
logger.info(
f"π ClassificaΓ§Γ£o: {resultado_processamento['tipo_message']} | "
f"Deve processar: {resultado_processamento['deve_processar']}"
)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PASSO 3: DECIDE SE AKIRA RESPONDE
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if not resultado_processamento['deve_processar']:
# Mensagem CONTEXTUAL β apenas registra, nΓ£o responde
logger.info(f"π Mensagem contextual (escuta). ConversΓ£o_id: {resultado_processamento['conversation_id']}")
return {
'status': 'context_registered',
'tipo': 'contextual',
'message': f"Entendi. {usuario} falou sobre isso no grupo.",
'deve_responder': False,
'conversation_id': resultado_processamento['conversation_id'],
}
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PASSO 4: AKIRA RESPONDE (mensagem Γ© DIRETA)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
conversation_id = resultado_processamento['conversation_id']
# ObtΓ©m contexto ISOLADO
contexto = listen_processor.obter_contexto_para_resposta(
numero=numero,
tipo_conversa=tipo_conversa,
grupo_id=grupo_id,
include_contextual=True
)
logger.info(
f"π Contexto obtido: {contexto['total_direct']} mensagens diretas | "
f"Participantes: {contexto.get('participants', [])}"
)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PASSO 5: ENRIQUECER COM CONTEXTO DE GRUPO
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
contexto_grupo_info = contexto.get('grupo_flow', {})
participants = contexto.get('participants', [])
# Monta prompt para AKIRA
prompt_system = f"""
VocΓͺ Γ© AKIRA, assistente IA em um grupo. Contexto:
- Participantes do grupo: {', '.join(participants) if participants else 'Desconhecido'}
- TΓ³picos recentes: {', '.join(contexto.get('topics', [])) if contexto.get('topics') else 'VΓ‘rios'}
- Sua conversa com {usuario}: {len(contexto['direct_messages'])} mensagens anteriores
IMPORTANTE: Responda APENAS sobre o que foi perguntado a vocΓͺ. NΓO comente sobre outras conversas do grupo (escuta sem falar). """
# HistΓ³rico ISOLADO
mensagens_anteriores = [
{
'usuario': m['usuario'],
'texto': m['texto'],
'timestamp': m['timestamp']
}
for m in contexto['direct_messages']
]
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PASSO 6: CHAMA LLM (seu cΓ³digo existente)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Isso seria integrado com seu chain LLM existente:
# resposta = gerar_resposta_llm(
# sistema=prompt_system,
# historico=mensagens_anteriores,
# mensagem_atual=texto,
# usuario=usuario
# )
resposta = f"[RESPOSTA DE AKIRA] VocΓͺ perguntou: {texto[:100]}" # Placeholder
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PASSO 7: RETORNA
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
return {
'status': 'success',
'tipo': 'direct',
'resposta': resposta,
'deve_responder': True,
'conversation_id': conversation_id,
'usuario': usuario,
'contexto_info': {
'num_direct_messages': contexto['total_direct'],
'participants': participants,
'topics': contexto.get('topics', []),
}
}
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π ALTERAΓΓES NECESSΓRIAS NO api.py
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""" LOCAIS ESPECΓFICOS A MODIFICAR EM api.py:
1οΈβ£ IMPORT SECTION (top do arquivo) ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Adicionar:
from modules.context_manager_v2 import get_context_manager
from modules.listen_stream_processor import get_listen_processor
ctx_manager = get_context_manager()
listen_processor = get_listen_processor()
2οΈβ£ FUNΓΓO akira_endpoint() - SUBSTITUIR INTEIRA ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ LocalizaΓ§Γ£o: api.py::akira_endpoint() (aproximadamente linha 950)
AΓ§Γ£o: SUBSTITUIR todo o corpo da funΓ§Γ£o pelo code do
novo_akira_endpoint_handler() acima.
O que muda:
β
Remove: data = contexto.obter_historico() (BUGGY - sem filtro)
β
Adiciona: resultado_processamento = listen_processor.processar_mensagem_chegando()
β
Adiciona: if not resultado_processamento['deve_processar']: return (skip contextual)
β
Adiciona: contexto = listen_processor.obter_contexto_para_resposta() (ISOLADO)
3οΈβ£ FUNΓΓO _get_user_context() - MODIFICAR ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ LocalizaΓ§Γ£o: api.py::_get_user_context() (aproximadamente linha 1000)
ANTES:
def _get_user_context(numero, usuario):
historico = contexto.obter_historico() # β SEM FILTRO
return {
'historico': historico,
'usuario': usuario
}
DEPOIS:
def _get_user_context(numero, usuario, tipo_conversa='pv', grupo_id=None):
# Usa novo context manager ISOLADO
historico = ctx_manager.obter_historico_direto(
numero=numero,
tipo_conversa=tipo_conversa,
grupo_id=grupo_id,
limit=50
)
contexto_grupo = ctx_manager.obter_contexto_grupo_amplificado(
numero=numero,
tipo_conversa=tipo_conversa,
grupo_id=grupo_id
) if tipo_conversa == "grupo" else None
return {
'historico': [m.to_dict() for m in historico],
'usuario': usuario,
'contexto_grupo': contexto_grupo,
'conversation_id': historico[0].conversation_id if historico else None
}
4οΈβ£ FUNΓΓO obter_historico() - DEPRECAR OU SUBSTITUIR ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ LocalizaΓ§Γ£o: database.py ou modules/database.py
ANTES:
def obter_historico():
return db.query(Mensagem).all() # β RETORNA TUDO
DEPOIS:
def obter_historico(conversation_id: str, msg_type: str = 'all'):
# msg_type: 'direct', 'contextual', 'all'
query = db.query(Mensagem).filter(
Mensagem.conversation_id == conversation_id
)
if msg_type == 'direct':
query = query.filter(Mensagem.tipo == 'direct')
elif msg_type == 'contextual':
query = query.filter(Mensagem.tipo == 'contextual')
return query.order_by(Mensagem.timestamp.desc()).limit(100).all()
5οΈβ£ SUPORTE AO PAYLOAD NOVO ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ O endpoint POST /akira AGORA ACEITA:
{
"usuario": "Isaac",
"numero": "202391978787009",
"texto": "@AKIRA qual Γ© a capital?",
"tipo_conversa": "grupo", β NOVO
"grupo_id": "g120363392399993499", β NOVO (opcional)
"referenced_message_author": "StefΓ’nio", β NOVO (opcional)
"referenced_message_texto": "Oi", β NOVO (opcional)
"referenced_message_id": "msg_123" β NOVO (opcional)
}
Os campos 'tipo_conversa', 'grupo_id', 'referenced_*' sΓ£o opcionais
e vΓͺm do discord-ts quando disponΓveis. Se nΓ£o vierem, valor default
Γ© 'pv' (conversa privada).
"""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π EXEMPLO DE USO COMPLETO
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""" CENΓRIO: Isaac e StefΓ’nio em grupo
1οΈβ£ ISAAC envia: "@AKIRA qual Γ© a capital de Portugal?" grupo: "g120363392399993499"
β listen_processor classifica como DIRECT (menciona @AKIRA)
β ctx_manager.adicionar_message_direta() com conversation_id ΓΊnico
β AKIRA responde: "A capital Γ© Lisboa"
2οΈβ£ STEFΓNIO responde (sem @AKIRA): "Bacano, eu nΓ£o sabia"
β listen_processor classifica como CONTEXTUAL
β ctx_manager.adicionar_message_contextual()
β AKIRA NΓO responde (nΓ£o foi direcionada a ela)
β Mas AKIRA "entende" que StefΓ’nio achou legal
3οΈβ£ STEFΓNIO envia: "Qual Γ© a capital da FranΓ§a?" (sem @AKIRA)
β listen_processor classifica como CONTEXTUAL
β AKIRA nΓ£o responde
4οΈβ£ ISAAC responde: "@AKIRA? JΓ‘ que perguntou, qual Γ©?"
β listen_processor classifica como DIRECT (menciona @AKIRA)
β ObtΓ©m contexto ISOLADO (sΓ³ conversas diretas com Isaac)
β AKIRA NΓO vΓͺ a pergunta de StefΓ’nio (contextual)
β AKIRA responde baseada sΓ³ no que Isaac perguntou
RESULTADO: β AKIRA entende quem fala o quΓͺ β NΓ£o mistura contextos β Responde apenas quando direcionada β Escuta o fluxo sem contaminar """
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π― PRΓXIMOS PASSOS
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""" TAREFAS PARA IMPLEMENTAR:
- β Criar context_manager_v2.py (FEITO)
- β Criar listen_stream_processor.py (FEITO)
- π Modificar api.py:
- Importar novos mΓ³dulos
- Reescrever akira_endpoint()
- Atualizar _get_user_context()
- π Modificar database.py:
- Adicionar suporte a conversation_id na query
- Adicionar campo 'tipo' na tabela Mensagem
- π Testar com fluxo real:
- Isaac + StefΓ’nio em grupo
- Verificar isolamento
- π Integrar com discord-ts:
- discord-ts deve enviar 'tipo_conversa' e 'grupo_id'
- Enviar 'referenced_message_author' quando Γ© reply """
all = [ 'novo_akira_endpoint_handler', 'ctx_manager', 'listen_processor', ]