From 74e0a01f6ae8ca8763a42bc246c69456d600039f Mon Sep 17 00:00:00 2001 From: Rodrigo Rodriguez Date: Sat, 18 Dec 2021 21:31:49 -0300 Subject: [PATCH] new(whatsapp.gblib): Bot in groups. --- .../services/GBConversationalService.ts | 14 ++-- packages/core.gbapp/services/GBMinService.ts | 33 +++++--- .../dialogs/FeedbackDialog.ts | 13 ++- .../services/WhatsappDirectLine.ts | 81 ++++++++++++------- 4 files changed, 89 insertions(+), 52 deletions(-) diff --git a/packages/core.gbapp/services/GBConversationalService.ts b/packages/core.gbapp/services/GBConversationalService.ts index a204851a..65ccc36c 100644 --- a/packages/core.gbapp/services/GBConversationalService.ts +++ b/packages/core.gbapp/services/GBConversationalService.ts @@ -286,9 +286,9 @@ export class GBConversationalService { }); } - public async sendToMobile(min: GBMinInstance, mobile: string, message: string) { + public async sendToMobile(min: GBMinInstance, mobile: string, message: string, conversationId ) { GBLog.info(`Sending message ${message} to ${mobile}...`); - await min.whatsAppDirectLine.sendToDevice(mobile, message); + await min.whatsAppDirectLine.sendToDevice(mobile, message, conversationId); } public static async getTextFromAudioBuffer(speechKey, cloudRegion, buffer, locale): Promise { @@ -510,7 +510,7 @@ export class GBConversationalService { if (!mobile) { await step.context.sendActivity(currentText); } else { - await this.sendToMobile(min, mobile, currentText); + await this.sendToMobile(min, mobile, currentText, step.context.activity.conversation.id); } await sleep(3000); currentText = ''; @@ -530,7 +530,7 @@ export class GBConversationalService { if (!mobile) { await step.context.sendActivity(currentText); } else { - await this.sendToMobile(min, mobile, currentText); + await this.sendToMobile(min, mobile, currentText, step.context.activity.conversation.id); } await sleep(3000); } @@ -563,7 +563,7 @@ export class GBConversationalService { if (!mobile) { await step.context.sendActivity(currentText); } else { - await this.sendToMobile(min, mobile, currentText); + await this.sendToMobile(min, mobile, currentText, step.context.activity.conversation.id); } await sleep(2900); } @@ -608,7 +608,7 @@ export class GBConversationalService { await step.context.sendActivity(currentText); } else { GBLog.info(`Sending .MD file to mobile: ${mobile}.`); - await this.sendToMobile(min, mobile, currentText); + await this.sendToMobile(min, mobile, currentText, step.context.activity.conversation.id); } } } @@ -888,7 +888,7 @@ export class GBConversationalService { analytics.createMessage(min.instance.instanceId, user.conversation, null, text); if (!isNaN(member.id) && !member.id.startsWith('1000')) { - await min.whatsAppDirectLine.sendToDevice(member.id, text); + await min.whatsAppDirectLine.sendToDevice(member.id, text, step.context.activity.conversation.id); } else { await step.context.sendActivity(text); } diff --git a/packages/core.gbapp/services/GBMinService.ts b/packages/core.gbapp/services/GBMinService.ts index 68ddb47b..78225fa6 100644 --- a/packages/core.gbapp/services/GBMinService.ts +++ b/packages/core.gbapp/services/GBMinService.ts @@ -173,7 +173,7 @@ export class GBMinService { }); GBLog.info(`Package deployment done.`); - + } @@ -302,17 +302,22 @@ export class GBMinService { private async WhatsAppCallback(req, res) { try { - // Detects if the message is echo fro itself. + // Detects if the message is echo from itself. - const id = req.body.messages[0].chatId.split('@')[0]; + const id = req.body.messages[0].author.split('@')[0]; const senderName = req.body.messages[0].senderName; - const text = req.body.messages[0].body; + if (req.body.messages[0].fromMe) { res.end(); return; // Exit here. } + // Processes group behaviour. + + let text = req.body.messages[0].body; + text = text.replace(/\@\d+ /gi, ''); + // Detects if the welcome message is enabled. let activeMin; @@ -358,7 +363,7 @@ export class GBMinService { await (activeMin as any).whatsAppDirectLine.sendToDevice( id, `Olá! Seja bem-vinda(o)!\nMe chamo ${activeMin.instance.title}. Como posso ajudar? Pode me falar que eu te ouço, me manda um aúdio.` - ); + , null); res.end(); } } else { @@ -383,8 +388,11 @@ export class GBMinService { } else { await (activeMin as any).whatsAppDirectLine.sendToDevice( id, - `Agora falando com ${activeMin.instance.title}...` + `Agora falando com ${activeMin.instance.title}...`, + null ); + + } res.end(); } else { @@ -815,6 +823,9 @@ export class GBMinService { await adapter['processActivity'](req, res, async context => { + context.activity.text = context.activity.text.replace(/\@General Bots Online /gi, ''); + + // Get loaded user state const step = await min.dialogs.createContext(context); @@ -887,7 +898,7 @@ export class GBMinService { if (step.context.activity.channelId === 'msteams') { if (step.context.activity.attachments && step.context.activity.attachments.length > 1) { - + const file = context.activity.attachments[0]; const credentials = new MicrosoftAppCredentials(min.instance.marketplaceId, min.instance.marketplacePassword); const botToken = await credentials.getToken(); @@ -895,10 +906,9 @@ export class GBMinService { const t = new SystemKeywords(null, null, null); const data = await t.getByHttp(file.contentUrl, headers, null, null, null, true); const folder = `work/${min.instance.botId}.gbai/cache`; - const filename =`${GBAdminService.generateUuid()}.png`; + const filename = `${GBAdminService.generateUuid()}.png`; - if (!Fs.existsSync(folder)) - { + if (!Fs.existsSync(folder)) { Fs.mkdirSync(folder); } @@ -1268,7 +1278,8 @@ export class GBMinService { } } else { - await min.whatsAppDirectLine.sendToDeviceEx(manualUser.userSystemId, `${manualUser.agentSystemId}: ${text}`, locale); + await min.whatsAppDirectLine.sendToDeviceEx(manualUser.userSystemId, `${manualUser.agentSystemId}: ${text}`, locale, + step.context.activity.conversation.id); } } else { diff --git a/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts b/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts index e0115c5b..47425d08 100644 --- a/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts +++ b/packages/customer-satisfaction.gbapp/dialogs/FeedbackDialog.ts @@ -130,14 +130,15 @@ export class FeedbackDialog extends IGBDialog { const manualUser = await sec.getUserFromAgentSystemId(userSystemId); await min.whatsAppDirectLine.sendToDeviceEx(manualUser.userSystemId, - Messages[locale].notify_end_transfer(min.instance.botId), locale); + Messages[locale].notify_end_transfer(min.instance.botId), locale, step.context.activity.conversation.id); if (userSystemId.charAt(2) === ":" || userSystemId.indexOf('@') > -1) { // Agent is from Teams or Google Chat. await min.conversationalService.sendText(min, step, Messages[locale].notify_end_transfer(min.instance.botId)); } else { await min.whatsAppDirectLine.sendToDeviceEx(userSystemId, - Messages[locale].notify_end_transfer(min.instance.botId), locale); + Messages[locale].notify_end_transfer(min.instance.botId), locale + , step.context.activity.conversation.id); } await sec.updateHumanAgent(userSystemId, min.instance.instanceId, null); @@ -152,7 +153,7 @@ export class FeedbackDialog extends IGBDialog { const agent = await sec.getUserFromSystemId(user.systemUser.agentSystemId); await min.whatsAppDirectLine.sendToDeviceEx(user.systemUser.userSystemId, - Messages[locale].notify_end_transfer(min.instance.botId), locale); + Messages[locale].notify_end_transfer(min.instance.botId), locale, step.context.activity.conversation.id); if (user.systemUser.agentSystemId.charAt(2) === ":" || userSystemId.indexOf('@') > -1) { // Agent is from Teams or Google Chat. @@ -160,7 +161,7 @@ export class FeedbackDialog extends IGBDialog { } else { await min.whatsAppDirectLine.sendToDeviceEx(user.systemUser.agentSystemId, - Messages[locale].notify_end_transfer(min.instance.botId), locale); + Messages[locale].notify_end_transfer(min.instance.botId), locale, step.context.activity.conversation.id); } await sec.updateHumanAgent(user.systemUser.userSystemId, min.instance.instanceId, null); @@ -177,12 +178,10 @@ export class FeedbackDialog extends IGBDialog { } else { await min.whatsAppDirectLine.sendToDeviceEx(user.systemUser.userSystemId, - 'Nenhum atendimento em andamento.'); + 'Nenhum atendimento em andamento.', locale, step.context.activity.conversation.id); } - } - return await step.next(); } ]) diff --git a/packages/whatsapp.gblib/services/WhatsappDirectLine.ts b/packages/whatsapp.gblib/services/WhatsappDirectLine.ts index 0afcc1ed..9a45f3bb 100644 --- a/packages/whatsapp.gblib/services/WhatsappDirectLine.ts +++ b/packages/whatsapp.gblib/services/WhatsappDirectLine.ts @@ -49,6 +49,8 @@ export class WhatsappDirectLine extends GBService { public static conversationIds = {}; public static mobiles = {}; + public static chatIds = {}; + public pollInterval = 5000; public directLineClientName = 'DirectLineClient'; @@ -87,7 +89,7 @@ export class WhatsappDirectLine extends GBService { } public async setup(setUrl) { - + this.directLineClient = new Swagger({ spec: JSON.parse(fs.readFileSync('directline-3.0.json', 'utf8')), @@ -130,8 +132,8 @@ export class WhatsappDirectLine extends GBService { } - public async resetConversationId(number) { - WhatsappDirectLine.conversationIds[number] = undefined; + public async resetConversationId(number, group) { + WhatsappDirectLine.conversationIds[number+group] = undefined; } public async check() { @@ -159,7 +161,27 @@ export class WhatsappDirectLine extends GBService { } const message = req.body.messages[0]; + let group = ""; + + + // Ignore group messages without the mention to Bot. + + if (message.chatName.charAt(0) !== '+') { + group = message.chatName; + + let smsServiceNumber = this.min.core.getParam(this.min.instance, 'whatsappServiceNumber', null);; + if (smsServiceNumber) { + smsServiceNumber = smsServiceNumber.replace('+', ''); + if (!message.body.startsWith('@' + smsServiceNumber)) { + return; + } + } + } + + let text = message.body; + text = text.replace(/\@\d+ /gi, ''); + const from = message.author.split('@')[0]; const fromName = message.senderName; @@ -174,7 +196,7 @@ export class WhatsappDirectLine extends GBService { await e.onExchangeData(this.min, 'whatsappMessage', message); }); - const id = req.body.messages[0].chatId.split('@')[0].replace('true_','').replace('false_',''); + const id = req.body.messages[0].chatId.split('@')[0].replace('true_', '').replace('false_', ''); const senderName = req.body.messages[0].senderName; const sec = new SecService(); @@ -199,11 +221,12 @@ export class WhatsappDirectLine extends GBService { buf, locale ); } else { - await this.sendToDevice(user.userSystemId, `No momento estou apenas conseguindo ler mensagens de texto.`); + await this.sendToDevice(user.userSystemId, + `No momento estou apenas conseguindo ler mensagens de texto.`, null); } } - const conversationId = WhatsappDirectLine.conversationIds[from]; + const conversationId = WhatsappDirectLine.conversationIds[from + group]; const client = await this.directLineClient; @@ -218,7 +241,7 @@ export class WhatsappDirectLine extends GBService { if (manualUser === null) { await sec.updateHumanAgent(id, this.min.instance.instanceId, null); - + } else { const agent = await sec.getUserFromSystemId(user.agentSystemId); @@ -229,28 +252,28 @@ export class WhatsappDirectLine extends GBService { if (message === null) { await this.sendToDeviceEx(user.userSystemId, `File ${filename} not found in any .gbkb published. Check the name or publish again the associated .gbkb.`, - locale); + locale, null); } else { await this.min.conversationalService.sendMarkdownToMobile(this.min, null, user.userSystemId, message); } } else if (text === '/qt') { // TODO: Transfers only in pt-br for now. await this.sendToDeviceEx(manualUser.userSystemId, - Messages[this.locale].notify_end_transfer(this.min.instance.botId), locale); + Messages[this.locale].notify_end_transfer(this.min.instance.botId), locale, null); if (user.agentSystemId.charAt(2) === ":") { // Agent is from Teams. await this.min.conversationalService['sendOnConversation'](this.min, agent, Messages[this.locale].notify_end_transfer(this.min.instance.botId)); } else { await this.sendToDeviceEx(user.agentSystemId, - Messages[this.locale].notify_end_transfer(this.min.instance.botId), locale); + Messages[this.locale].notify_end_transfer(this.min.instance.botId), locale, null); } await sec.updateHumanAgent(manualUser.userSystemId, this.min.instance.instanceId, null); await sec.updateHumanAgent(user.agentSystemId, this.min.instance.instanceId, null); } else { GBLog.info(`HUMAN AGENT (${manualUser.agentSystemId}) TO USER ${manualUser.userSystemId}: ${text}`); - await this.sendToDeviceEx(manualUser.userSystemId, `AGENTE: *${text}*`, locale); + await this.sendToDeviceEx(manualUser.userSystemId, `AGENTE: *${text}*`, locale, null); } } @@ -259,18 +282,18 @@ export class WhatsappDirectLine extends GBService { const agent = await sec.getUserFromSystemId(user.agentSystemId); if (text === '/t') { - await this.sendToDeviceEx(user.userSystemId, `Você já está sendo atendido por ${agent.userSystemId}.`, locale); + await this.sendToDeviceEx(user.userSystemId, `Você já está sendo atendido por ${agent.userSystemId}.`, locale, null); } else if (text === '/qt' || text === 'Sair' || text === 'Fechar') { // TODO: Transfers only in pt-br for now. await this.sendToDeviceEx(id, - Messages[this.locale].notify_end_transfer(this.min.instance.botId), locale); + Messages[this.locale].notify_end_transfer(this.min.instance.botId), locale, null); - if (user.agentSystemId.charAt(2) === ":") { // Agent is from Teams. - await this.min.conversationalService['sendOnConversation'](this.min, agent, Messages[this.locale].notify_end_transfer(this.min.instance.botId)); - } - else { - await this.sendToDeviceEx(user.agentSystemId, Messages[this.locale].notify_end_transfer(this.min.instance.botId), locale); - } + if (user.agentSystemId.charAt(2) === ":") { // Agent is from Teams. + await this.min.conversationalService['sendOnConversation'](this.min, agent, Messages[this.locale].notify_end_transfer(this.min.instance.botId)); + } + else { + await this.sendToDeviceEx(user.agentSystemId, Messages[this.locale].notify_end_transfer(this.min.instance.botId), locale, null); + } await sec.updateHumanAgent(id, this.min.instance.instanceId, null); } else { @@ -280,20 +303,21 @@ export class WhatsappDirectLine extends GBService { await this.min.conversationalService['sendOnConversation'](this.min, agent, text); } else { - await this.sendToDeviceEx(user.agentSystemId, `Bot: ${this.min.instance.botId}\n${id}: ${text}`, locale); + await this.sendToDeviceEx(user.agentSystemId, `Bot: ${this.min.instance.botId}\n${id}: ${text}`, locale, null); } } } else if (user.agentMode === 'bot' || user.agentMode === null || user.agentMode === undefined) { - if (WhatsappDirectLine.conversationIds[from] === undefined) { + if (WhatsappDirectLine.conversationIds[from + group] === undefined) { GBLog.info(`GBWhatsapp: Starting new conversation on Bot.`); const response = await client.Conversations.Conversations_StartConversation(); const generatedConversationId = response.obj.conversationId; - WhatsappDirectLine.conversationIds[from] = generatedConversationId; + WhatsappDirectLine.conversationIds[from + group] = generatedConversationId; WhatsappDirectLine.mobiles[generatedConversationId] = from; + WhatsappDirectLine.chatIds[generatedConversationId] = message.chatId; this.pollMessages(client, generatedConversationId, from, fromName); this.inputMessage(client, generatedConversationId, text, from, fromName); @@ -387,7 +411,7 @@ export class WhatsappDirectLine extends GBService { }); } - await this.sendToDevice(from, output); + await this.sendToDevice(from, output, conversationId); } public renderHeroCard(attachment) { @@ -454,7 +478,7 @@ export class WhatsappDirectLine extends GBService { await this.sendFileToDevice(to, url, 'Audio', msg); } - public async sendToDevice(to: string, msg: string) { + public async sendToDevice(to: string, msg: string, conversationId ) { const cmd = '/audio '; if (msg.startsWith(cmd)) { @@ -463,12 +487,15 @@ export class WhatsappDirectLine extends GBService { return await this.sendTextAsAudioToDevice(to, msg); } else { + let chatId = WhatsappDirectLine.chatIds[conversationId]; + const options = { method: 'POST', url: urlJoin(this.whatsappServiceUrl, 'message'), qs: { token: this.whatsappServiceKey, - phone: to, + phone: chatId ? null : to, + chatId: chatId, body: msg }, headers: { @@ -488,13 +515,13 @@ export class WhatsappDirectLine extends GBService { } } - public async sendToDeviceEx(to, text, locale) { + public async sendToDeviceEx(to, text, locale, conversationId) { text = await this.min.conversationalService.translate( this.min, text, locale ); - await this.sendToDevice(to, text); + await this.sendToDevice(to, text, conversationId); } }