2019-06-22 07:06:21 -03:00
|
|
|
/*****************************************************************************\
|
|
|
|
| ( )_ _ |
|
|
|
|
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
2020-07-01 15:00:40 -03:00
|
|
|
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
|
2019-06-22 07:06:21 -03:00
|
|
|
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
|
|
|
|
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
|
|
|
| | | ( )_) | |
|
|
|
|
| (_) \___/' |
|
|
|
|
| |
|
|
|
|
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
|
|
|
|
| Licensed under the AGPL-3.0. |
|
|
|
|
| |
|
|
|
|
| According to our dual licensing model, this program can be used either |
|
|
|
|
| under the terms of the GNU Affero General Public License, version 3, |
|
|
|
|
| or under a proprietary license. |
|
|
|
|
| |
|
|
|
|
| The texts of the GNU Affero General Public License with an additional |
|
|
|
|
| permission and of our proprietary license can be found at and |
|
|
|
|
| in the LICENSE file you have received along with this program. |
|
|
|
|
| |
|
|
|
|
| This program is distributed in the hope that it will be useful, |
|
|
|
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
|
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
|
|
| GNU Affero General Public License for more details. |
|
|
|
|
| |
|
|
|
|
| "General Bots" is a registered trademark of Pragmatismo.io. |
|
|
|
|
| The licensing of the program under the AGPLv3 does not imply a |
|
|
|
|
| trademark license. Therefore any rights, title and interest in |
|
|
|
|
| our trademarks remain entirely with us. |
|
|
|
|
| |
|
|
|
|
\*****************************************************************************/
|
|
|
|
|
2022-01-03 13:11:21 -03:00
|
|
|
const urlJoin = require('url-join');
|
2019-03-08 17:05:58 -03:00
|
|
|
|
2018-11-12 12:20:44 -02:00
|
|
|
const Swagger = require('swagger-client');
|
2020-05-02 21:28:13 -03:00
|
|
|
const fs = require('fs');
|
2020-12-31 15:36:19 -03:00
|
|
|
import { GBLog, GBMinInstance, GBService, IGBPackage } from 'botlib';
|
|
|
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
2018-11-12 12:20:44 -02:00
|
|
|
import * as request from 'request-promise-native';
|
2019-05-15 12:41:04 -03:00
|
|
|
import { GBServer } from '../../../src/app';
|
2020-04-13 19:14:55 -03:00
|
|
|
import { GBConversationalService } from '../../core.gbapp/services/GBConversationalService';
|
2020-07-26 16:46:37 -03:00
|
|
|
import { SecService } from '../../security.gbapp/services/SecService';
|
2020-05-02 21:28:13 -03:00
|
|
|
import { Messages } from '../strings';
|
2021-12-25 22:13:52 -03:00
|
|
|
import { KBService } from '../../kb.gbapp/services/KBService';
|
2018-11-12 12:20:44 -02:00
|
|
|
|
2019-03-09 16:59:31 -03:00
|
|
|
/**
|
|
|
|
* Support for Whatsapp.
|
|
|
|
*/
|
2018-05-07 20:45:11 -03:00
|
|
|
export class WhatsappDirectLine extends GBService {
|
2020-12-31 15:36:19 -03:00
|
|
|
|
|
|
|
public static conversationIds = {};
|
2021-10-13 09:39:24 -03:00
|
|
|
public static mobiles = {};
|
2021-12-18 21:31:49 -03:00
|
|
|
public static chatIds = {};
|
2021-12-31 09:39:23 -03:00
|
|
|
public static usernames = {};
|
2021-12-18 21:31:49 -03:00
|
|
|
|
2021-12-25 22:13:52 -03:00
|
|
|
public pollInterval = 3000;
|
2019-03-08 06:37:13 -03:00
|
|
|
public directLineClientName = 'DirectLineClient';
|
|
|
|
|
|
|
|
public directLineClient: any;
|
|
|
|
public whatsappServiceKey: string;
|
|
|
|
public whatsappServiceNumber: string;
|
|
|
|
public whatsappServiceUrl: string;
|
|
|
|
public botId: string;
|
2020-12-31 15:36:19 -03:00
|
|
|
public min: GBMinInstance;
|
2020-04-08 21:33:27 -03:00
|
|
|
private directLineSecret: string;
|
2020-05-02 21:28:13 -03:00
|
|
|
private locale: string = 'pt-BR';
|
2019-03-08 06:37:13 -03:00
|
|
|
|
|
|
|
constructor(
|
2020-04-13 19:14:55 -03:00
|
|
|
min: GBMinInstance,
|
2019-03-08 06:37:13 -03:00
|
|
|
botId,
|
|
|
|
directLineSecret,
|
|
|
|
whatsappServiceKey,
|
|
|
|
whatsappServiceNumber,
|
2019-06-17 15:22:13 -03:00
|
|
|
whatsappServiceUrl
|
2019-03-08 06:37:13 -03:00
|
|
|
) {
|
|
|
|
super();
|
|
|
|
|
2020-04-13 19:14:55 -03:00
|
|
|
this.min = min;
|
2019-03-08 06:37:13 -03:00
|
|
|
this.botId = botId;
|
2020-04-08 21:33:27 -03:00
|
|
|
this.directLineSecret = directLineSecret;
|
2019-03-08 06:37:13 -03:00
|
|
|
this.whatsappServiceKey = whatsappServiceKey;
|
|
|
|
this.whatsappServiceNumber = whatsappServiceNumber;
|
|
|
|
this.whatsappServiceUrl = whatsappServiceUrl;
|
|
|
|
|
2020-04-08 21:33:27 -03:00
|
|
|
}
|
|
|
|
|
2020-12-31 15:36:19 -03:00
|
|
|
public static async asyncForEach(array, callback) {
|
|
|
|
for (let index = 0; index < array.length; index++) {
|
|
|
|
await callback(array[index], index, array);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-15 01:42:54 +00:00
|
|
|
public async setup(setUrl) {
|
2021-12-18 21:31:49 -03:00
|
|
|
|
2020-04-08 21:33:27 -03:00
|
|
|
this.directLineClient =
|
2019-05-15 22:30:14 -03:00
|
|
|
new Swagger({
|
|
|
|
spec: JSON.parse(fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
|
|
usePromise: true
|
|
|
|
});
|
2020-12-31 15:36:19 -03:00
|
|
|
const client = await this.directLineClient;
|
2020-04-08 21:33:27 -03:00
|
|
|
|
|
|
|
client.clientAuthorizations.add(
|
|
|
|
'AuthorizationBotConnector',
|
|
|
|
new Swagger.ApiKeyAuthorization('Authorization', `Bearer ${this.directLineSecret}`, 'header')
|
|
|
|
);
|
|
|
|
|
|
|
|
const options = {
|
|
|
|
method: 'POST',
|
|
|
|
url: urlJoin(this.whatsappServiceUrl, 'webhook'),
|
2020-05-06 14:12:47 +00:00
|
|
|
timeout: 10000,
|
2020-04-08 21:33:27 -03:00
|
|
|
qs: {
|
|
|
|
token: this.whatsappServiceKey,
|
2022-01-09 19:17:03 -03:00
|
|
|
webhookUrl: `${GBServer.globals.publicAddress}/webhooks/whatsapp/${this.botId}`,
|
2020-04-08 21:33:27 -03:00
|
|
|
set: true
|
|
|
|
},
|
|
|
|
headers: {
|
|
|
|
'cache-control': 'no-cache'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-04-15 01:42:54 +00:00
|
|
|
if (setUrl) {
|
2020-04-28 20:54:04 -03:00
|
|
|
const express = require('express');
|
|
|
|
GBServer.globals.server.use(`/audios`, express.static('work'));
|
|
|
|
|
2020-12-31 15:36:19 -03:00
|
|
|
if (process.env.ENDPOINT_UPDATE === 'true') {
|
2020-06-04 13:44:02 -03:00
|
|
|
try {
|
2020-12-31 15:36:19 -03:00
|
|
|
const res = await request.post(options);
|
2020-06-04 13:44:02 -03:00
|
|
|
GBLog.info(res);
|
|
|
|
} catch (error) {
|
|
|
|
GBLog.error(`Error initializing 3rd party Whatsapp provider(1) ${error.message}`);
|
|
|
|
}
|
2020-04-15 01:42:54 +00:00
|
|
|
}
|
2020-04-08 21:33:27 -03:00
|
|
|
}
|
|
|
|
|
2019-03-08 06:37:13 -03:00
|
|
|
}
|
2018-05-07 20:45:11 -03:00
|
|
|
|
2021-12-27 15:41:54 -03:00
|
|
|
public async resetConversationId(number, group = '') {
|
2021-12-25 22:13:52 -03:00
|
|
|
WhatsappDirectLine.conversationIds[number + group] = undefined;
|
2020-04-15 01:42:54 +00:00
|
|
|
}
|
|
|
|
|
2020-05-12 19:20:59 -03:00
|
|
|
public async check() {
|
|
|
|
|
2020-05-12 19:41:51 -03:00
|
|
|
GBLog.info(`GBWhatsapp: Checking server...`);
|
2020-05-12 19:20:59 -03:00
|
|
|
|
|
|
|
const options = {
|
2020-05-16 16:40:44 -03:00
|
|
|
url: urlJoin(this.whatsappServiceUrl, 'status') + `?token=${this.min.instance.whatsappServiceKey}`,
|
2020-12-31 15:36:19 -03:00
|
|
|
method: 'GET'
|
2020-05-16 16:40:44 -03:00
|
|
|
|
2020-05-12 19:20:59 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
const res = await request(options);
|
2020-05-12 19:41:51 -03:00
|
|
|
const json = JSON.parse(res);
|
2020-12-31 15:36:19 -03:00
|
|
|
|
|
|
|
return json.accountStatus === 'authenticated';
|
2020-05-12 19:20:59 -03:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-06-28 11:17:41 -03:00
|
|
|
public async received(req, res) {
|
|
|
|
if (req.body.messages === undefined) {
|
|
|
|
res.end();
|
2020-12-31 15:36:19 -03:00
|
|
|
|
2019-06-28 11:17:41 -03:00
|
|
|
return; // Exit here.
|
|
|
|
}
|
|
|
|
|
2020-04-13 19:14:55 -03:00
|
|
|
const message = req.body.messages[0];
|
2021-12-18 21:31:49 -03:00
|
|
|
let group = "";
|
2021-12-25 22:13:52 -03:00
|
|
|
let answerText = null;
|
2021-12-18 21:31:49 -03:00
|
|
|
|
|
|
|
|
2020-04-13 19:14:55 -03:00
|
|
|
let text = message.body;
|
2021-12-18 21:31:49 -03:00
|
|
|
text = text.replace(/\@\d+ /gi, '');
|
|
|
|
|
2020-04-13 19:14:55 -03:00
|
|
|
const from = message.author.split('@')[0];
|
|
|
|
const fromName = message.senderName;
|
2021-12-25 22:13:52 -03:00
|
|
|
GBLog.info(`GBWhatsapp: RCV ${from}(${fromName}): ${text})`);
|
|
|
|
|
2018-05-12 13:40:34 -03:00
|
|
|
|
2019-03-08 06:37:13 -03:00
|
|
|
if (req.body.messages[0].fromMe) {
|
2019-06-28 11:17:41 -03:00
|
|
|
res.end();
|
2020-12-31 15:36:19 -03:00
|
|
|
|
2019-03-08 06:37:13 -03:00
|
|
|
return; // Exit here.
|
2018-05-12 13:40:34 -03:00
|
|
|
}
|
2021-12-25 22:13:52 -03:00
|
|
|
|
2021-12-27 15:41:54 -03:00
|
|
|
if (message.chatName.charAt(0) !== '+') {
|
2021-12-25 22:13:52 -03:00
|
|
|
group = message.chatName;
|
|
|
|
|
|
|
|
let botGroupName = this.min.core.getParam<string>(this.min.instance, 'WhatsApp Group Name', null);
|
|
|
|
let botShortcuts = this.min.core.getParam<string>(this.min.instance, 'WhatsApp Group Shortcuts', null);
|
|
|
|
if (!botShortcuts) {
|
|
|
|
botShortcuts = new Array()
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
botShortcuts = botShortcuts.split(' ');
|
|
|
|
}
|
|
|
|
|
|
|
|
const parts = text.split(' ');
|
|
|
|
|
|
|
|
// Bot name must be specified on config.
|
|
|
|
|
|
|
|
if (botGroupName === group) {
|
|
|
|
|
|
|
|
// Shortcut has been mentioned?
|
|
|
|
|
|
|
|
let found = false;
|
|
|
|
parts.forEach(e1 => {
|
|
|
|
botShortcuts.forEach(e2 => {
|
|
|
|
if (e1 === e2 && !found) {
|
|
|
|
found = true;
|
2021-12-27 15:41:54 -03:00
|
|
|
text = text.replace(e2, '');
|
2021-12-25 22:13:52 -03:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Verify if it is a group cache answer.
|
|
|
|
|
|
|
|
const questions = this.min['groupCache'];
|
|
|
|
if (questions && questions.length > 0) {
|
|
|
|
questions.forEach(q => {
|
|
|
|
if (q.content === e1 && !found) {
|
|
|
|
const answer = this.min.kbService['getAnswerById'](this.min.instance.instanceId,
|
|
|
|
q.answerId);
|
|
|
|
answerText = answer.content;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Ignore group messages without the mention to Bot.
|
|
|
|
|
|
|
|
let smsServiceNumber = this.min.core.getParam<string>(this.min.instance, 'whatsappServiceNumber', null);
|
|
|
|
if (smsServiceNumber && !answerText) {
|
|
|
|
smsServiceNumber = smsServiceNumber.replace('+', '');
|
|
|
|
if (!message.body.startsWith('@' + smsServiceNumber)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-08 06:37:13 -03:00
|
|
|
|
2020-12-14 09:28:12 -03:00
|
|
|
await CollectionUtil.asyncForEach(this.min.appPackages, async (e: IGBPackage) => {
|
2020-12-31 15:36:19 -03:00
|
|
|
await e.onExchangeData(this.min, 'whatsappMessage', message);
|
2020-06-12 15:55:18 -03:00
|
|
|
});
|
2020-12-14 09:28:12 -03:00
|
|
|
|
2021-12-18 21:31:49 -03:00
|
|
|
const id = req.body.messages[0].chatId.split('@')[0].replace('true_', '').replace('false_', '');
|
2020-05-17 22:36:00 +00:00
|
|
|
const senderName = req.body.messages[0].senderName;
|
2020-12-31 15:36:19 -03:00
|
|
|
const sec = new SecService();
|
2020-05-17 22:36:00 +00:00
|
|
|
|
|
|
|
const user = await sec.ensureUser(this.min.instance.instanceId, id,
|
2021-03-03 16:46:18 -03:00
|
|
|
senderName, '', 'whatsapp', senderName, null);
|
2020-05-17 22:36:00 +00:00
|
|
|
|
2020-05-27 23:01:44 -03:00
|
|
|
const locale = user.locale ? user.locale : 'pt';
|
2021-12-25 22:13:52 -03:00
|
|
|
|
|
|
|
if (answerText) {
|
|
|
|
await this.sendToDeviceEx(user.userSystemId, answerText, locale, null);
|
|
|
|
return; // Exit here.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-12-31 15:36:19 -03:00
|
|
|
if (message.type === 'ptt') {
|
2020-04-13 19:14:55 -03:00
|
|
|
|
2020-12-31 15:36:19 -03:00
|
|
|
if (process.env.AUDIO_DISABLED !== 'true') {
|
2020-05-27 23:01:44 -03:00
|
|
|
const options = {
|
|
|
|
url: message.body,
|
|
|
|
method: 'GET',
|
|
|
|
encoding: 'binary'
|
|
|
|
};
|
|
|
|
|
|
|
|
const res = await request(options);
|
2020-12-31 15:36:19 -03:00
|
|
|
const buf = Buffer.from(res, 'binary');
|
2020-05-27 23:01:44 -03:00
|
|
|
text = await GBConversationalService.getTextFromAudioBuffer(
|
|
|
|
this.min.instance.speechKey,
|
|
|
|
this.min.instance.cloudLocation,
|
|
|
|
buf, locale
|
|
|
|
);
|
2020-12-31 15:36:19 -03:00
|
|
|
} else {
|
2021-12-25 22:13:52 -03:00
|
|
|
await this.sendToDevice(user.userSystemId,
|
2021-12-18 21:31:49 -03:00
|
|
|
`No momento estou apenas conseguindo ler mensagens de texto.`, null);
|
2020-05-27 23:01:44 -03:00
|
|
|
}
|
2020-04-13 19:14:55 -03:00
|
|
|
}
|
|
|
|
|
2021-12-18 21:31:49 -03:00
|
|
|
const conversationId = WhatsappDirectLine.conversationIds[from + group];
|
2019-03-08 06:37:13 -03:00
|
|
|
|
2020-12-31 15:36:19 -03:00
|
|
|
const client = await this.directLineClient;
|
2021-03-03 16:46:18 -03:00
|
|
|
|
|
|
|
|
|
|
|
// Check if this message is from a Human Agent itself.
|
|
|
|
|
2020-12-31 15:36:19 -03:00
|
|
|
if (user.agentMode === 'self') {
|
2019-06-28 11:17:41 -03:00
|
|
|
|
2021-03-03 16:46:18 -03:00
|
|
|
// Check if there is someone being handled by this Human Agent.
|
|
|
|
|
|
|
|
const manualUser = await sec.getUserFromAgentSystemId(id);
|
2020-05-16 16:40:44 -03:00
|
|
|
if (manualUser === null) {
|
2021-03-03 16:46:18 -03:00
|
|
|
|
|
|
|
await sec.updateHumanAgent(id, this.min.instance.instanceId, null);
|
2021-12-18 21:31:49 -03:00
|
|
|
|
2020-12-31 15:36:19 -03:00
|
|
|
} else {
|
2021-03-03 16:46:18 -03:00
|
|
|
const agent = await sec.getUserFromSystemId(user.agentSystemId);
|
|
|
|
|
2020-05-16 16:40:44 -03:00
|
|
|
const cmd = '/reply ';
|
|
|
|
if (text.startsWith(cmd)) {
|
2020-12-31 15:36:19 -03:00
|
|
|
const filename = text.substr(cmd.length);
|
|
|
|
const message = await this.min.kbService.getAnswerTextByMediaName(this.min.instance.instanceId, filename);
|
2020-05-16 16:40:44 -03:00
|
|
|
|
|
|
|
if (message === null) {
|
2020-05-17 22:36:00 +00:00
|
|
|
await this.sendToDeviceEx(user.userSystemId, `File ${filename} not found in any .gbkb published. Check the name or publish again the associated .gbkb.`,
|
2021-12-18 21:31:49 -03:00
|
|
|
locale, null);
|
2020-05-16 16:40:44 -03:00
|
|
|
} else {
|
|
|
|
await this.min.conversationalService.sendMarkdownToMobile(this.min, null, user.userSystemId, message);
|
|
|
|
}
|
|
|
|
} else if (text === '/qt') {
|
|
|
|
// TODO: Transfers only in pt-br for now.
|
2020-12-31 15:36:19 -03:00
|
|
|
await this.sendToDeviceEx(manualUser.userSystemId,
|
2021-12-18 21:31:49 -03:00
|
|
|
Messages[this.locale].notify_end_transfer(this.min.instance.botId), locale, null);
|
2020-05-16 16:40:44 -03:00
|
|
|
|
2021-03-03 16:46:18 -03:00
|
|
|
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,
|
2021-12-18 21:31:49 -03:00
|
|
|
Messages[this.locale].notify_end_transfer(this.min.instance.botId), locale, null);
|
2021-03-03 16:46:18 -03:00
|
|
|
|
|
|
|
}
|
|
|
|
await sec.updateHumanAgent(manualUser.userSystemId, this.min.instance.instanceId, null);
|
|
|
|
await sec.updateHumanAgent(user.agentSystemId, this.min.instance.instanceId, null);
|
2020-12-31 15:36:19 -03:00
|
|
|
} else {
|
2021-03-08 18:36:59 -03:00
|
|
|
GBLog.info(`HUMAN AGENT (${manualUser.agentSystemId}) TO USER ${manualUser.userSystemId}: ${text}`);
|
2021-12-18 21:31:49 -03:00
|
|
|
await this.sendToDeviceEx(manualUser.userSystemId, `AGENTE: *${text}*`, locale, null);
|
2020-05-16 16:40:44 -03:00
|
|
|
}
|
2020-05-02 21:28:13 -03:00
|
|
|
}
|
2021-03-03 16:46:18 -03:00
|
|
|
|
|
|
|
|
2020-12-31 15:36:19 -03:00
|
|
|
} else if (user.agentMode === 'human') {
|
2021-03-03 16:46:18 -03:00
|
|
|
|
2020-12-31 15:36:19 -03:00
|
|
|
const agent = await sec.getUserFromSystemId(user.agentSystemId);
|
2020-05-02 21:28:13 -03:00
|
|
|
if (text === '/t') {
|
2021-12-18 21:31:49 -03:00
|
|
|
await this.sendToDeviceEx(user.userSystemId, `Você já está sendo atendido por ${agent.userSystemId}.`, locale, null);
|
2020-12-31 15:36:19 -03:00
|
|
|
} else if (text === '/qt' || text === 'Sair' || text === 'Fechar') {
|
2020-05-02 21:28:13 -03:00
|
|
|
// TODO: Transfers only in pt-br for now.
|
2020-12-31 15:36:19 -03:00
|
|
|
await this.sendToDeviceEx(id,
|
2021-12-18 21:31:49 -03:00
|
|
|
Messages[this.locale].notify_end_transfer(this.min.instance.botId), locale, null);
|
2021-03-03 16:46:18 -03:00
|
|
|
|
2021-12-18 21:31:49 -03:00
|
|
|
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);
|
|
|
|
}
|
2020-05-02 21:28:13 -03:00
|
|
|
|
2021-03-03 16:46:18 -03:00
|
|
|
await sec.updateHumanAgent(id, this.min.instance.instanceId, null);
|
2020-12-31 15:36:19 -03:00
|
|
|
} else {
|
2021-03-03 16:46:18 -03:00
|
|
|
GBLog.info(`USER (${id}) TO AGENT ${agent.userSystemId}: ${text}`);
|
|
|
|
|
2021-06-16 11:53:20 -03:00
|
|
|
if (user.agentSystemId.charAt(2) === ":" || agent.userSystemId.indexOf("@") > -1) { // Agent is from Teams or Google Chat.
|
2021-03-03 16:46:18 -03:00
|
|
|
await this.min.conversationalService['sendOnConversation'](this.min, agent, text);
|
|
|
|
}
|
|
|
|
else {
|
2021-12-18 21:31:49 -03:00
|
|
|
await this.sendToDeviceEx(user.agentSystemId, `Bot: ${this.min.instance.botId}\n${id}: ${text}`, locale, null);
|
2021-03-03 16:46:18 -03:00
|
|
|
}
|
|
|
|
|
2020-05-02 21:28:13 -03:00
|
|
|
}
|
2019-06-28 11:17:41 -03:00
|
|
|
|
2020-12-31 15:36:19 -03:00
|
|
|
} else if (user.agentMode === 'bot' || user.agentMode === null || user.agentMode === undefined) {
|
2020-05-02 21:28:13 -03:00
|
|
|
|
2021-12-18 21:31:49 -03:00
|
|
|
if (WhatsappDirectLine.conversationIds[from + group] === undefined) {
|
2020-05-02 21:28:13 -03:00
|
|
|
GBLog.info(`GBWhatsapp: Starting new conversation on Bot.`);
|
2020-06-15 00:40:25 -03:00
|
|
|
const response = await client.Conversations.Conversations_StartConversation();
|
2020-05-02 21:28:13 -03:00
|
|
|
const generatedConversationId = response.obj.conversationId;
|
|
|
|
|
2021-12-18 21:31:49 -03:00
|
|
|
WhatsappDirectLine.conversationIds[from + group] = generatedConversationId;
|
2021-10-13 09:39:24 -03:00
|
|
|
WhatsappDirectLine.mobiles[generatedConversationId] = from;
|
2021-12-31 09:39:23 -03:00
|
|
|
WhatsappDirectLine.usernames[from] = fromName;
|
2021-12-18 21:31:49 -03:00
|
|
|
WhatsappDirectLine.chatIds[generatedConversationId] = message.chatId;
|
2021-12-31 09:39:23 -03:00
|
|
|
|
2020-05-02 21:28:13 -03:00
|
|
|
|
|
|
|
this.pollMessages(client, generatedConversationId, from, fromName);
|
2021-12-27 15:41:54 -03:00
|
|
|
this.inputMessage(client, generatedConversationId, text, from, fromName, group);
|
2020-05-02 21:28:13 -03:00
|
|
|
} else {
|
|
|
|
|
2021-12-27 15:41:54 -03:00
|
|
|
this.inputMessage(client, conversationId, text, from, fromName, group);
|
2020-05-02 21:28:13 -03:00
|
|
|
}
|
2020-12-31 15:36:19 -03:00
|
|
|
} else {
|
2020-05-02 21:28:13 -03:00
|
|
|
GBLog.warn(`Inconsistencty found: Invalid agentMode on User Table: ${user.agentMode}`);
|
|
|
|
}
|
|
|
|
|
2019-06-28 11:17:41 -03:00
|
|
|
res.end();
|
2019-06-17 15:22:13 -03:00
|
|
|
|
2019-03-08 06:37:13 -03:00
|
|
|
}
|
|
|
|
|
2021-12-27 15:41:54 -03:00
|
|
|
public inputMessage(client, conversationId, text, from, fromName, group) {
|
2019-06-28 11:17:41 -03:00
|
|
|
return client.Conversations.Conversations_PostActivity({
|
2019-03-08 06:37:13 -03:00
|
|
|
conversationId: conversationId,
|
|
|
|
activity: {
|
|
|
|
textFormat: 'plain',
|
2020-05-27 23:01:44 -03:00
|
|
|
text: text,
|
2019-03-08 06:37:13 -03:00
|
|
|
type: 'message',
|
2021-05-09 19:19:44 -03:00
|
|
|
mobile: from,
|
2021-12-27 15:41:54 -03:00
|
|
|
group: group,
|
2019-03-08 06:37:13 -03:00
|
|
|
from: {
|
|
|
|
id: from,
|
|
|
|
name: fromName
|
|
|
|
},
|
|
|
|
replyToId: from
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public pollMessages(client, conversationId, from, fromName) {
|
2019-06-23 07:03:32 -03:00
|
|
|
GBLog.info(`GBWhatsapp: Starting message polling(${from}, ${conversationId}).`);
|
|
|
|
|
2019-06-23 07:24:35 -03:00
|
|
|
let watermark: any;
|
|
|
|
|
2019-06-23 07:03:32 -03:00
|
|
|
const worker = async () => {
|
|
|
|
try {
|
2019-06-23 07:24:35 -03:00
|
|
|
const response = await client.Conversations.Conversations_GetActivities({
|
2019-06-23 07:03:32 -03:00
|
|
|
conversationId: conversationId,
|
2019-06-23 07:24:35 -03:00
|
|
|
watermark: watermark
|
2019-03-08 06:37:13 -03:00
|
|
|
});
|
2019-06-23 07:24:35 -03:00
|
|
|
watermark = response.obj.watermark;
|
2019-06-23 07:03:32 -03:00
|
|
|
await this.printMessages(response.obj.activities, conversationId, from, fromName);
|
|
|
|
} catch (err) {
|
2020-04-28 20:54:04 -03:00
|
|
|
GBLog.error(`Error calling printMessages on Whatsapp channel ${err.data === undefined ? err : err.data}`);
|
2019-06-23 07:03:32 -03:00
|
|
|
}
|
2019-06-22 07:06:21 -03:00
|
|
|
};
|
2019-06-23 07:25:59 -03:00
|
|
|
setInterval(worker, this.pollInterval);
|
2019-03-08 06:37:13 -03:00
|
|
|
}
|
2018-10-16 10:19:34 -03:00
|
|
|
|
2019-06-22 07:51:04 -03:00
|
|
|
public async printMessages(activities, conversationId, from, fromName) {
|
2019-03-08 06:37:13 -03:00
|
|
|
if (activities && activities.length) {
|
|
|
|
// Ignore own messages.
|
2018-11-12 12:20:44 -02:00
|
|
|
|
2019-05-15 22:30:14 -03:00
|
|
|
activities = activities.filter(m => m.from.id === this.botId && m.type === 'message');
|
2018-05-07 20:45:11 -03:00
|
|
|
|
2019-03-08 06:37:13 -03:00
|
|
|
if (activities.length) {
|
|
|
|
// Print other messages.
|
2018-05-12 13:40:34 -03:00
|
|
|
|
2019-06-22 07:51:04 -03:00
|
|
|
await WhatsappDirectLine.asyncForEach(activities, async activity => {
|
|
|
|
await this.printMessage(activity, conversationId, from, fromName);
|
2019-03-08 06:37:13 -03:00
|
|
|
});
|
|
|
|
}
|
2018-05-07 20:45:11 -03:00
|
|
|
}
|
2019-03-08 06:37:13 -03:00
|
|
|
}
|
2018-05-07 20:45:11 -03:00
|
|
|
|
2019-06-22 07:51:04 -03:00
|
|
|
public async printMessage(activity, conversationId, from, fromName) {
|
2019-03-08 06:37:13 -03:00
|
|
|
let output = '';
|
2018-05-12 13:40:34 -03:00
|
|
|
|
2019-03-08 06:37:13 -03:00
|
|
|
if (activity.text) {
|
2019-06-22 07:51:04 -03:00
|
|
|
GBLog.info(`GBWhatsapp: SND ${from}(${fromName}): ${activity.text}`);
|
2019-03-08 06:37:13 -03:00
|
|
|
output = activity.text;
|
2018-05-07 20:45:11 -03:00
|
|
|
}
|
|
|
|
|
2019-03-08 06:37:13 -03:00
|
|
|
if (activity.attachments) {
|
|
|
|
activity.attachments.forEach(attachment => {
|
|
|
|
switch (attachment.contentType) {
|
|
|
|
case 'application/vnd.microsoft.card.hero':
|
|
|
|
output += `\n${this.renderHeroCard(attachment)}`;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'image/png':
|
2019-03-09 16:59:31 -03:00
|
|
|
GBLog.info(`Opening the requested image ${attachment.contentUrl}`);
|
2019-03-08 06:37:13 -03:00
|
|
|
output += `\n${attachment.contentUrl}`;
|
|
|
|
break;
|
2019-03-09 16:59:31 -03:00
|
|
|
default:
|
|
|
|
GBLog.info(`Unknown content type: ${attachment.contentType}`);
|
2019-03-08 06:37:13 -03:00
|
|
|
}
|
|
|
|
});
|
2018-05-07 20:45:11 -03:00
|
|
|
}
|
2018-05-11 22:18:38 -03:00
|
|
|
|
2021-12-18 21:31:49 -03:00
|
|
|
await this.sendToDevice(from, output, conversationId);
|
2019-03-08 06:37:13 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
public renderHeroCard(attachment) {
|
|
|
|
return `${attachment.content.title} - ${attachment.content.text}`;
|
|
|
|
}
|
|
|
|
|
2021-12-31 08:39:51 -03:00
|
|
|
public async sendFileToDevice(to, url, filename, caption, chatId) {
|
2019-08-24 12:22:52 -03:00
|
|
|
const options = {
|
|
|
|
method: 'POST',
|
|
|
|
url: urlJoin(this.whatsappServiceUrl, 'sendFile'),
|
|
|
|
qs: {
|
|
|
|
token: this.whatsappServiceKey,
|
2021-12-31 08:39:51 -03:00
|
|
|
phone: chatId ? null : to,
|
|
|
|
chatId: chatId,
|
2019-08-24 18:46:04 -03:00
|
|
|
body: url,
|
2020-03-31 09:11:04 -03:00
|
|
|
filename: filename,
|
|
|
|
caption: caption
|
2019-08-24 12:22:52 -03:00
|
|
|
},
|
|
|
|
headers: {
|
|
|
|
'cache-control': 'no-cache'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
try {
|
|
|
|
// tslint:disable-next-line: await-promise
|
|
|
|
const result = await request.post(options);
|
2020-05-27 23:01:44 -03:00
|
|
|
GBLog.info(`File ${url} sent to ${to}: ${result}`);
|
2019-08-24 12:22:52 -03:00
|
|
|
} catch (error) {
|
2020-02-26 15:20:47 -03:00
|
|
|
GBLog.error(`Error sending file to Whatsapp provider ${error.message}`);
|
2019-08-24 12:22:52 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-31 08:39:51 -03:00
|
|
|
public async sendAudioToDevice(to, url, chatId) {
|
2019-08-24 18:46:04 -03:00
|
|
|
const options = {
|
|
|
|
method: 'POST',
|
|
|
|
url: urlJoin(this.whatsappServiceUrl, 'sendPTT'),
|
|
|
|
qs: {
|
|
|
|
token: this.whatsappServiceKey,
|
2021-12-31 08:39:51 -03:00
|
|
|
phone: chatId ? null : to,
|
|
|
|
chatId: chatId,
|
2020-04-28 20:54:04 -03:00
|
|
|
body: url
|
2019-08-24 18:46:04 -03:00
|
|
|
},
|
|
|
|
headers: {
|
|
|
|
'cache-control': 'no-cache'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
try {
|
|
|
|
// tslint:disable-next-line: await-promise
|
|
|
|
const result = await request.post(options);
|
2020-05-27 23:01:44 -03:00
|
|
|
GBLog.info(`Audio ${url} sent to ${to}: ${result}`);
|
2019-08-24 18:46:04 -03:00
|
|
|
} catch (error) {
|
2020-02-26 15:20:47 -03:00
|
|
|
GBLog.error(`Error sending audio message to Whatsapp provider ${error.message}`);
|
2019-08-24 18:46:04 -03:00
|
|
|
}
|
|
|
|
}
|
2019-08-24 12:22:52 -03:00
|
|
|
|
2021-12-31 08:39:51 -03:00
|
|
|
public async sendTextAsAudioToDevice(to, msg, chatId) {
|
2020-04-28 20:54:04 -03:00
|
|
|
|
2021-12-28 15:51:14 -03:00
|
|
|
const url = await GBConversationalService.getAudioBufferFromText(
|
2021-12-30 07:58:16 -03:00
|
|
|
msg
|
2021-12-28 15:51:14 -03:00
|
|
|
);
|
|
|
|
|
2021-12-31 08:39:51 -03:00
|
|
|
await this.sendFileToDevice(to, url, 'Audio', msg, chatId);
|
2020-04-28 20:54:04 -03:00
|
|
|
}
|
|
|
|
|
2021-12-25 22:13:52 -03:00
|
|
|
public async sendToDevice(to: string, msg: string, conversationId) {
|
2019-05-15 22:30:14 -03:00
|
|
|
|
2020-04-28 20:54:04 -03:00
|
|
|
const cmd = '/audio ';
|
2021-12-31 08:39:51 -03:00
|
|
|
|
|
|
|
let chatId = WhatsappDirectLine.chatIds[conversationId];
|
|
|
|
|
2020-06-04 20:14:02 -03:00
|
|
|
if (msg.startsWith(cmd)) {
|
2020-04-28 20:54:04 -03:00
|
|
|
msg = msg.substr(cmd.length);
|
2020-06-05 14:40:21 -03:00
|
|
|
|
2021-12-31 08:39:51 -03:00
|
|
|
return await this.sendTextAsAudioToDevice(to, msg, chatId);
|
2020-06-05 14:40:21 -03:00
|
|
|
} else {
|
2020-04-28 20:54:04 -03:00
|
|
|
|
2021-12-31 08:39:51 -03:00
|
|
|
|
2021-12-18 21:31:49 -03:00
|
|
|
|
2020-04-28 20:54:04 -03:00
|
|
|
const options = {
|
|
|
|
method: 'POST',
|
|
|
|
url: urlJoin(this.whatsappServiceUrl, 'message'),
|
|
|
|
qs: {
|
|
|
|
token: this.whatsappServiceKey,
|
2021-12-18 21:31:49 -03:00
|
|
|
phone: chatId ? null : to,
|
|
|
|
chatId: chatId,
|
2020-04-28 20:54:04 -03:00
|
|
|
body: msg
|
|
|
|
},
|
|
|
|
headers: {
|
|
|
|
'cache-control': 'no-cache'
|
|
|
|
}
|
|
|
|
};
|
2020-02-26 15:20:47 -03:00
|
|
|
|
2020-04-28 20:54:04 -03:00
|
|
|
try {
|
|
|
|
// tslint:disable-next-line: await-promise
|
|
|
|
const result = await request.post(options);
|
2020-05-27 23:01:44 -03:00
|
|
|
GBLog.info(`Message [${msg}] sent to ${to}: ${result}`);
|
2020-04-28 20:54:04 -03:00
|
|
|
} catch (error) {
|
|
|
|
GBLog.error(`Error sending message to Whatsapp provider ${error.message}`);
|
|
|
|
|
|
|
|
// TODO: Handle Error: socket hang up and retry.
|
|
|
|
}
|
2019-05-15 22:30:14 -03:00
|
|
|
}
|
2019-03-08 06:37:13 -03:00
|
|
|
}
|
2020-12-31 15:36:19 -03:00
|
|
|
|
2021-12-18 21:31:49 -03:00
|
|
|
public async sendToDeviceEx(to, text, locale, conversationId) {
|
2021-06-16 11:53:20 -03:00
|
|
|
text = await this.min.conversationalService.translate(
|
|
|
|
this.min,
|
2020-12-31 15:36:19 -03:00
|
|
|
text,
|
|
|
|
locale
|
|
|
|
);
|
2021-12-18 21:31:49 -03:00
|
|
|
await this.sendToDevice(to, text, conversationId);
|
2020-12-31 15:36:19 -03:00
|
|
|
|
|
|
|
}
|
2018-10-16 10:19:34 -03:00
|
|
|
}
|