import ConfigManager from './ConfigManager.js'; import { CustomerIdentifier } from './CustomerIdentifier.js'; import { getContentType } from '@whiskeysockets/baileys'; import type { Logger } from 'pino'; export type ExtractedMessage = { type: string | undefined; text: string; isGroup: boolean; remoteJid: string; senderNum: string; senderCrmFormat: string; senderName: string; isReplyToBot: boolean; messageId: string | undefined; fromMe: boolean; mentionedJid: string[]; }; /** * Fluxo PV simples (estilo negra_plena, sem menus): * - PV: responde a tudo (menos fromMe/stubs/vazio/só-emoji). * - Grupo: só se for reply à Akira, menção ou "akira" no texto. */ export class MessageProcessor { private config: ConfigManager; private logger: Logger; private customerId: CustomerIdentifier; private botId: string = ''; constructor(logger: Logger) { this.config = ConfigManager.getInstance(); this.logger = logger; this.customerId = new CustomerIdentifier(); } public setBotId(id: string) { this.botId = this.customerId.getClientId(id); } public extractInfo(m: any): ExtractedMessage | null { const message = m.message; if (!message) return null; const type = getContentType(message); let text = ''; if (type === 'conversation') text = message.conversation; else if (type === 'extendedTextMessage') text = message.extendedTextMessage.text; else if (type === 'imageMessage' && message.imageMessage.caption) text = message.imageMessage.caption; else if (type === 'videoMessage' && message.videoMessage.caption) text = message.videoMessage.caption; const remoteJid = m.key.remoteJid || ''; const isGroup = remoteJid.endsWith('@g.us'); let senderRaw = isGroup ? m.key.participant : remoteJid; if (m.key.fromMe) senderRaw = this.botId; const senderPn = m.key.senderPn || m.key.remoteJidAlt || senderRaw; const senderNum = this.customerId.getClientId(senderPn); const senderCrmFormat = this.customerId.formatForCRM(senderPn); const contextInfo = message?.extendedTextMessage?.contextInfo; const repliedJid = contextInfo?.participant || ''; const isReplyToBot = !!repliedJid && this.customerId.getClientId(repliedJid) === this.botId; return { type, text: text || '', isGroup, remoteJid, senderNum, senderCrmFormat, senderName: m.pushName || 'Cliente', isReplyToBot, messageId: m.key.id, fromMe: m.key.fromMe || false, mentionedJid: contextInfo?.mentionedJid || [], }; } public shouldRespondToAI(info: ExtractedMessage, rawMessage: any): boolean { if (info.fromMe) return false; if (rawMessage.messageStubType) { this.logger.debug('STUB ignorado'); return false; } const textoLimpo = (info.text || '').trim(); if (textoLimpo.length === 0) return false; if (!info.isGroup) { const emojiOnlyRegex = /^[\p{Emoji}\p{Emoji_Modifier}\p{Emoji_Component}\p{Emoji_Modifier_Base}\p{Emoji_Presentation}\s]{1,10}$/u; if (emojiOnlyRegex.test(textoLimpo) && textoLimpo.length <= 10) return false; return true; } if (info.isReplyToBot) return true; const isBotMentioned = info.mentionedJid.some( (jid) => this.customerId.getClientId(jid) === this.botId ); if (isBotMentioned) return true; if (textoLimpo.toLowerCase().includes('akira')) return true; return false; } }