Akiragpu / botcore /modules /MessageProcessor.ts
Isaac Quarenta
feat(botcore): BotCore WhatsApp PV simples estilo negra_plena -> POST /api/akira (Akiragpu)
6727a3d
Raw History Blame Contribute Delete
3.76 kB
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;
}
}