From cd673107b8f9adaf344fed16fc89a627edb6d6c9 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 12 Jan 2025 20:30:09 -0500 Subject: [PATCH] Salvando-historico do usuario --- src/api/controllers/sendMessage.controller.ts | 151 +++++++- src/api/dto/sendMessage.dto.ts | 2 - .../evolution/evolution.channel.service.ts | 26 +- .../chatwoot/services/chatwoot.service.ts | 84 ++++- .../controllers/evolutionBot.controller.ts | 2 +- .../chatbot/openai/services/openai.service.ts | 346 +++++++++++------- 6 files changed, 459 insertions(+), 152 deletions(-) diff --git a/src/api/controllers/sendMessage.controller.ts b/src/api/controllers/sendMessage.controller.ts index ac40562c..77117c84 100644 --- a/src/api/controllers/sendMessage.controller.ts +++ b/src/api/controllers/sendMessage.controller.ts @@ -17,81 +17,200 @@ import { import { WAMonitoringService } from '@api/services/monitor.service'; import { BadRequestException } from '@exceptions'; import { isBase64, isURL } from 'class-validator'; +import { Logger } from '@config/logger.config'; export class SendMessageController { constructor(private readonly waMonitor: WAMonitoringService) {} + private readonly logger = new Logger('SendMessageController'); + public async sendTemplate({ instanceName }: InstanceDto, data: SendTemplateDto) { - return await this.waMonitor.waInstances[instanceName].templateMessage(data); + this.logger.log(`[sendTemplate] [${instanceName}] - Iniciando envio de template...`); + this.logger.debug(`[sendTemplate] [${instanceName}] - Dados de envio: ${JSON.stringify(data)}`); + + const result = await this.waMonitor.waInstances[instanceName].templateMessage(data); + + this.logger.log(`[sendTemplate] [${instanceName}] - Envio concluído com sucesso.`); + this.logger.debug(`[sendTemplate] [${instanceName}] - Resultado: ${JSON.stringify(result)}`); + + return result; } public async sendText({ instanceName }: InstanceDto, data: SendTextDto) { - return await this.waMonitor.waInstances[instanceName].textMessage(data); + this.logger.log(`[sendText] [${instanceName}] - Iniciando envio de texto...`); + this.logger.debug(`[sendText] [${instanceName}] - Dados de envio: ${JSON.stringify(data)}`); + + const result = await this.waMonitor.waInstances[instanceName].textMessage(data); + + this.logger.log(`[sendText] [${instanceName}] - Envio concluído com sucesso.`); + this.logger.debug(`[sendText] [${instanceName}] - Resultado: ${JSON.stringify(result)}`); + + return result; } public async sendMedia({ instanceName }: InstanceDto, data: SendMediaDto, file?: any) { + this.logger.log(`[sendMedia] [${instanceName}] - Iniciando envio de mídia...`); + this.logger.debug(`[sendMedia] [${instanceName}] - Dados de envio: ${JSON.stringify(data)}`); + if (isBase64(data?.media) && !data?.fileName && data?.mediatype === 'document') { + this.logger.error( + `[sendMedia] [${instanceName}] - Falha: Para base64, é necessário informar o nome do arquivo.` + ); throw new BadRequestException('For base64 the file name must be informed.'); } if (file || isURL(data?.media) || isBase64(data?.media)) { - return await this.waMonitor.waInstances[instanceName].mediaMessage(data, file); + const result = await this.waMonitor.waInstances[instanceName].mediaMessage(data, file); + this.logger.log(`[sendMedia] [${instanceName}] - Envio de mídia concluído com sucesso.`); + this.logger.debug(`[sendMedia] [${instanceName}] - Resultado: ${JSON.stringify(result)}`); + return result; } + + this.logger.error( + `[sendMedia] [${instanceName}] - Falha: Mídia deve ser uma URL ou base64.` + ); throw new BadRequestException('Owned media must be a url or base64'); } public async sendPtv({ instanceName }: InstanceDto, data: SendPtvDto, file?: any) { + this.logger.log(`[sendPtv] [${instanceName}] - Iniciando envio de vídeo (PTV)...`); + this.logger.debug(`[sendPtv] [${instanceName}] - Dados de envio: ${JSON.stringify(data)}`); + if (file || isURL(data?.video) || isBase64(data?.video)) { - return await this.waMonitor.waInstances[instanceName].ptvMessage(data, file); + const result = await this.waMonitor.waInstances[instanceName].ptvMessage(data, file); + this.logger.log(`[sendPtv] [${instanceName}] - Envio de vídeo (PTV) concluído com sucesso.`); + this.logger.debug(`[sendPtv] [${instanceName}] - Resultado: ${JSON.stringify(result)}`); + return result; } + + this.logger.error( + `[sendPtv] [${instanceName}] - Falha: Vídeo deve ser uma URL ou base64.` + ); throw new BadRequestException('Owned media must be a url or base64'); } public async sendSticker({ instanceName }: InstanceDto, data: SendStickerDto, file?: any) { + this.logger.log(`[sendSticker] [${instanceName}] - Iniciando envio de sticker...`); + this.logger.debug(`[sendSticker] [${instanceName}] - Dados de envio: ${JSON.stringify(data)}`); + if (file || isURL(data.sticker) || isBase64(data.sticker)) { - return await this.waMonitor.waInstances[instanceName].mediaSticker(data, file); + const result = await this.waMonitor.waInstances[instanceName].mediaSticker(data, file); + this.logger.log(`[sendSticker] [${instanceName}] - Envio de sticker concluído com sucesso.`); + this.logger.debug(`[sendSticker] [${instanceName}] - Resultado: ${JSON.stringify(result)}`); + return result; } + + this.logger.error( + `[sendSticker] [${instanceName}] - Falha: Sticker deve ser uma URL ou base64.` + ); throw new BadRequestException('Owned media must be a url or base64'); } public async sendWhatsAppAudio({ instanceName }: InstanceDto, data: SendAudioDto, file?: any) { + this.logger.log(`[sendWhatsAppAudio] [${instanceName}] - Iniciando envio de áudio...`); + this.logger.debug(`[sendWhatsAppAudio] [${instanceName}] - Dados de envio: ${JSON.stringify(data)}`); + if (file?.buffer || isURL(data.audio) || isBase64(data.audio)) { - // Si file existe y tiene buffer, o si es una URL o Base64, continúa - return await this.waMonitor.waInstances[instanceName].audioWhatsapp(data, file); + const result = await this.waMonitor.waInstances[instanceName].audioWhatsapp(data, file); + this.logger.log(`[sendWhatsAppAudio] [${instanceName}] - Envio de áudio concluído com sucesso.`); + this.logger.debug(`[sendWhatsAppAudio] [${instanceName}] - Resultado: ${JSON.stringify(result)}`); + return result; } else { - console.error('El archivo no tiene buffer o el audio no es una URL o Base64 válida'); - throw new BadRequestException('Owned media must be a url, base64, or valid file with buffer'); + this.logger.error( + `[sendWhatsAppAudio] [${instanceName}] - Falha: O arquivo não possui buffer, ou o áudio não é uma URL/base64 válida.` + ); + throw new BadRequestException( + 'Owned media must be a url, base64, or valid file with buffer' + ); } } public async sendButtons({ instanceName }: InstanceDto, data: SendButtonsDto) { - return await this.waMonitor.waInstances[instanceName].buttonMessage(data); + this.logger.log(`[sendButtons] [${instanceName}] - Iniciando envio de botões...`); + this.logger.debug(`[sendButtons] [${instanceName}] - Dados de envio: ${JSON.stringify(data)}`); + + const result = await this.waMonitor.waInstances[instanceName].buttonMessage(data); + + this.logger.log(`[sendButtons] [${instanceName}] - Envio de botões concluído com sucesso.`); + this.logger.debug(`[sendButtons] [${instanceName}] - Resultado: ${JSON.stringify(result)}`); + + return result; } public async sendLocation({ instanceName }: InstanceDto, data: SendLocationDto) { - return await this.waMonitor.waInstances[instanceName].locationMessage(data); + this.logger.log(`[sendLocation] [${instanceName}] - Iniciando envio de localização...`); + this.logger.debug(`[sendLocation] [${instanceName}] - Dados de envio: ${JSON.stringify(data)}`); + + const result = await this.waMonitor.waInstances[instanceName].locationMessage(data); + + this.logger.log(`[sendLocation] [${instanceName}] - Envio de localização concluído com sucesso.`); + this.logger.debug(`[sendLocation] [${instanceName}] - Resultado: ${JSON.stringify(result)}`); + + return result; } public async sendList({ instanceName }: InstanceDto, data: SendListDto) { - return await this.waMonitor.waInstances[instanceName].listMessage(data); + this.logger.log(`[sendList] [${instanceName}] - Iniciando envio de lista...`); + this.logger.debug(`[sendList] [${instanceName}] - Dados de envio: ${JSON.stringify(data)}`); + + const result = await this.waMonitor.waInstances[instanceName].listMessage(data); + + this.logger.log(`[sendList] [${instanceName}] - Envio de lista concluído com sucesso.`); + this.logger.debug(`[sendList] [${instanceName}] - Resultado: ${JSON.stringify(result)}`); + + return result; } public async sendContact({ instanceName }: InstanceDto, data: SendContactDto) { - return await this.waMonitor.waInstances[instanceName].contactMessage(data); + this.logger.log(`[sendContact] [${instanceName}] - Iniciando envio de contato...`); + this.logger.debug(`[sendContact] [${instanceName}] - Dados de envio: ${JSON.stringify(data)}`); + + const result = await this.waMonitor.waInstances[instanceName].contactMessage(data); + + this.logger.log(`[sendContact] [${instanceName}] - Envio de contato concluído com sucesso.`); + this.logger.debug(`[sendContact] [${instanceName}] - Resultado: ${JSON.stringify(result)}`); + + return result; } public async sendReaction({ instanceName }: InstanceDto, data: SendReactionDto) { + this.logger.log(`[sendReaction] [${instanceName}] - Iniciando envio de reação...`); + this.logger.debug(`[sendReaction] [${instanceName}] - Dados de envio: ${JSON.stringify(data)}`); + if (!data.reaction.match(/[^()\w\sà-ú"-+]+/)) { + this.logger.error(`[sendReaction] [${instanceName}] - Falha: "reaction" deve ser um emoji.`); throw new BadRequestException('"reaction" must be an emoji'); } - return await this.waMonitor.waInstances[instanceName].reactionMessage(data); + + const result = await this.waMonitor.waInstances[instanceName].reactionMessage(data); + + this.logger.log(`[sendReaction] [${instanceName}] - Envio de reação concluído com sucesso.`); + this.logger.debug(`[sendReaction] [${instanceName}] - Resultado: ${JSON.stringify(result)}`); + + return result; } public async sendPoll({ instanceName }: InstanceDto, data: SendPollDto) { - return await this.waMonitor.waInstances[instanceName].pollMessage(data); + this.logger.log(`[sendPoll] [${instanceName}] - Iniciando envio de enquete (poll)...`); + this.logger.debug(`[sendPoll] [${instanceName}] - Dados de envio: ${JSON.stringify(data)}`); + + const result = await this.waMonitor.waInstances[instanceName].pollMessage(data); + + this.logger.log(`[sendPoll] [${instanceName}] - Envio de enquete concluído com sucesso.`); + this.logger.debug(`[sendPoll] [${instanceName}] - Resultado: ${JSON.stringify(result)}`); + + return result; } public async sendStatus({ instanceName }: InstanceDto, data: SendStatusDto, file?: any) { - return await this.waMonitor.waInstances[instanceName].statusMessage(data, file); + this.logger.log(`[sendStatus] [${instanceName}] - Iniciando envio de Status...`); + this.logger.debug(`[sendStatus] [${instanceName}] - Dados de envio: ${JSON.stringify(data)}`); + + const result = await this.waMonitor.waInstances[instanceName].statusMessage(data, file); + + this.logger.log(`[sendStatus] [${instanceName}] - Envio de Status concluído com sucesso.`); + this.logger.debug(`[sendStatus] [${instanceName}] - Resultado: ${JSON.stringify(result)}`); + + return result; } } diff --git a/src/api/dto/sendMessage.dto.ts b/src/api/dto/sendMessage.dto.ts index 801db0fe..ab450cea 100644 --- a/src/api/dto/sendMessage.dto.ts +++ b/src/api/dto/sendMessage.dto.ts @@ -49,8 +49,6 @@ export class Metadata { export class SendTextDto extends Metadata { text: string; // Conteúdo do texto number: string; // WhatsApp ou 'webwidget:...' - channel?: string; // ex: 'Channel::WebWidget' ou outro - inbox_id?: number; // se quiser mandar explicitamente ID=3 delay?: number; quoted?: any; linkPreview?: boolean; diff --git a/src/api/integrations/channel/evolution/evolution.channel.service.ts b/src/api/integrations/channel/evolution/evolution.channel.service.ts index 88c071ce..5fc5c7e1 100644 --- a/src/api/integrations/channel/evolution/evolution.channel.service.ts +++ b/src/api/integrations/channel/evolution/evolution.channel.service.ts @@ -347,7 +347,7 @@ export class EvolutionStartupService extends ChannelStartupService { } protected async sendMessageWithTyping( - number: string, + number: string, // remoteJid message: any, options?: Options, isIntegration = false, @@ -393,18 +393,34 @@ export class EvolutionStartupService extends ChannelStartupService { ); // debug message + this.logger.debug(`[sendMessageWithTyping] Mensagem a ser enviada de numero: ${number}`); this.logger.debug( `[sendMessageWithTyping] Mensagem a ser enviada: ${JSON.stringify(message)}`, ); let messageRaw: any = { - key: { fromMe: true, id: messageId, remoteJid: number, channel: message.channel, inbox_id: message.inbox_id }, + key: { + fromMe: true, + id: messageId, + remoteJid: number, + }, messageTimestamp: Math.round(new Date().getTime() / 1000), webhookUrl, source: 'unknown', instanceId: this.instanceId, status: status[1], }; + + // Salvando chatwootConversationId para mensagens webwidget + if (number && number.startsWith('webwidget:')) { + this.logger.debug('[sendMessageWithTyping] Detectado número webwidget...'); + const conversationIdStr = number.split(':')[1] || '0'; + const conversation_id = parseInt(conversationIdStr, 10); + messageRaw.source = 'web'; + messageRaw.chatwootConversationId = conversation_id; + } + // debug messageRaw + this.logger.debug(`[sendMessageWithTyping] messageRaw a ser enviada: ${number}`); this.logger.debug(`[sendMessageWithTyping] messageRaw a ser enviada: ${JSON.stringify(messageRaw)}`); // Verifica o tipo de mídia para compor a mensagem @@ -498,7 +514,7 @@ export class EvolutionStartupService extends ChannelStartupService { }); } - this.logger.debug('[sendMessageWithTyping] Salvando mensagem no Prisma...'); + this.logger.debug(`[sendMessageWithTyping] Salvando mensagem no Prisma: ${JSON.stringify(messageRaw)}`); await this.prismaRepository.message.create({ data: messageRaw, }); @@ -517,11 +533,9 @@ export class EvolutionStartupService extends ChannelStartupService { this.logger.debug(`[textMessage] Dados recebidos: ${JSON.stringify(data2)}`); const res = await this.sendMessageWithTyping( - data2.number, + data2.number, { conversation: data2.text, - channel: data2.channel, // passa channel aqui - inbox_id: data2.inbox_id, // e inbox_id aqui }, { delay: data2?.delay, diff --git a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts index dd62e4dc..7669ed19 100644 --- a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts +++ b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts @@ -1365,6 +1365,9 @@ public async createConversation(instance: InstanceDto, body: any) { await new Promise((resolve) => setTimeout(resolve, 500)); const client = await this.clientCw(instance); + const chatId = + body.conversation?.meta?.sender?.identifier || + body.conversation?.meta?.sender?.phone_number?.replace('+', ''); if (!client) { this.logger.warn('[receiveWebhook] Client não encontrado'); @@ -1381,6 +1384,82 @@ public async createConversation(instance: InstanceDto, body: any) { const keyToDelete = `${instance.instanceName}:createConversation-${body.meta.sender.identifier}`; this.cache.delete(keyToDelete); } + + // debugar intancia + this.logger.debug(`[receiveWebhook] Instance recebido: ${JSON.stringify(instance)}`); + + // Salva a mensagem do usuário no banco de dados + if (body.message_type === 'incoming' && body.event === 'message_created') { + this.logger.debug('[receiveWebhook] Salvando Mensagem do usuário'); + + // Id da conversa no Chatwoot + const conversationId = body.conversation?.id; + // Conteúdo textual da mensagem enviada pelo usuário (ex.: "fsddsfsdf") + const content = body.content; + + if (!conversationId || !content) { + this.logger.error('[receiveWebhook] Dados insuficientes para salvar a mensagem.'); + return; + } + + try { + // Monta os dados para inserir no Prisma + const dataToSave = { + key: { + // Você pode gerar um ID único como quiser, por exemplo: + id: String(body.id) || 'algum-id-unico', + remoteJid: `webwidget:${conversationId}`, + fromMe: false, + }, + message: { + // A parte textual da conversa + conversation: content, + }, + messageType: 'conversation', + source: 'unknown', // se for enum, ajuste conforme seu modelo + messageTimestamp: Math.floor(Date.now() / 1000), + + // Informações específicas do Chatwoot que podem ser úteis + chatwootMessageId: body.id, // ID da mensagem no Chatwoot + chatwootConversationId: conversationId, // ID da conversa no Chatwoot + chatwootInboxId: body.inbox?.id ?? null, // ID da inbox que recebeu a mensagem + chatwootContactInboxSourceId: body.conversation?.contact_inbox?.source_id ?? null, + chatwootIsRead: false, // ou true, dependendo da sua lógica + + //instace + Instance: { + connect: { name: instance.instanceName } + }, + + // Relacionamento com sua instância + instanceId: instance.instanceId, + + // Caso queira salvar o nome do usuário (pushName) + pushName: body.sender?.name ?? null, + + // Se quiser salvar o “participant”, pode usar “identifier” ou “phone_number” + participant: + body.sender?.identifier ?? + body.sender?.phone_number ?? + null, + + // Se você tiver algum status a aplicar + status: 'pending', // ou qualquer outro valor que faça sentido + }; + + this.logger.debug(`[receiveWebhook] Dados para salvar: ${JSON.stringify(dataToSave)}`); + + const savedMsg = await this.prismaRepository.message.create({ + data: dataToSave, + }); + + this.logger.debug(`[receiveWebhook] Mensagem do usuário salva: ${JSON.stringify(savedMsg)}`); + } catch (error) { + this.logger.error(`[receiveWebhook] Erro ao salvar a mensagem: ${error.message}`); + // Lógica adicional de erro, se necessário + } + } + if ( !body?.conversation || @@ -1436,9 +1515,6 @@ public async createConversation(instance: InstanceDto, body: any) { return { message: 'webwidget_incoming_ok' }; } - const chatId = - body.conversation?.meta?.sender?.identifier || - body.conversation?.meta?.sender?.phone_number?.replace('+', ''); const messageReceived = body.content ? body.content .replaceAll(/(? { return { @@ -38,9 +39,10 @@ export class OpenaiService { }; }); + // Assistant messages const assistantMessages: any = openaiBot.assistantMessages; - this.logger.debug(`AssistantMessages recuperadas: ${assistantMessages}`); - + this.logger.debug(`[sendMessageToBot] AssistantMessages recuperadas: ${assistantMessages}`); + const messagesAssistant: any[] = assistantMessages.map((message) => { return { role: 'assistant', @@ -48,8 +50,9 @@ export class OpenaiService { }; }); + // User messages const userMessages: any = openaiBot.userMessages; - this.logger.debug(`UserMessages recuperadas: ${userMessages}`); + this.logger.debug(`[sendMessageToBot] UserMessages recuperadas: ${userMessages}`); const messagesUser: any[] = userMessages.map((message) => { return { @@ -58,17 +61,18 @@ export class OpenaiService { }; }); + // Imagem messages const messageData: any = { role: 'user', - content: [{ type: 'text', text: content }], + content: content, }; if (this.isImageMessage(content)) { - this.logger.debug('Identificada mensagem de imagem no texto.'); + this.logger.debug('[sendMessageToBot] Identificada mensagem de imagem no texto.'); const contentSplit = content.split('|'); const url = contentSplit[1].split('?')[0]; - this.logger.debug(`URL da imagem extraída: ${url}`); + this.logger.debug(`[sendMessageToBot] URL da imagem extraída: ${url}`); messageData.content = [ { type: 'text', text: contentSplit[2] || content }, @@ -81,17 +85,111 @@ export class OpenaiService { ]; } - const messages: any[] = [...messagesSystem, ...messagesAssistant, ...messagesUser, messageData]; - // o logo precisa formatar messages em joson - this.logger.debug(`Mensagens que serão enviadas para a API da OpenAI: ${JSON.stringify(messages)}`); + // History Mensagens + // Define aqui o limite máximo de caracteres do histórico + const MAX_HISTORY_CHARS = 30000; + + /** + * Extrai o texto principal de um objeto de mensagem. + * @param msg Mensagem recebida do banco (tipo `Message`). + * @returns Texto extraído da mensagem ou um JSON.stringify como fallback. + */ + function extrairTextoDaMensagem(msg: Message): string { + // Se não houver conteúdo + if (!msg?.message) { + return ''; + } + + // Caso seja mensagem de texto simples + if (msg.message.conversation) { + return msg.message.conversation; + } + + // Caso seja extendedTextMessage + if (msg.message.extendedTextMessage?.text) { + return msg.message.extendedTextMessage.text; + } + + // Caso seja imagem com caption + if (msg.message.imageMessage?.caption) { + return msg.message.imageMessage.caption; + } + + // Fallback: retorna o objeto como JSON + return JSON.stringify(msg.message); + } + + let historyArray: any[] = []; + + if (remoteJid && remoteJid.startsWith('webwidget:')) { + // Extrai o ID da conversa a partir do remoteJid (ex: 'webwidget:12345') + const conversationId = remoteJid.split(':')[1] || '0'; + this.logger.debug(`[sendMessageToBot] RemoteJid é webwidget. Buscando histórico da conversa: ${conversationId}`); + + // Busca todas as mensagens, sem limite de quantidade + let conversationHistory = await this.prismaRepository.message.findMany({ + where: { + chatwootConversationId: parseInt(conversationId), + }, + orderBy: { + messageTimestamp: 'desc', + }, + }); + this.logger.debug(`[sendMessageToBot] Histórico da conversa recuperado: ${conversationHistory.length} mensagens`); + + if (conversationHistory.length > 0) { + // Inverte para ficar das mais antigas às mais recentes + conversationHistory = conversationHistory.reverse(); + + // Mapeia cada mensagem para uma linha (role + texto) + let lines = conversationHistory.map((msg) => { + const textoExtraido = extrairTextoDaMensagem(msg); + // Se a mensagem for "fromMe", consideramos como 'assistant'; senão, 'user' + const roleOpenAI = msg.key?.fromMe ? 'assistant' : 'user'; + return `${roleOpenAI}: ${textoExtraido}`; + }); + + // Monta o histórico inicial com todas as linhas + let conversationString = lines.join('\n'); + + // Se exceder o limite de caracteres, remover mensagens mais antigas + while (conversationString.length > MAX_HISTORY_CHARS && lines.length > 0) { + // Remove a primeira linha (mais antiga) do array + lines.shift(); + conversationString = lines.join('\n'); + } + + historyArray = [ + { + role: 'system', + content: `This is the conversation history so far:\n\n${conversationString}`, + } + ]; + } else { + // Caso não haja histórico + historyArray = [ + { + role: 'system', + content: 'Não há histórico de conversa ainda.', + } + ]; + } + + this.logger.debug(`[sendMessageToBot] HistoryMessages: ${JSON.stringify(historyArray)}`); + } + + // debug historyMessages + this.logger.debug(`[sendMessageToBot] HistoryMessages: ${JSON.stringify(historyArray)}`); + const messages: any[] = [...messagesSystem, ...messagesAssistant, ...messagesUser, ...historyArray, messageData]; + this.logger.debug(`[sendMessageToBot] Mensagens que serão enviadas para a API da OpenAI: ${JSON.stringify(messages)}`); if (instance.integration === Integration.WHATSAPP_BAILEYS) { - this.logger.debug('Atualizando presença para WHATSAPP_BAILEYS (composing).'); + this.logger.debug('[sendMessageToBot] Atualizando presença para WHATSAPP_BAILEYS (composing).'); await instance.client.presenceSubscribe(remoteJid); await instance.client.sendPresenceUpdate('composing', remoteJid); } - this.logger.debug('Chamando a API da OpenAI (chat.completions.create).'); + this.logger.debug('[sendMessageToBot] Chamando a API da OpenAI (chat.completions.create).'); const completions = await this.client.chat.completions.create({ model: openaiBot.model, messages: messages, @@ -99,12 +197,12 @@ export class OpenaiService { }); if (instance.integration === Integration.WHATSAPP_BAILEYS) { - this.logger.debug('Atualizando presença para WHATSAPP_BAILEYS (paused).'); + this.logger.debug('[sendMessageToBot] Atualizando presença para WHATSAPP_BAILEYS (paused).'); await instance.client.sendPresenceUpdate('paused', remoteJid); } const message = completions.choices[0].message.content; - this.logger.debug(`Resposta obtida da OpenAI (sendMessageToBot): ${message}`); + this.logger.debug(`[sendMessageToBot] Resposta obtida da OpenAI: ${message}`); return message; } @@ -118,8 +216,8 @@ export class OpenaiService { content: string, threadId: string, ) { - this.logger.debug('Enviando mensagem para o assistente (sendMessageToAssistant).'); - this.logger.debug(`RemoteJid: ${remoteJid}, ThreadId: ${threadId}, Content: ${content}`); + this.logger.debug('[sendMessageToAssistant] Enviando mensagem para o assistente.'); + this.logger.debug(`[sendMessageToAssistant] RemoteJid: ${remoteJid}, ThreadId: ${threadId}, Content: ${content}`); const messageData: any = { role: fromMe ? 'assistant' : 'user', @@ -127,11 +225,11 @@ export class OpenaiService { }; if (this.isImageMessage(content)) { - this.logger.debug('Identificada mensagem de imagem no texto para Assistant.'); + this.logger.debug('[sendMessageToAssistant] Identificada mensagem de imagem no texto.'); const contentSplit = content.split('|'); const url = contentSplit[1].split('?')[0]; - this.logger.debug(`URL da imagem extraída: ${url}`); + this.logger.debug(`[sendMessageToAssistant] URL da imagem extraída: ${url}`); messageData.content = [ { type: 'text', text: contentSplit[2] || content }, @@ -144,36 +242,36 @@ export class OpenaiService { ]; } - this.logger.debug('Criando mensagem no thread do Assistant.'); + this.logger.debug('[sendMessageToAssistant] Criando mensagem no thread do Assistant.'); await this.client.beta.threads.messages.create(threadId, messageData); if (fromMe) { - this.logger.debug('Mensagem enviada foi do próprio bot (fromMe). Enviando Telemetry.'); + this.logger.debug('[sendMessageToAssistant] Mensagem enviada foi do próprio bot (fromMe). Enviando Telemetry.'); sendTelemetry('/message/sendText'); return; } - this.logger.debug('Iniciando corrida (run) do Assistant com ID do assistant configurado.'); + this.logger.debug('[sendMessageToAssistant] Iniciando corrida (run) do Assistant com ID do assistant configurado.'); const runAssistant = await this.client.beta.threads.runs.create(threadId, { assistant_id: openaiBot.assistantId, }); if (instance.integration === Integration.WHATSAPP_BAILEYS) { - this.logger.debug('Atualizando presença para WHATSAPP_BAILEYS (composing).'); + this.logger.debug('[sendMessageToAssistant] Atualizando presença para WHATSAPP_BAILEYS (composing).'); await instance.client.presenceSubscribe(remoteJid); await instance.client.sendPresenceUpdate('composing', remoteJid); } - this.logger.debug('Aguardando resposta do Assistant (getAIResponse).'); + this.logger.debug('[sendMessageToAssistant] Aguardando resposta do Assistant (getAIResponse).'); const response = await this.getAIResponse(threadId, runAssistant.id, openaiBot.functionUrl, remoteJid, pushName); if (instance.integration === Integration.WHATSAPP_BAILEYS) { - this.logger.debug('Atualizando presença para WHATSAPP_BAILEYS (paused).'); + this.logger.debug('[sendMessageToAssistant] Atualizando presença para WHATSAPP_BAILEYS (paused).'); await instance.client.sendPresenceUpdate('paused', remoteJid); } const message = response?.data[0].content[0].text.value; - this.logger.debug(`Resposta obtida do Assistant (sendMessageToAssistant): ${message}`); + this.logger.debug(`[sendMessageToAssistant] Resposta obtida do Assistant: ${message}`); return message; } @@ -185,8 +283,8 @@ export class OpenaiService { settings: OpenaiSetting, message: string, ) { - this.logger.debug('Enviando mensagem para o WhatsApp (sendMessageWhatsapp).'); - this.logger.debug(`RemoteJid: ${remoteJid}, Mensagem: ${message}`); + this.logger.debug('[sendMessageWhatsapp] Enviando mensagem para o WhatsApp.'); + this.logger.debug(`[sendMessageWhatsapp] RemoteJid: ${remoteJid}, Mensagem: ${message}`); const linkRegex = /(!?)\[(.*?)\]\((.*?)\)/g; let textBuffer = ''; @@ -209,10 +307,10 @@ export class OpenaiService { }; // Processa links (ou mídia) dentro do texto - this.logger.debug('Verificando se a mensagem contém mídia (links) no formato [altText](url).'); + this.logger.debug('[sendMessageWhatsapp] Verificando se a mensagem contém mídia (links) no formato [altText](url).'); while ((match = linkRegex.exec(message)) !== null) { const [fullMatch, exclMark, altText, url] = match; - this.logger.debug(`Match encontrado: ${fullMatch}, url: ${url}, altText: ${altText}`); + this.logger.debug(`[sendMessageWhatsapp] Match encontrado: ${fullMatch}, url: ${url}, altText: ${altText}`); const mediaType = getMediaType(url); const beforeText = message.slice(lastIndex, match.index); @@ -236,14 +334,14 @@ export class OpenaiService { const delay = Math.min(Math.max(message.length * timePerChar, minDelay), maxDelay); if (instance.integration === Integration.WHATSAPP_BAILEYS) { - this.logger.debug('Atualizando presença (composing) antes de enviar texto em partes.'); + this.logger.debug('[sendMessageWhatsapp] Atualizando presença (composing) antes de enviar texto em partes.'); await instance.client.presenceSubscribe(remoteJid); await instance.client.sendPresenceUpdate('composing', remoteJid); } await new Promise((resolve) => { setTimeout(async () => { - this.logger.debug(`Enviando texto (splitMessage): ${message}`); + this.logger.debug(`[sendMessageWhatsapp] Enviando texto (splitMessage): ${part}`); await instance.textMessage( { number: remoteJid.split('@')[0], @@ -257,12 +355,12 @@ export class OpenaiService { }); if (instance.integration === Integration.WHATSAPP_BAILEYS) { - this.logger.debug('Atualizando presença (paused) após enviar parte do texto.'); + this.logger.debug('[sendMessageWhatsapp] Atualizando presença (paused) após enviar parte do texto.'); await instance.client.sendPresenceUpdate('paused', remoteJid); } } } else { - this.logger.debug(`Enviando texto inteiro do buffer: ${textBuffer.trim()}`); + this.logger.debug(`[sendMessageWhatsapp] Enviando texto inteiro do buffer: ${textBuffer.trim()}`); await instance.textMessage( { number: remoteJid.split('@')[0], @@ -275,9 +373,9 @@ export class OpenaiService { } } - this.logger.debug(`Identificado arquivo de mídia do tipo: ${mediaType}`); + this.logger.debug(`[sendMessageWhatsapp] Identificado arquivo de mídia do tipo: ${mediaType}`); if (mediaType === 'audio') { - this.logger.debug('Enviando arquivo de áudio para o WhatsApp.'); + this.logger.debug('[sendMessageWhatsapp] Enviando arquivo de áudio para o WhatsApp.'); await instance.audioWhatsapp({ number: remoteJid.split('@')[0], delay: settings?.delayMessage || 1000, @@ -285,7 +383,7 @@ export class OpenaiService { caption: altText, }); } else { - this.logger.debug('Enviando arquivo de mídia (imagem, vídeo ou documento) para o WhatsApp.'); + this.logger.debug('[sendMessageWhatsapp] Enviando arquivo de mídia (imagem, vídeo ou documento) para o WhatsApp.'); await instance.mediaMessage( { number: remoteJid.split('@')[0], @@ -299,7 +397,7 @@ export class OpenaiService { ); } } else { - this.logger.debug('Não é um tipo de mídia suportado. Adicionando link no buffer de texto.'); + this.logger.debug('[sendMessageWhatsapp] Não é um tipo de mídia suportado. Adicionando link no buffer de texto.'); textBuffer += `[${altText}](${url})`; } @@ -329,14 +427,14 @@ export class OpenaiService { const delay = Math.min(Math.max(message.length * timePerChar, minDelay), maxDelay); if (instance.integration === Integration.WHATSAPP_BAILEYS) { - this.logger.debug('Atualizando presença (composing) antes de enviar resto do texto em partes.'); + this.logger.debug('[sendMessageWhatsapp] Atualizando presença (composing) antes de enviar resto do texto em partes.'); await instance.client.presenceSubscribe(remoteJid); await instance.client.sendPresenceUpdate('composing', remoteJid); } await new Promise((resolve) => { setTimeout(async () => { - this.logger.debug(`Enviando texto (splitMessage): ${message}`); + this.logger.debug(`[sendMessageWhatsapp] Enviando texto (splitMessage): ${part}`); await instance.textMessage( { number: remoteJid.split('@')[0], @@ -350,12 +448,12 @@ export class OpenaiService { }); if (instance.integration === Integration.WHATSAPP_BAILEYS) { - this.logger.debug('Atualizando presença (paused) após enviar parte final do texto.'); + this.logger.debug('[sendMessageWhatsapp] Atualizando presença (paused) após enviar parte final do texto.'); await instance.client.sendPresenceUpdate('paused', remoteJid); } } } else { - this.logger.debug(`Enviando todo o texto restante no buffer: ${textBuffer.trim()}`); + this.logger.debug(`[sendMessageWhatsapp] Enviando todo o texto restante no buffer: ${textBuffer.trim()}`); await instance.textMessage( { number: remoteJid.split('@')[0], @@ -368,10 +466,10 @@ export class OpenaiService { } } - this.logger.debug('Enviando telemetria após envio de texto.'); + this.logger.debug('[sendMessageWhatsapp] Enviando telemetria após envio de texto.'); sendTelemetry('/message/sendText'); - this.logger.debug(`Atualizando sessão (id: ${session.id}) para 'opened' e 'awaitUser: true'.`); + this.logger.debug(`[sendMessageWhatsapp] Atualizando sessão (id: ${session.id}) para 'opened' e 'awaitUser: true'.`); await this.prismaRepository.integrationSession.update({ where: { id: session.id, @@ -384,11 +482,11 @@ export class OpenaiService { } public async createAssistantNewSession(instance: InstanceDto, data: any) { - this.logger.debug('Iniciando criação de nova sessão do Assistant (createAssistantNewSession).'); - this.logger.debug(`Dados recebidos: ${JSON.stringify(data)}`); + this.logger.debug('[createAssistantNewSession] Iniciando criação de nova sessão do Assistant.'); + this.logger.debug(`[createAssistantNewSession] Dados recebidos: ${JSON.stringify(data)}`); if (data.remoteJid === 'status@broadcast') { - this.logger.debug('remoteJid é status@broadcast, abortando criação de sessão.'); + this.logger.debug('[createAssistantNewSession] remoteJid é status@broadcast, abortando criação de sessão.'); return; } @@ -399,23 +497,23 @@ export class OpenaiService { }); if (!creds) { - this.logger.error('Openai Creds não encontrados, lançando erro.'); + this.logger.error('[createAssistantNewSession] Openai Creds não encontrados, lançando erro.'); throw new Error('Openai Creds not found'); } try { - this.logger.debug('Instanciando cliente OpenAI para Assistant.'); + this.logger.debug('[createAssistantNewSession] Instanciando cliente OpenAI para Assistant.'); this.client = new OpenAI({ apiKey: creds.apiKey, }); - this.logger.debug('Criando thread (beta.threads.create).'); + this.logger.debug('[createAssistantNewSession] Criando thread (beta.threads.create).'); const thread = await this.client.beta.threads.create({}); const threadId = thread.id; let session = null; if (threadId) { - this.logger.debug('Thread criada com sucesso. Salvando sessão no banco de dados.'); + this.logger.debug('[createAssistantNewSession] Thread criada com sucesso. Salvando sessão no banco de dados.'); session = await this.prismaRepository.integrationSession.create({ data: { remoteJid: data.remoteJid, @@ -431,7 +529,7 @@ export class OpenaiService { } return { session }; } catch (error) { - this.logger.error(`Erro ao criar nova sessão do Assistant: ${error}`); + this.logger.error(`[createAssistantNewSession] Erro ao criar nova sessão do Assistant: ${error}`); return; } } @@ -446,8 +544,8 @@ export class OpenaiService { session: IntegrationSession, content: string, ) { - this.logger.debug('Iniciando sessão do Assistant (initAssistantNewSession).'); - this.logger.debug(`RemoteJid: ${remoteJid}, PushName: ${pushName}, Content: ${content}`); + this.logger.debug('[initAssistantNewSession] Iniciando sessão do Assistant.'); + this.logger.debug(`[initAssistantNewSession] RemoteJid: ${remoteJid}, PushName: ${pushName}, Content: ${content}`); const data = await this.createAssistantNewSession(instance, { remoteJid, @@ -458,10 +556,10 @@ export class OpenaiService { if (data.session) { session = data.session; - this.logger.debug(`Sessão criada com sucesso. ID: ${session.id}`); + this.logger.debug(`[initAssistantNewSession] Sessão criada com sucesso. ID: ${session.id}`); } - this.logger.debug('Enviando mensagem para Assistant para iniciar conversa.'); + this.logger.debug('[initAssistantNewSession] Enviando mensagem para Assistant para iniciar conversa.'); const message = await this.sendMessageToAssistant( instance, openaiBot, @@ -472,9 +570,9 @@ export class OpenaiService { session.sessionId, ); - this.logger.debug(`Retorno do Assistant: ${message}`); + this.logger.debug(`[initAssistantNewSession] Retorno do Assistant: ${message}`); if (message) { - this.logger.debug('Enviando mensagem do Assistant para WhatsApp.'); + this.logger.debug('[initAssistantNewSession] Enviando mensagem do Assistant para WhatsApp.'); await this.sendMessageWhatsapp(instance, session, remoteJid, settings, message); } @@ -497,12 +595,12 @@ export class OpenaiService { remoteJid: string, pushName: string, ) { - this.logger.debug(`Consultando run do Assistant (getAIResponse). ThreadId: ${threadId}, RunId: ${runId}`); + this.logger.debug(`[getAIResponse] Consultando run do Assistant. ThreadId: ${threadId}, RunId: ${runId}`); const getRun = await this.client.beta.threads.runs.retrieve(threadId, runId); let toolCalls; switch (getRun.status) { case 'requires_action': - this.logger.debug('Run requer ação (requires_action). Verificando chamadas de ferramenta (tool_calls).'); + this.logger.debug('[getAIResponse] Run requer ação. Verificando chamadas de ferramenta (tool_calls).'); toolCalls = getRun?.required_action?.submit_tool_outputs?.tool_calls; if (toolCalls) { @@ -514,7 +612,7 @@ export class OpenaiService { : toolCall?.function?.arguments; let output = null; - this.logger.debug(`Chamando função externa: ${functionName} com argumentos:`, functionArgument); + this.logger.debug(`[getAIResponse] Chamando função externa: ${functionName} com argumentos:`, functionArgument); try { const { data } = await axios.post(functionUrl, { @@ -529,9 +627,9 @@ export class OpenaiService { .replace(/\n/g, '\\n') .replace(/\r/g, '\\r') .replace(/\t/g, '\\t'); - this.logger.debug(`Resposta da função externa (${functionName}):`, data); + this.logger.debug(`[getAIResponse] Resposta da função externa (${functionName}):`, data); } catch (error) { - this.logger.error(`Erro ao chamar função externa (${functionName}):`, error); + this.logger.error(`[getAIResponse] Erro ao chamar função externa (${functionName}):`, error); output = JSON.stringify(error) .replace(/\\/g, '\\\\') .replace(/"/g, '\\"') @@ -540,7 +638,7 @@ export class OpenaiService { .replace(/\t/g, '\\t'); } - this.logger.debug('Submetendo output para a run do Assistant (submitToolOutputs).'); + this.logger.debug('[getAIResponse] Submetendo output para a run do Assistant (submitToolOutputs).'); await this.client.beta.threads.runs.submitToolOutputs(threadId, runId, { tool_outputs: [ { @@ -552,18 +650,18 @@ export class OpenaiService { } } - this.logger.debug('Repetindo chamada getAIResponse até status diferente de requires_action.'); + this.logger.debug('[getAIResponse] Repetindo chamada getAIResponse até status diferente de requires_action.'); return this.getAIResponse(threadId, runId, functionUrl, remoteJid, pushName); case 'queued': - this.logger.debug('Run está em fila (queued). Aguardando 1 segundo antes de tentar novamente.'); + this.logger.debug('[getAIResponse] Run está em fila (queued). Aguardando 1 segundo antes de tentar novamente.'); await new Promise((resolve) => setTimeout(resolve, 1000)); return this.getAIResponse(threadId, runId, functionUrl, remoteJid, pushName); case 'in_progress': - this.logger.debug('Run está em progresso (in_progress). Aguardando 1 segundo antes de tentar novamente.'); + this.logger.debug('[getAIResponse] Run está em progresso (in_progress). Aguardando 1 segundo antes de tentar novamente.'); await new Promise((resolve) => setTimeout(resolve, 1000)); return this.getAIResponse(threadId, runId, functionUrl, remoteJid, pushName); case 'completed': - this.logger.debug('Run concluída (completed). Recuperando última mensagem.'); + this.logger.debug('[getAIResponse] Run concluída (completed). Recuperando última mensagem.'); return await this.client.beta.threads.messages.list(threadId, { run_id: runId, limit: 1, @@ -585,27 +683,27 @@ export class OpenaiService { settings: OpenaiSetting, content: string, ) { - this.logger.debug('Processando mensagem para o Assistant (processOpenaiAssistant).'); + this.logger.debug('[processOpenaiAssistant] Processando mensagem para o Assistant.'); this.logger.debug( - `RemoteJid: ${remoteJid}, pushName: ${pushName}, fromMe: ${fromMe}, content: ${content}`, + `[processOpenaiAssistant] RemoteJid: ${remoteJid}, pushName: ${pushName}, fromMe: ${fromMe}, content: ${content}`, ); if (session && session.status === 'closed') { - this.logger.debug('A sessão está fechada, não será processada.'); + this.logger.debug('[processOpenaiAssistant] A sessão está fechada, não será processada.'); return; } if (session && settings.expire && settings.expire > 0) { - this.logger.debug('Verificando tempo de expiração da sessão...'); + this.logger.debug('[processOpenaiAssistant] Verificando tempo de expiração da sessão...'); const now = Date.now(); const sessionUpdatedAt = new Date(session.updatedAt).getTime(); const diff = now - sessionUpdatedAt; const diffInMinutes = Math.floor(diff / 1000 / 60); if (diffInMinutes > settings.expire) { - this.logger.debug(`Sessão expirada há ${diffInMinutes} minutos.`); + this.logger.debug(`[processOpenaiAssistant] Sessão expirada há ${diffInMinutes} minutos.`); if (settings.keepOpen) { - this.logger.debug('Atualizando status da sessão para CLOSED.'); + this.logger.debug('[processOpenaiAssistant] Atualizando status da sessão para CLOSED.'); await this.prismaRepository.integrationSession.update({ where: { id: session.id, @@ -615,7 +713,7 @@ export class OpenaiService { }, }); } else { - this.logger.debug('Deletando sessão do banco de dados.'); + this.logger.debug('[processOpenaiAssistant] Deletando sessão do banco de dados.'); await this.prismaRepository.integrationSession.deleteMany({ where: { botId: openaiBot.id, @@ -624,7 +722,7 @@ export class OpenaiService { }); } - this.logger.debug('Recriando nova sessão de Assistant...'); + this.logger.debug('[processOpenaiAssistant] Recriando nova sessão de Assistant...'); await this.initAssistantNewSession( instance, remoteJid, @@ -640,13 +738,13 @@ export class OpenaiService { } if (!session) { - this.logger.debug('Nenhuma sessão ativa encontrada, criando nova sessão de Assistant...'); + this.logger.debug('[processOpenaiAssistant] Nenhuma sessão ativa encontrada, criando nova sessão de Assistant...'); await this.initAssistantNewSession(instance, remoteJid, pushName, fromMe, openaiBot, settings, session, content); return; } if (session.status !== 'paused') { - this.logger.debug('Marcando sessão como aberta e awaitUser = false.'); + this.logger.debug('[processOpenaiAssistant] Marcando sessão como aberta e awaitUser = false.'); await this.prismaRepository.integrationSession.update({ where: { id: session.id, @@ -659,9 +757,9 @@ export class OpenaiService { } if (!content) { - this.logger.debug('Não há conteúdo na mensagem. Verificando se existe unknownMessage para retorno.'); + this.logger.debug('[processOpenaiAssistant] Não há conteúdo na mensagem. Verificando se existe unknownMessage para retorno.'); if (settings.unknownMessage) { - this.logger.debug(`Enviando unknownMessage para o remoteJid: ${remoteJid}`); + this.logger.debug(`[processOpenaiAssistant] Enviando unknownMessage para o remoteJid: ${remoteJid}`); this.waMonitor.waInstances[instance.instanceName].textMessage( { number: remoteJid.split('@')[0], @@ -676,7 +774,7 @@ export class OpenaiService { } if (settings.keywordFinish && content.toLowerCase() === settings.keywordFinish.toLowerCase()) { - this.logger.debug('Keyword finish detectada. Encerrando sessão.'); + this.logger.debug('[processOpenaiAssistant] Keyword finish detectada. Encerrando sessão.'); if (settings.keepOpen) { await this.prismaRepository.integrationSession.update({ where: { @@ -697,7 +795,7 @@ export class OpenaiService { return; } - this.logger.debug('Buscando OpenaiCreds no banco...'); + this.logger.debug('[processOpenaiAssistant] Buscando OpenaiCreds no banco...'); const creds = await this.prismaRepository.openaiCreds.findFirst({ where: { id: openaiBot.openaiCredsId, @@ -705,17 +803,17 @@ export class OpenaiService { }); if (!creds) { - this.logger.error('Openai Creds não encontrados, lançando erro.'); + this.logger.error('[processOpenaiAssistant] Openai Creds não encontrados, lançando erro.'); throw new Error('Openai Creds not found'); } - this.logger.debug('Instanciando cliente OpenAI para processar a mensagem no Assistant.'); + this.logger.debug('[processOpenaiAssistant] Instanciando cliente OpenAI para processar a mensagem no Assistant.'); this.client = new OpenAI({ apiKey: creds.apiKey, }); const threadId = session.sessionId; - this.logger.debug(`Enviando mensagem ao Assistant (threadId: ${threadId}).`); + this.logger.debug(`[processOpenaiAssistant] Enviando mensagem ao Assistant (threadId: ${threadId}).`); const message = await this.sendMessageToAssistant( instance, openaiBot, @@ -727,7 +825,7 @@ export class OpenaiService { ); if (message) { - this.logger.debug(`Resposta do Assistant recebida. Enviando para WhatsApp: ${message}`); + this.logger.debug(`[processOpenaiAssistant] Resposta do Assistant recebida. Enviando para WhatsApp: ${message}`); await this.sendMessageWhatsapp(instance, session, remoteJid, settings, message); } @@ -735,16 +833,16 @@ export class OpenaiService { } public async createChatCompletionNewSession(instance: InstanceDto, data: any) { - this.logger.debug('Iniciando criação de nova sessão de chatCompletion (createChatCompletionNewSession).'); - this.logger.debug(`Dados recebidos: ${JSON.stringify(data)}`); + this.logger.debug('[createChatCompletionNewSession] Iniciando criação de nova sessão de chatCompletion.'); + this.logger.debug(`[createChatCompletionNewSession] Dados recebidos: ${JSON.stringify(data)}`); if (data.remoteJid === 'status@broadcast') { - this.logger.debug('remoteJid é status@broadcast, abortando criação de sessão.'); + this.logger.debug('[createChatCompletionNewSession] remoteJid é status@broadcast, abortando criação de sessão.'); return; } const id = Math.floor(Math.random() * 10000000000).toString(); - this.logger.debug(`Gerando ID pseudo-aleatório da sessão: ${id}`); + this.logger.debug(`[createChatCompletionNewSession] Gerando ID pseudo-aleatório da sessão: ${id}`); const creds = await this.prismaRepository.openaiCreds.findFirst({ where: { @@ -753,12 +851,12 @@ export class OpenaiService { }); if (!creds) { - this.logger.error('Openai Creds não encontrados, lançando erro.'); + this.logger.error('[createChatCompletionNewSession] Openai Creds não encontrados, lançando erro.'); throw new Error('Openai Creds not found'); } try { - this.logger.debug('Criando sessão no banco de dados.'); + this.logger.debug('[createChatCompletionNewSession] Criando sessão no banco de dados.'); const session = await this.prismaRepository.integrationSession.create({ data: { remoteJid: data.remoteJid, @@ -774,7 +872,7 @@ export class OpenaiService { return { session, creds }; } catch (error) { - this.logger.error(`Erro ao criar nova sessão de chatCompletion: ${error}`); + this.logger.error(`[createChatCompletionNewSession] Erro ao criar nova sessão de chatCompletion: ${error}`); return; } } @@ -788,8 +886,8 @@ export class OpenaiService { session: IntegrationSession, content: string, ) { - this.logger.debug('Iniciando sessão de chatCompletion (initChatCompletionNewSession).'); - this.logger.debug(`RemoteJid: ${remoteJid}, PushName: ${pushName}, Content: ${content}`); + this.logger.debug('[initChatCompletionNewSession] Iniciando sessão de chatCompletion.'); + this.logger.debug(`[initChatCompletionNewSession] RemoteJid: ${remoteJid}, PushName: ${pushName}, Content: ${content}`); const data = await this.createChatCompletionNewSession(instance, { remoteJid, @@ -800,18 +898,18 @@ export class OpenaiService { session = data.session; const creds = data.creds; - this.logger.debug(`Sessão criada com sucesso (ID: ${session.id}). Instanciando cliente OpenAI.`); + this.logger.debug(`[initChatCompletionNewSession] Sessão criada com sucesso (ID: ${session.id}). Instanciando cliente OpenAI.`); this.client = new OpenAI({ apiKey: creds.apiKey, }); - this.logger.debug('Enviando mensagem para o Bot usando chatCompletion.'); + this.logger.debug('[initChatCompletionNewSession] Enviando mensagem para o Bot usando chatCompletion.'); const message = await this.sendMessageToBot(instance, openaiBot, remoteJid, content); - this.logger.debug(`Resposta do Bot: ${message}`); + this.logger.debug(`[initChatCompletionNewSession] Resposta do Bot: ${message}`); if (message) { - this.logger.debug('Enviando resposta para o WhatsApp.'); + this.logger.debug('[initChatCompletionNewSession] Enviando resposta para o WhatsApp.'); await this.sendMessageWhatsapp(instance, session, remoteJid, settings, message); } @@ -833,21 +931,21 @@ export class OpenaiService { ); if (session && session.status !== 'opened') { - this.logger.debug('Sessão existente não está aberta. Não será processado.'); + this.logger.debug('[processOpenaiChatCompletion] Sessão existente não está aberta. Não será processado.'); return; } if (session && settings.expire && settings.expire > 0) { - this.logger.debug('Verificando tempo de expiração da sessão...'); + this.logger.debug('[processOpenaiChatCompletion] Verificando tempo de expiração da sessão...'); const now = Date.now(); const sessionUpdatedAt = new Date(session.updatedAt).getTime(); const diff = now - sessionUpdatedAt; const diffInMinutes = Math.floor(diff / 1000 / 60); if (diffInMinutes > settings.expire) { - this.logger.debug(`Sessão expirada há ${diffInMinutes} minutos.`); + this.logger.debug(`[processOpenaiChatCompletion] Sessão expirada há ${diffInMinutes} minutos.`); if (settings.keepOpen) { - this.logger.debug('Atualizando status da sessão para CLOSED.'); + this.logger.debug('[processOpenaiChatCompletion] Atualizando status da sessão para CLOSED.'); await this.prismaRepository.integrationSession.update({ where: { id: session.id, @@ -857,7 +955,7 @@ export class OpenaiService { }, }); } else { - this.logger.debug('Deletando sessão do banco de dados.'); + this.logger.debug('[processOpenaiChatCompletion] Deletando sessão do banco de dados.'); await this.prismaRepository.integrationSession.deleteMany({ where: { botId: openaiBot.id, @@ -866,19 +964,19 @@ export class OpenaiService { }); } - this.logger.debug('Recriando nova sessão de chatCompletion...'); + this.logger.debug('[processOpenaiChatCompletion] Recriando nova sessão de chatCompletion...'); await this.initChatCompletionNewSession(instance, remoteJid, pushName, openaiBot, settings, session, content); return; } } if (!session) { - this.logger.debug('Nenhuma sessão encontrada. Criando nova sessão de chatCompletion...'); + this.logger.debug('[processOpenaiChatCompletion] Nenhuma sessão encontrada. Criando nova sessão de chatCompletion...'); await this.initChatCompletionNewSession(instance, remoteJid, pushName, openaiBot, settings, session, content); return; } - this.logger.debug('Marcando sessão como aberta e awaitUser = false.'); + this.logger.debug('[processOpenaiChatCompletion] Marcando sessão como aberta e awaitUser = false.'); await this.prismaRepository.integrationSession.update({ where: { id: session.id, @@ -890,9 +988,9 @@ export class OpenaiService { }); if (!content) { - this.logger.debug('Não há conteúdo na mensagem. Verificando se existe unknownMessage para retorno.'); + this.logger.debug('[processOpenaiChatCompletion] Não há conteúdo na mensagem. Verificando se existe unknownMessage para retorno.'); if (settings.unknownMessage) { - this.logger.debug(`Enviando unknownMessage para o remoteJid: ${remoteJid}`); + this.logger.debug(`[processOpenaiChatCompletion] Enviando unknownMessage para o remoteJid: ${remoteJid}`); this.waMonitor.waInstances[instance.instanceName].textMessage( { number: remoteJid.split('@')[0], @@ -907,7 +1005,7 @@ export class OpenaiService { } if (settings.keywordFinish && content.toLowerCase() === settings.keywordFinish.toLowerCase()) { - this.logger.debug('Keyword finish detectada. Encerrando sessão.'); + this.logger.debug('[processOpenaiChatCompletion] Keyword finish detectada. Encerrando sessão.'); if (settings.keepOpen) { await this.prismaRepository.integrationSession.update({ where: { @@ -928,7 +1026,7 @@ export class OpenaiService { return; } - this.logger.debug('Buscando OpenaiCreds no banco...'); + this.logger.debug('[processOpenaiChatCompletion] Buscando OpenaiCreds no banco...'); const creds = await this.prismaRepository.openaiCreds.findFirst({ where: { id: openaiBot.openaiCredsId, @@ -936,21 +1034,21 @@ export class OpenaiService { }); if (!creds) { - this.logger.error('Openai Creds não encontrados, lançando erro.'); + this.logger.error('[processOpenaiChatCompletion] Openai Creds não encontrados, lançando erro.'); throw new Error('Openai Creds not found'); } - this.logger.debug('Instanciando cliente OpenAI para processar a mensagem (ChatCompletion).'); + this.logger.debug('[processOpenaiChatCompletion] Instanciando cliente OpenAI para processar a mensagem (ChatCompletion).'); this.client = new OpenAI({ apiKey: creds.apiKey, }); - this.logger.debug('Enviando mensagem para o Bot usando chatCompletion.'); + this.logger.debug('[processOpenaiChatCompletion] Enviando mensagem para o Bot usando chatCompletion.'); const message = await this.sendMessageToBot(instance, openaiBot, remoteJid, content); - this.logger.debug(`Resposta do Bot: ${message}`); + this.logger.debug(`[processOpenaiChatCompletion] Resposta do Bot: ${message}`); if (message) { - this.logger.debug('Enviando resposta para o WhatsApp.'); + this.logger.debug('[processOpenaiChatCompletion] Enviando resposta para o WhatsApp.'); await this.sendMessageWhatsapp(instance, session, remoteJid, settings, message); } @@ -958,17 +1056,17 @@ export class OpenaiService { } public async speechToText(creds: OpenaiCreds, msg: any, updateMediaMessage: any) { - this.logger.debug('Iniciando conversão de fala em texto (speechToText).'); + this.logger.debug('[speechToText] Iniciando conversão de fala em texto.'); let audio; if (msg?.message?.mediaUrl) { - this.logger.debug('Baixando áudio via URL (mediaUrl).'); + this.logger.debug('[speechToText] Baixando áudio via URL (mediaUrl).'); audio = await axios.get(msg.message.mediaUrl, { responseType: 'arraybuffer' }).then((response) => { return Buffer.from(response.data, 'binary'); }); } else { - this.logger.debug('Baixando áudio via downloadMediaMessage (baileys).'); + this.logger.debug('[speechToText] Baixando áudio via downloadMediaMessage (baileys).'); audio = await downloadMediaMessage( { key: msg.key, message: msg?.message }, 'buffer', @@ -983,14 +1081,14 @@ export class OpenaiService { const lang = this.configService.get('LANGUAGE').includes('pt') ? 'pt' : this.configService.get('LANGUAGE'); - this.logger.debug(`Definindo idioma da transcrição como: ${lang}`); + this.logger.debug(`[speechToText] Definindo idioma da transcrição como: ${lang}`); const formData = new FormData(); formData.append('file', audio, 'audio.ogg'); formData.append('model', 'whisper-1'); formData.append('language', lang); - this.logger.debug('Enviando requisição POST para a API de transcrição do OpenAI.'); + this.logger.debug('[speechToText] Enviando requisição POST para a API de transcrição do OpenAI.'); const response = await axios.post('https://api.openai.com/v1/audio/transcriptions', formData, { headers: { 'Content-Type': 'multipart/form-data', @@ -998,7 +1096,7 @@ export class OpenaiService { }, }); - this.logger.debug(`Status da requisição: ${response.status}`); + this.logger.debug(`[speechToText] Status da requisição: ${response.status}`); return response?.data?.text; } }