new(all) General Bots Auto Tester 1.0; Unlimited conditionals after-code BASIC 3.0;
This commit is contained in:
parent
c66f9bfe04
commit
30c93526c0
11 changed files with 8829 additions and 28129 deletions
4
gbot.sh
4
gbot.sh
|
@ -1 +1,5 @@
|
||||||
|
echo General Bots
|
||||||
|
echo Installing modules for the first time...
|
||||||
|
|
||||||
|
npm i
|
||||||
node .
|
node .
|
||||||
|
|
18578
package-lock.json
generated
18578
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -98,6 +98,7 @@
|
||||||
"googleapis": "75.0.0",
|
"googleapis": "75.0.0",
|
||||||
"ibm-watson": "6.1.1",
|
"ibm-watson": "6.1.1",
|
||||||
"js-beautify": "1.13.13",
|
"js-beautify": "1.13.13",
|
||||||
|
"keyv": "^4.5.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"luxon": "2.0.2",
|
"luxon": "2.0.2",
|
||||||
"mammoth": "^1.4.21",
|
"mammoth": "^1.4.21",
|
||||||
|
@ -147,6 +148,7 @@
|
||||||
"url-join": "4.0.1",
|
"url-join": "4.0.1",
|
||||||
"vbscript-to-typescript": "1.0.8",
|
"vbscript-to-typescript": "1.0.8",
|
||||||
"vhost": "^3.0.2",
|
"vhost": "^3.0.2",
|
||||||
|
"vm2": "^3.9.11",
|
||||||
"walk-promise": "0.2.0",
|
"walk-promise": "0.2.0",
|
||||||
"washyourmouthoutwithsoap": "1.0.2",
|
"washyourmouthoutwithsoap": "1.0.2",
|
||||||
"whatsapp-web.js": "github:pedroslopez/whatsapp-web.js#fix-buttons-list",
|
"whatsapp-web.js": "github:pedroslopez/whatsapp-web.js#fix-buttons-list",
|
||||||
|
|
|
@ -1,404 +0,0 @@
|
||||||
/*****************************************************************************\
|
|
||||||
| ( )_ _ |
|
|
||||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
|
||||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
|
|
||||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
|
|
||||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
|
||||||
| | | ( )_) | |
|
|
||||||
| (_) \___/' |
|
|
||||||
| |
|
|
||||||
| 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. |
|
|
||||||
| |
|
|
||||||
\*****************************************************************************/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
|
||||||
import { GBLog } from 'botlib';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import { CollectionUtil } from 'pragmatismo-io-framework';
|
|
||||||
import * as request from 'request-promise-native';
|
|
||||||
import { Messages } from '../strings';
|
|
||||||
import { GBConversationalService } from '../../core.gbapp/services/GBConversationalService';
|
|
||||||
import { GBConfigService } from '../../core.gbapp/services/GBConfigService';
|
|
||||||
const { Buttons } = require('whatsapp-web.js');
|
|
||||||
const Path = require('path');
|
|
||||||
const phoneUtil = require('google-libphonenumber').PhoneNumberUtil.getInstance();
|
|
||||||
const phone = require('phone');
|
|
||||||
|
|
||||||
//tslint:disable-next-line:no-submodule-imports
|
|
||||||
/**
|
|
||||||
* HEAR Bot Framework support.
|
|
||||||
*/
|
|
||||||
export class HearDialog {
|
|
||||||
|
|
||||||
private static async downloadAttachmentAndWrite(attachment) {
|
|
||||||
|
|
||||||
|
|
||||||
const url = attachment.contentUrl;
|
|
||||||
const localFolder = Path.join('work'); // TODO: , '${botId}', 'uploads');
|
|
||||||
const localFileName = Path.join(localFolder, attachment.name);
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
let response;
|
|
||||||
if (url.startsWith('data:')) {
|
|
||||||
var regex = /^data:.+\/(.+);base64,(.*)$/;
|
|
||||||
var matches = url.match(regex);
|
|
||||||
var ext = matches[1];
|
|
||||||
var data = matches[2];
|
|
||||||
response = Buffer.from(data, 'base64');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// arraybuffer is necessary for images
|
|
||||||
const options = {
|
|
||||||
url: url,
|
|
||||||
method: 'GET',
|
|
||||||
encoding: 'binary',
|
|
||||||
};
|
|
||||||
response = await request.get(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFile(localFileName, response, (fsError) => {
|
|
||||||
if (fsError) {
|
|
||||||
throw fsError;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
// If no error was thrown while writing to disk, return the attachment's name
|
|
||||||
// and localFilePath for the response back to the user.
|
|
||||||
return {
|
|
||||||
fileName: attachment.name,
|
|
||||||
localPath: localFileName
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static addHearDialog(min) {
|
|
||||||
min.dialogs.add(
|
|
||||||
new WaterfallDialog('/hear', [
|
|
||||||
async step => {
|
|
||||||
step.activeDialog.state.options = step.options;
|
|
||||||
step.activeDialog.state.options.id = (step.options as any).id;
|
|
||||||
step.activeDialog.state.options.previousResolve = (step.options as any).previousResolve;
|
|
||||||
|
|
||||||
|
|
||||||
const args = step.options['args'];
|
|
||||||
if (args && args.length >1) {
|
|
||||||
|
|
||||||
let choices = [];
|
|
||||||
let i = 0;
|
|
||||||
args.forEach(arg => {
|
|
||||||
i++;
|
|
||||||
choices.push({ body: arg, id: `button${i}` });
|
|
||||||
});
|
|
||||||
|
|
||||||
const locale = step.context.activity.locale;
|
|
||||||
const button = new Buttons(Messages[locale].choices, choices, ' ', ' ');
|
|
||||||
|
|
||||||
await min.conversationalService.sendText(min, step, button);
|
|
||||||
|
|
||||||
GBLog.info(`BASIC: Asking for input (HEAR with ${step.options['args'][0]}).`);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
GBLog.info('BASIC: Asking for input (HEAR).');
|
|
||||||
}
|
|
||||||
|
|
||||||
step.activeDialog.state.options = step.options;
|
|
||||||
if (step.activeDialog.state.options['kind'] === "login") {
|
|
||||||
if (step.context.activity.channelId !== 'msteams' && process.env.ENABLE_AUTH) {
|
|
||||||
GBLog.info('BASIC: Authenticating beforing running General Bots BASIC code.');
|
|
||||||
return await step.beginDialog('/auth');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return await step.next(step.options);
|
|
||||||
},
|
|
||||||
async step => {
|
|
||||||
if (step.activeDialog.state.options['kind'] === "login") {
|
|
||||||
return await step.next(step.options);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (step.activeDialog.state.options['kind'] === "file") {
|
|
||||||
return await step.prompt('attachmentPrompt', {});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return await min.conversationalService.prompt(min, step, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
async step => {
|
|
||||||
|
|
||||||
const isIntentYes = (locale, utterance) => {
|
|
||||||
return utterance.toLowerCase().match(Messages[locale].affirmative_sentences);
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = step.context.activity['originalText'];
|
|
||||||
if (step.activeDialog.state.options['kind'] === "file") {
|
|
||||||
|
|
||||||
// Prepare Promises to download each attachment and then execute each Promise.
|
|
||||||
const promises = step.context.activity.attachments.map(
|
|
||||||
HearDialog.downloadAttachmentAndWrite);
|
|
||||||
const successfulSaves = await Promise.all(promises);
|
|
||||||
|
|
||||||
async function replyForReceivedAttachments(localAttachmentData) {
|
|
||||||
if (localAttachmentData) {
|
|
||||||
// Because the TurnContext was bound to this function, the bot can call
|
|
||||||
// `TurnContext.sendActivity` via `this.sendActivity`;
|
|
||||||
await this.sendActivity(`Upload OK.`);
|
|
||||||
} else {
|
|
||||||
await this.sendActivity('Error uploading file. Please, start again.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare Promises to reply to the user with information about saved attachments.
|
|
||||||
// The current TurnContext is bound so `replyForReceivedAttachments` can also send replies.
|
|
||||||
const replyPromises = successfulSaves.map(replyForReceivedAttachments.bind(step.context));
|
|
||||||
await Promise.all(replyPromises);
|
|
||||||
|
|
||||||
result = {
|
|
||||||
data: fs.readFileSync(successfulSaves[0].localPath),
|
|
||||||
filename: successfulSaves[0].fileName
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (step.activeDialog.state.options['kind'] === "boolean") {
|
|
||||||
if (isIntentYes('pt-BR', step.result)) {
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (step.activeDialog.state.options['kind'] === "email") {
|
|
||||||
|
|
||||||
const extractEntity = (text) => {
|
|
||||||
return text.match(/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)/gi);
|
|
||||||
}
|
|
||||||
|
|
||||||
const value = extractEntity(step.result);
|
|
||||||
|
|
||||||
if (value === null) {
|
|
||||||
await step.context.sendActivity("Por favor, digite um e-mail válido.");
|
|
||||||
return await step.replaceDialog('/hear', step.activeDialog.state.options);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = value;
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (step.activeDialog.state.options['kind'] === "name") {
|
|
||||||
const extractEntity = text => {
|
|
||||||
return text.match(/[_a-zA-Z][_a-zA-Z0-9]{0,16}/gi);
|
|
||||||
};
|
|
||||||
|
|
||||||
const value = extractEntity(step.result);
|
|
||||||
|
|
||||||
if (value === null || value.length != 1) {
|
|
||||||
await step.context.sendActivity("Por favor, digite um nome válido.");
|
|
||||||
return await step.replaceDialog('/hear', step.activeDialog.state.options);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = value;
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (step.activeDialog.state.options['kind'] === "integer") {
|
|
||||||
const extractEntity = text => {
|
|
||||||
return text.match(/\d+/gi);
|
|
||||||
};
|
|
||||||
|
|
||||||
const value = extractEntity(step.result);
|
|
||||||
|
|
||||||
if (value === null || value.length != 1) {
|
|
||||||
await step.context.sendActivity("Por favor, digite um número válido.");
|
|
||||||
return await step.replaceDialog('/hear', step.activeDialog.state.options);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = value;
|
|
||||||
}
|
|
||||||
else if (step.activeDialog.state.options['kind'] === "date") {
|
|
||||||
const extractEntity = text => {
|
|
||||||
return text.match(/(^(((0[1-9]|1[0-9]|2[0-8])[\/](0[1-9]|1[012]))|((29|30|31)[\/](0[13578]|1[02]))|((29|30)[\/](0[4,6,9]|11)))[\/](19|[2-9][0-9])\d\d$)|(^29[\/]02[\/](19|[2-9][0-9])(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)$)/gi);
|
|
||||||
};
|
|
||||||
|
|
||||||
const value = extractEntity(step.result);
|
|
||||||
|
|
||||||
if (value === null || value.length != 1) {
|
|
||||||
await step.context.sendActivity("Por favor, digite uma data no formato 12/12/2020.");
|
|
||||||
return await step.replaceDialog('/hear', step.activeDialog.state.options);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = value;
|
|
||||||
}
|
|
||||||
else if (step.activeDialog.state.options['kind'] === "hour") {
|
|
||||||
|
|
||||||
const extractEntity = text => {
|
|
||||||
return text.match(/^([0-1]?[0-9]|2[0-4]):([0-5][0-9])(:[0-5][0-9])?$/gi);
|
|
||||||
};
|
|
||||||
|
|
||||||
const value = extractEntity(step.result);
|
|
||||||
|
|
||||||
if (value === null || value.length != 1) {
|
|
||||||
await step.context.sendActivity("Por favor, digite um horário no formato hh:ss.");
|
|
||||||
return await step.replaceDialog('/hear', step.activeDialog.state.options);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = value;
|
|
||||||
}
|
|
||||||
else if (step.activeDialog.state.options['kind'] === "money") {
|
|
||||||
const extractEntity = text => {
|
|
||||||
|
|
||||||
if (step.context.locale === 'en') { // TODO: Change to user.
|
|
||||||
return text.match(/(?:\d{1,3},)*\d{1,3}(?:\.\d+)?/gi);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return text.match(/(?:\d{1,3}.)*\d{1,3}(?:\,\d+)?/gi);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const value = extractEntity(step.result);
|
|
||||||
|
|
||||||
if (value === null || value.length != 1) {
|
|
||||||
await step.context.sendActivity("Por favor, digite um valor monetário.");
|
|
||||||
return await step.replaceDialog('/hear', step.activeDialog.state.options);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = value;
|
|
||||||
}
|
|
||||||
else if (step.activeDialog.state.options['kind'] === "mobile") {
|
|
||||||
const locale = step.context.activity.locale;
|
|
||||||
let phoneNumber;
|
|
||||||
try {
|
|
||||||
phoneNumber = phone(step.result, 'BRA')[0]; // TODO: Use accordingly to the person.
|
|
||||||
phoneNumber = phoneUtil.parse(phoneNumber);
|
|
||||||
} catch (error) {
|
|
||||||
await step.context.sendActivity(Messages[locale].validation_enter_valid_mobile);
|
|
||||||
|
|
||||||
return await step.replaceDialog('/profile_mobile', step.activeDialog.state.options);
|
|
||||||
}
|
|
||||||
if (!phoneUtil.isPossibleNumber(phoneNumber)) {
|
|
||||||
await step.context.sendActivity("Por favor, digite um número de telefone válido.");
|
|
||||||
return await step.replaceDialog('/hear', step.activeDialog.state.options);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = phoneNumber;
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (step.activeDialog.state.options['kind'] === "zipcode") {
|
|
||||||
const extractEntity = text => {
|
|
||||||
|
|
||||||
text = text.replace(/\-/gi, '');
|
|
||||||
|
|
||||||
if (step.context.locale === 'en') { // TODO: Change to user.
|
|
||||||
return text.match(/\d{8}/gi);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return text.match(/(?:\d{1,3}.)*\d{1,3}(?:\,\d+)?/gi);
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const value = extractEntity(step.result);
|
|
||||||
|
|
||||||
if (value === null || value.length != 1) {
|
|
||||||
await step.context.sendActivity("Por favor, digite um valor monetário.");
|
|
||||||
return await step.replaceDialog('/hear', step.activeDialog.state.options);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = value[0];
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (step.activeDialog.state.options['kind'] === "menu") {
|
|
||||||
|
|
||||||
const list = step.activeDialog.state.options['args'];
|
|
||||||
result = null;
|
|
||||||
const typed = step.context.activity['originalText'];
|
|
||||||
await CollectionUtil.asyncForEach(list, async item => {
|
|
||||||
if (GBConversationalService.kmpSearch(typed, item) != -1) {
|
|
||||||
result = item;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result === null) {
|
|
||||||
await step.context.sendActivity(`Escolha por favor um dos itens sugeridos.`);
|
|
||||||
return await step.replaceDialog('/hear', step.activeDialog.state.options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (step.activeDialog.state.options['kind'] === "language") {
|
|
||||||
|
|
||||||
result = null;
|
|
||||||
|
|
||||||
const list = [
|
|
||||||
{ name: 'english', code: 'en' },
|
|
||||||
{ name: 'inglês', code: 'en' },
|
|
||||||
{ name: 'portuguese', code: 'pt' },
|
|
||||||
{ name: 'português', code: 'pt' },
|
|
||||||
{ name: 'français', code: 'fr' },
|
|
||||||
{ name: 'francês', code: 'fr' },
|
|
||||||
{ name: 'french', code: 'fr' },
|
|
||||||
{ name: 'spanish', code: 'es' },
|
|
||||||
{ name: 'espanõl', code: 'es' },
|
|
||||||
{ name: 'espanhol', code: 'es' },
|
|
||||||
{ name: 'german', code: 'de' },
|
|
||||||
{ name: 'deutsch', code: 'de' },
|
|
||||||
{ name: 'alemão', code: 'de' }
|
|
||||||
];
|
|
||||||
|
|
||||||
const text = step.context.activity['originalText'];
|
|
||||||
|
|
||||||
await CollectionUtil.asyncForEach(list, async item => {
|
|
||||||
if (GBConversationalService.kmpSearch(text.toLowerCase(), item.name.toLowerCase()) != -1 ||
|
|
||||||
GBConversationalService.kmpSearch(text.toLowerCase(), item.code.toLowerCase()) != -1) {
|
|
||||||
result = item.code;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result === null) {
|
|
||||||
await min.conversationalService.sendText(min, step, `Escolha por favor um dos idiomas sugeridos.`);
|
|
||||||
return await step.replaceDialog('/hear', step.activeDialog.state.options);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const id = step.activeDialog.state.options.id;
|
|
||||||
if (min.cbMap[id]) {
|
|
||||||
const promise = min.cbMap[id].promise;
|
|
||||||
delete min.cbMap[id];
|
|
||||||
try {
|
|
||||||
const opts = await promise(step, result);
|
|
||||||
if (opts) {
|
|
||||||
return await step.replaceDialog('/hear', opts);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
GBLog.error(`Error in BASIC code: ${error}`);
|
|
||||||
const locale = step.context.activity.locale;
|
|
||||||
await min.conversationalService.sendText(min, step, Messages[locale].very_sorry_about_error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return await step.endDialog();
|
|
||||||
}
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -44,8 +44,19 @@ import { GBMinService } from '../../core.gbapp/services/GBMinService';
|
||||||
import { HubSpotServices } from '../../hubspot.gblib/services/HubSpotServices';
|
import { HubSpotServices } from '../../hubspot.gblib/services/HubSpotServices';
|
||||||
import { WhatsappDirectLine } from '../../whatsapp.gblib/services/WhatsappDirectLine';
|
import { WhatsappDirectLine } from '../../whatsapp.gblib/services/WhatsappDirectLine';
|
||||||
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
|
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
|
||||||
const DateDiff = require('date-diff');
|
|
||||||
import { createBrowser } from '../../core.gbapp/services/GBSSR';
|
import { createBrowser } from '../../core.gbapp/services/GBSSR';
|
||||||
|
import * as request from 'request-promise-native';
|
||||||
|
import { Messages } from '../strings';
|
||||||
|
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
|
import { GBConversationalService } from '../../core.gbapp/services/GBConversationalService';
|
||||||
|
|
||||||
|
|
||||||
|
const DateDiff = require('date-diff');
|
||||||
|
const { Buttons } = require('whatsapp-web.js');
|
||||||
|
const phoneUtil = require('google-libphonenumber').PhoneNumberUtil.getInstance();
|
||||||
|
const phone = require('phone');
|
||||||
|
|
||||||
const Path = require('path');
|
const Path = require('path');
|
||||||
const sgMail = require('@sendgrid/mail');
|
const sgMail = require('@sendgrid/mail');
|
||||||
|
@ -881,6 +892,49 @@ export class DialogKeywords {
|
||||||
public async showMenu(step) {
|
public async showMenu(step) {
|
||||||
return await step.beginDialog('/menu');
|
return await step.beginDialog('/menu');
|
||||||
}
|
}
|
||||||
|
private static async downloadAttachmentAndWrite(attachment) {
|
||||||
|
|
||||||
|
|
||||||
|
const url = attachment.contentUrl;
|
||||||
|
const localFolder = Path.join('work'); // TODO: , '${botId}', 'uploads');
|
||||||
|
const localFileName = Path.join(localFolder, attachment.name);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
let response;
|
||||||
|
if (url.startsWith('data:')) {
|
||||||
|
var regex = /^data:.+\/(.+);base64,(.*)$/;
|
||||||
|
var matches = url.match(regex);
|
||||||
|
var ext = matches[1];
|
||||||
|
var data = matches[2];
|
||||||
|
response = Buffer.from(data, 'base64');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// arraybuffer is necessary for images
|
||||||
|
const options = {
|
||||||
|
url: url,
|
||||||
|
method: 'GET',
|
||||||
|
encoding: 'binary',
|
||||||
|
};
|
||||||
|
response = await request.get(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFile(localFileName, response, (fsError) => {
|
||||||
|
if (fsError) {
|
||||||
|
throw fsError;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
// If no error was thrown while writing to disk, return the attachment's name
|
||||||
|
// and localFilePath for the response back to the user.
|
||||||
|
return {
|
||||||
|
fileName: attachment.name,
|
||||||
|
localPath: localFileName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the transfer of the conversation to a human agent.
|
* Performs the transfer of the conversation to a human agent.
|
||||||
|
@ -898,32 +952,289 @@ export class DialogKeywords {
|
||||||
* @example HEAR name
|
* @example HEAR name
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public async hear(step, promise, previousResolve, kind, ...args) {
|
public async hear(step, kind, ...args) {
|
||||||
function random(low, high) {
|
|
||||||
return Math.random() * (high - low) + low;
|
|
||||||
}
|
|
||||||
const idPromise = random(0, 120000000);
|
|
||||||
this.min.cbMap[idPromise] = {};
|
|
||||||
this.min.cbMap[idPromise].promise = promise;
|
|
||||||
|
|
||||||
let opts = { id: idPromise, previousResolve: previousResolve, kind: kind, args };
|
try {
|
||||||
|
|
||||||
if (this.hrOn) {
|
let user;
|
||||||
|
const isIntentYes = (locale, utterance) => {
|
||||||
// Waits for next message in HEAR delegated context.
|
return utterance.toLowerCase().match(Messages[locale].affirmative_sentences);
|
||||||
|
|
||||||
const botId = this.min.botId;
|
|
||||||
WhatsappDirectLine.state[botId + this.hrOn] = {
|
|
||||||
promise: promise, previousResolve: previousResolve
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
if (previousResolve !== undefined) {
|
|
||||||
previousResolve(opts);
|
|
||||||
} else {
|
|
||||||
await step.beginDialog('/hear', opts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.hrOn) {
|
||||||
|
const sec = new SecService();
|
||||||
|
user = await sec.getUserFromAgentSystemId(this.hrOn)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
user = this.user.systemUser;
|
||||||
|
}
|
||||||
|
const userId = user.userId;
|
||||||
|
let result;
|
||||||
|
|
||||||
|
const locale = user.locale ? user.locale : 'en-US';
|
||||||
|
// TODO: https://github.com/GeneralBots/BotServer/issues/266
|
||||||
|
|
||||||
|
if (args && args.length > 1) {
|
||||||
|
|
||||||
|
let choices = [];
|
||||||
|
let i = 0;
|
||||||
|
args.forEach(arg => {
|
||||||
|
i++;
|
||||||
|
choices.push({ body: arg, id: `button${i}` });
|
||||||
|
});
|
||||||
|
|
||||||
|
const button = new Buttons(Messages[locale].choices, choices, ' ', ' ');
|
||||||
|
|
||||||
|
await this.talk(button);
|
||||||
|
GBLog.info(`BASIC: HEAR with ${args.toString()} (Asking for input).`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
GBLog.info('BASIC: HEAR (Asking for input).');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the user to answer.
|
||||||
|
|
||||||
|
let sleep = ms => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(resolve, ms);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
this.min.cbMap[userId] = {}
|
||||||
|
this.min.cbMap[userId]['promise'] = '!GBHEAR';
|
||||||
|
|
||||||
|
while (this.min.cbMap[userId].promise === '!GBHEAR') {
|
||||||
|
await sleep(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = this.min.cbMap[userId].promise;
|
||||||
|
|
||||||
|
if (kind === "file") {
|
||||||
|
await step.prompt('attachmentPrompt', {});
|
||||||
|
|
||||||
|
// Prepare Promises to download each attachment and then execute each Promise.
|
||||||
|
const promises = step.context.activity.attachments.map(
|
||||||
|
DialogKeywords.downloadAttachmentAndWrite);
|
||||||
|
const successfulSaves = await Promise.all(promises);
|
||||||
|
|
||||||
|
async function replyForReceivedAttachments(localAttachmentData) {
|
||||||
|
if (localAttachmentData) {
|
||||||
|
// Because the TurnContext was bound to this function, the bot can call
|
||||||
|
// `TurnContext.sendActivity` via `this.sendActivity`;
|
||||||
|
await this.sendActivity(`Upload OK.`);
|
||||||
|
} else {
|
||||||
|
await this.sendActivity('Error uploading file. Please, start again.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare Promises to reply to the user with information about saved attachments.
|
||||||
|
// The current TurnContext is bound so `replyForReceivedAttachments` can also send replies.
|
||||||
|
const replyPromises = successfulSaves.map(replyForReceivedAttachments.bind(step.context));
|
||||||
|
await Promise.all(replyPromises);
|
||||||
|
|
||||||
|
result = {
|
||||||
|
data: fs.readFileSync(successfulSaves[0]['localPath']),
|
||||||
|
filename: successfulSaves[0]['fileName']
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (kind === "boolean") {
|
||||||
|
if (isIntentYes('pt-BR', text)) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (kind === "email") {
|
||||||
|
|
||||||
|
const extractEntity = (text) => {
|
||||||
|
return text.match(/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)/gi);
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = extractEntity(text);
|
||||||
|
|
||||||
|
if (value === null) {
|
||||||
|
await this.talk("Por favor, digite um e-mail válido.");
|
||||||
|
return await this.hear(step, kind, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = value;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (kind === "name") {
|
||||||
|
const extractEntity = text => {
|
||||||
|
return text.match(/[_a-zA-Z][_a-zA-Z0-9]{0,16}/gi);
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = extractEntity(text);
|
||||||
|
|
||||||
|
if (value === null || value.length != 1) {
|
||||||
|
await this.talk("Por favor, digite um nome válido.");
|
||||||
|
return await this.hear(step, kind, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = value;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (kind === "integer") {
|
||||||
|
const extractEntity = text => {
|
||||||
|
return text.match(/\d+/gi);
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = extractEntity(text);
|
||||||
|
|
||||||
|
if (value === null || value.length != 1) {
|
||||||
|
await this.talk("Por favor, digite um número válido.");
|
||||||
|
return await this.hear(step, kind, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = value;
|
||||||
|
}
|
||||||
|
else if (kind === "date") {
|
||||||
|
const extractEntity = text => {
|
||||||
|
return text.match(/(^(((0[1-9]|1[0-9]|2[0-8])[\/](0[1-9]|1[012]))|((29|30|31)[\/](0[13578]|1[02]))|((29|30)[\/](0[4,6,9]|11)))[\/](19|[2-9][0-9])\d\d$)|(^29[\/]02[\/](19|[2-9][0-9])(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)$)/gi);
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = extractEntity(text);
|
||||||
|
|
||||||
|
if (value === null || value.length != 1) {
|
||||||
|
await this.talk("Por favor, digite uma data no formato 12/12/2020.");
|
||||||
|
return await this.hear(step, kind, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = value;
|
||||||
|
}
|
||||||
|
else if (kind === "hour") {
|
||||||
|
|
||||||
|
const extractEntity = text => {
|
||||||
|
return text.match(/^([0-1]?[0-9]|2[0-4]):([0-5][0-9])(:[0-5][0-9])?$/gi);
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = extractEntity(text);
|
||||||
|
|
||||||
|
if (value === null || value.length != 1) {
|
||||||
|
await this.talk("Por favor, digite um horário no formato hh:ss.");
|
||||||
|
return await this.hear(step, kind, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = value;
|
||||||
|
}
|
||||||
|
else if (kind === "money") {
|
||||||
|
const extractEntity = text => {
|
||||||
|
|
||||||
|
if (step.context.locale === 'en') { // TODO: Change to user.
|
||||||
|
return text.match(/(?:\d{1,3},)*\d{1,3}(?:\.\d+)?/gi);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return text.match(/(?:\d{1,3}.)*\d{1,3}(?:\,\d+)?/gi);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = extractEntity(text);
|
||||||
|
|
||||||
|
if (value === null || value.length != 1) {
|
||||||
|
await this.talk("Por favor, digite um valor monetário.");
|
||||||
|
return await this.hear(step, kind, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = value;
|
||||||
|
}
|
||||||
|
else if (kind === "mobile") {
|
||||||
|
const locale = step.context.activity.locale;
|
||||||
|
let phoneNumber;
|
||||||
|
try {
|
||||||
|
phoneNumber = phone(text, 'BRA')[0]; // TODO: Use accordingly to the person.
|
||||||
|
phoneNumber = phoneUtil.parse(phoneNumber);
|
||||||
|
} catch (error) {
|
||||||
|
await this.talk(Messages[locale].validation_enter_valid_mobile);
|
||||||
|
|
||||||
|
return await this.hear(step, kind, args);
|
||||||
|
}
|
||||||
|
if (!phoneUtil.isPossibleNumber(phoneNumber)) {
|
||||||
|
await this.talk("Por favor, digite um número de telefone válido.");
|
||||||
|
return await this.hear(step, kind, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = phoneNumber;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (kind === "zipcode") {
|
||||||
|
const extractEntity = text => {
|
||||||
|
|
||||||
|
text = text.replace(/\-/gi, '');
|
||||||
|
|
||||||
|
if (step.context.locale === 'en') { // TODO: Change to user.
|
||||||
|
return text.match(/\d{8}/gi);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return text.match(/(?:\d{1,3}.)*\d{1,3}(?:\,\d+)?/gi);
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = extractEntity(text);
|
||||||
|
|
||||||
|
if (value === null || value.length != 1) {
|
||||||
|
await this.talk("Por favor, digite um valor monetário.");
|
||||||
|
return await this.hear(step, kind, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = value[0];
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (kind === "menu") {
|
||||||
|
|
||||||
|
const list = args;
|
||||||
|
result = null;
|
||||||
|
await CollectionUtil.asyncForEach(list, async item => {
|
||||||
|
if (GBConversationalService.kmpSearch(text, item) != -1) {
|
||||||
|
result = item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result === null) {
|
||||||
|
await this.talk(`Escolha por favor um dos itens sugeridos.`);
|
||||||
|
return await this.hear(step, kind, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (kind === "language") {
|
||||||
|
|
||||||
|
result = null;
|
||||||
|
|
||||||
|
const list = [
|
||||||
|
{ name: 'english', code: 'en' },
|
||||||
|
{ name: 'inglês', code: 'en' },
|
||||||
|
{ name: 'portuguese', code: 'pt' },
|
||||||
|
{ name: 'português', code: 'pt' },
|
||||||
|
{ name: 'français', code: 'fr' },
|
||||||
|
{ name: 'francês', code: 'fr' },
|
||||||
|
{ name: 'french', code: 'fr' },
|
||||||
|
{ name: 'spanish', code: 'es' },
|
||||||
|
{ name: 'espanõl', code: 'es' },
|
||||||
|
{ name: 'espanhol', code: 'es' },
|
||||||
|
{ name: 'german', code: 'de' },
|
||||||
|
{ name: 'deutsch', code: 'de' },
|
||||||
|
{ name: 'alemão', code: 'de' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const text = step.context.activity['originalText'];
|
||||||
|
|
||||||
|
await CollectionUtil.asyncForEach(list, async item => {
|
||||||
|
if (GBConversationalService.kmpSearch(text.toLowerCase(), item.name.toLowerCase()) != -1 ||
|
||||||
|
GBConversationalService.kmpSearch(text.toLowerCase(), item.code.toLowerCase()) != -1) {
|
||||||
|
result = item.code;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result === null) {
|
||||||
|
await this.min.conversationalService.sendText(this.min, step, `Escolha por favor um dos idiomas sugeridos.`);
|
||||||
|
return await this.hear(step, kind, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
GBLog.error(`BASIC RUNTIME ERR HEAR ${error.message ? error.message : error}\n Stack:${error.stack}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -953,10 +1264,14 @@ export class DialogKeywords {
|
||||||
/**
|
/**
|
||||||
* Talks to the user by using the specified text.
|
* Talks to the user by using the specified text.
|
||||||
*/
|
*/
|
||||||
public async talk(step, text: string) {
|
public async talk(text: string) {
|
||||||
|
GBLog.info(`BASIC: TALK '${text}'.`);
|
||||||
const translate = this.user ? this.user.basicOptions.translatorOn : false;
|
const translate = this.user ? this.user.basicOptions.translatorOn : false;
|
||||||
await this.min.conversationalService['sendTextWithOptions'](this.min, step, text,
|
// TODO: Translate.
|
||||||
translate, null);
|
|
||||||
|
|
||||||
|
await this.min.conversationalService['sendOnConversation'](this.min,
|
||||||
|
this.user.systemUser, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static getChannel(step): string {
|
private static getChannel(step): string {
|
||||||
|
@ -965,7 +1280,7 @@ export class DialogKeywords {
|
||||||
return 'webchat';
|
return 'webchat';
|
||||||
} else {
|
} else {
|
||||||
if (step.context.activity.from && !isNaN(step.context.activity.from.id)) {
|
if (step.context.activity.from && !isNaN(step.context.activity.from.id)) {
|
||||||
return 'whatsapp';
|
return 'w}, 0);hatsapp';
|
||||||
}
|
}
|
||||||
return 'webchat';
|
return 'webchat';
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,10 +40,11 @@ import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
const urlJoin = require('url-join');
|
const urlJoin = require('url-join');
|
||||||
import { DialogKeywords } from './DialogKeywords';
|
import { DialogKeywords } from './DialogKeywords';
|
||||||
import { ScheduleServices } from './ScheduleServices';
|
import { ScheduleServices } from './ScheduleServices';
|
||||||
import { HearDialog } from '../dialogs/HearDialog';
|
|
||||||
import { GBConfigService } from '../../core.gbapp/services/GBConfigService';
|
import { GBConfigService } from '../../core.gbapp/services/GBConfigService';
|
||||||
//tslint:disable-next-line:no-submodule-imports
|
//tslint:disable-next-line:no-submodule-imports
|
||||||
const vm = require('vm');
|
const { VM } = require('vm2');
|
||||||
|
|
||||||
|
|
||||||
const vb2ts = require('./vbscript-to-typescript');
|
const vb2ts = require('./vbscript-to-typescript');
|
||||||
const beautify = require('js-beautify').js;
|
const beautify = require('js-beautify').js;
|
||||||
const textract = require('textract');
|
const textract = require('textract');
|
||||||
|
@ -65,7 +66,6 @@ const Path = require('path');
|
||||||
export class GBVMService extends GBService {
|
export class GBVMService extends GBService {
|
||||||
public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) {
|
public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) {
|
||||||
const files = await walkPromise(folder);
|
const files = await walkPromise(folder);
|
||||||
HearDialog.addHearDialog(min);
|
|
||||||
|
|
||||||
await CollectionUtil.asyncForEach(files, async file => {
|
await CollectionUtil.asyncForEach(files, async file => {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
|
@ -173,18 +173,18 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
|
|
||||||
code = `<%\n
|
code = `<%\n
|
||||||
|
step=dk.step
|
||||||
id = sys().getRandomId()
|
id = sys().getRandomId()
|
||||||
username = step ? this.userName(step) : sys().getRandomId();
|
username = step ? dk.userName(step) : sys().getRandomId();
|
||||||
mobile = step ? this.userMobile(step) : sys().getRandomId();
|
mobile = step ? dk.userMobile(step) : sys().getRandomId();
|
||||||
from = mobile;
|
from = mobile;
|
||||||
ENTER = String.fromCharCode(13);
|
ENTER = String.fromCharCode(13);
|
||||||
ubound = function(array){return array.length};
|
ubound = function(array){return array.length};
|
||||||
isarray = function(array){return Array.isArray(array) };
|
isarray = function(array){return Array.isArray(array) };
|
||||||
weekday = this.getWeekFromDate.bind(this);
|
weekday = dk.getWeekFromDate.bind(dk);
|
||||||
hour = this.getHourFromDate.bind(this);
|
hour = dk.getHourFromDate.bind(dk);
|
||||||
base64 = this.getCoded;
|
base64 = dk.getCoded;
|
||||||
tolist = this.getToLst;
|
tolist = dk.getToLst;
|
||||||
headers = {};
|
headers = {};
|
||||||
data = {};
|
data = {};
|
||||||
list = [];
|
list = [];
|
||||||
|
@ -288,7 +288,7 @@ export class GBVMService extends GBService {
|
||||||
});
|
});
|
||||||
|
|
||||||
code = code.replace(/CALL\s*(.*)/gi, ($0, $1, $2, $3) => {
|
code = code.replace(/CALL\s*(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
return `sys().callVM("${$1}", this.getMin(), this.getStep(), this.getDeployer())\n`;
|
return `sys().callVM("${$1}", dk.getMin(), dk.getStep(), dk.getDeployer())\n`;
|
||||||
});
|
});
|
||||||
|
|
||||||
code = code.replace(/(\w)\s*\=\s*find\s*(.*)/gi, ($0, $1, $2, $3) => {
|
code = code.replace(/(\w)\s*\=\s*find\s*(.*)/gi, ($0, $1, $2, $3) => {
|
||||||
|
@ -604,7 +604,7 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
const tsfile: string = `${filename}.ts`;
|
const tsfile: string = `${filename}.ts`;
|
||||||
let tsCode: string = fs.readFileSync(tsfile, 'utf8');
|
let tsCode: string = fs.readFileSync(tsfile, 'utf8');
|
||||||
tsCode = tsCode.replace(/export.*\n/gi, `export function ${mainName}(step:any) { let resolve;`);
|
tsCode = tsCode + `let resolve;`;
|
||||||
fs.writeFileSync(tsfile, tsCode);
|
fs.writeFileSync(tsfile, tsCode);
|
||||||
const tsc = new TSCompiler();
|
const tsc = new TSCompiler();
|
||||||
tsc.compile([tsfile]);
|
tsc.compile([tsfile]);
|
||||||
|
@ -621,70 +621,11 @@ export class GBVMService extends GBService {
|
||||||
// Finds all hear calls.
|
// Finds all hear calls.
|
||||||
|
|
||||||
let parsedCode = code;
|
let parsedCode = code;
|
||||||
const hearExp = /(\w+).*hear.*\((.*)\)/;
|
|
||||||
|
|
||||||
let match1;
|
|
||||||
|
|
||||||
while ((match1 = hearExp.exec(code))) {
|
|
||||||
let pos = 0;
|
|
||||||
|
|
||||||
// Writes async body.
|
|
||||||
|
|
||||||
const variable = match1[1]; // Construct variable = hear ().
|
|
||||||
const args = match1[2]; // Construct variable = hear ("A", "B").
|
|
||||||
const promiseName = `promiseFor${variable}`;
|
|
||||||
|
|
||||||
parsedCode = code.substring(pos, pos + match1.index);
|
|
||||||
parsedCode += ``;
|
|
||||||
parsedCode += `const ${promiseName}= async (step, ${variable}) => {`;
|
|
||||||
parsedCode += ` return new Promise(async (resolve, reject) => { try {`;
|
|
||||||
|
|
||||||
// Skips old construction and point to the async block.
|
|
||||||
|
|
||||||
pos = pos + match1.index;
|
|
||||||
let tempCode = code.substring(pos + match1[0].length + 1);
|
|
||||||
const start = pos;
|
|
||||||
|
|
||||||
// Balances code blocks and checks for exits.
|
|
||||||
|
|
||||||
let right = 0;
|
|
||||||
let left = 1;
|
|
||||||
let match2;
|
|
||||||
while ((match2 = /\{|\}/.exec(tempCode))) {
|
|
||||||
const c = tempCode.substring(match2.index, match2.index + 1);
|
|
||||||
|
|
||||||
if (c === '}') {
|
|
||||||
right++;
|
|
||||||
} else if (c === '{') {
|
|
||||||
left++;
|
|
||||||
}
|
|
||||||
|
|
||||||
tempCode = tempCode.substring(match2.index + 1);
|
|
||||||
pos += match2.index + 1;
|
|
||||||
|
|
||||||
if (left === right) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parsedCode += code.substring(start + match1[0].length + 1, pos + match1[0].length);
|
|
||||||
|
|
||||||
parsedCode += '}catch(error){reject(error);}});\n';
|
|
||||||
parsedCode += '}\n';
|
|
||||||
|
|
||||||
|
|
||||||
parsedCode += `hear (step, ${promiseName}, resolve, ${args === '' ? null : args});\n`;
|
|
||||||
parsedCode += code.substring(pos + match1[0].length);
|
|
||||||
|
|
||||||
// A interaction will be made for each hear.
|
|
||||||
|
|
||||||
code = parsedCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
parsedCode = this.handleThisAndAwait(parsedCode);
|
parsedCode = this.handleThisAndAwait(parsedCode);
|
||||||
|
|
||||||
parsedCode = parsedCode.replace(/(\bnow\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'await this.getNow()');
|
parsedCode = parsedCode.replace(/(\bnow\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'await dk.getNow()');
|
||||||
parsedCode = parsedCode.replace(/(\btoday\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'await this.getToday(step)');
|
parsedCode = parsedCode.replace(/(\btoday\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'await dk.getToday(step)');
|
||||||
parsedCode = parsedCode.replace(/(\bweekday\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'weekday');
|
parsedCode = parsedCode.replace(/(\bweekday\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'weekday');
|
||||||
parsedCode = parsedCode.replace(/(\bhour\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'hour');
|
parsedCode = parsedCode.replace(/(\bhour\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'hour');
|
||||||
parsedCode = parsedCode.replace(/(\btolist\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'tolist');
|
parsedCode = parsedCode.replace(/(\btolist\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'tolist');
|
||||||
|
@ -708,89 +649,89 @@ export class GBVMService extends GBService {
|
||||||
private handleThisAndAwait(code: string) {
|
private handleThisAndAwait(code: string) {
|
||||||
// this insertion.
|
// this insertion.
|
||||||
|
|
||||||
code = code.replace(/sys\(\)/gi, 'this.sys()');
|
code = code.replace(/sys\(\)/gi, 'dk.sys()');
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\btalk\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\btalk\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.talk' : $1;
|
return $1 === undefined ? 'dk.talk' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bhear\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bhear\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.hear' : $1;
|
return $1 === undefined ? 'dk.hear' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\baskEmail\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\baskEmail\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.askEmail' : $1;
|
return $1 === undefined ? 'dk.askEmail' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bsendFileTo\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bsendFileTo\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.sendFileTo' : $1;
|
return $1 === undefined ? 'dk.sendFileTo' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bsendFile\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bsendFile\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.sendFile' : $1;
|
return $1 === undefined ? 'dk.sendFile' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bsetLanguage\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bsetLanguage\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.setLanguage' : $1;
|
return $1 === undefined ? 'dk.setLanguage' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bdateAdd\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bdateAdd\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.dateAdd' : $1;
|
return $1 === undefined ? 'dk.dateAdd' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bdateDiff\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bdateDiff\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.dateDiff' : $1;
|
return $1 === undefined ? 'dk.dateDiff' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bgotoDialog\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bgotoDialog\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.gotoDialog' : $1;
|
return $1 === undefined ? 'dk.gotoDialog' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bsetMaxLines\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bsetMaxLines\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.setMaxLines' : $1;
|
return $1 === undefined ? 'dk.setMaxLines' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bsetTranslatorOn\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bsetTranslatorOn\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.setTranslatorOn' : $1;
|
return $1 === undefined ? 'dk.setTranslatorOn' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bsetTheme\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bsetTheme\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.setTheme' : $1;
|
return $1 === undefined ? 'dk.setTheme' : $1;
|
||||||
});
|
});
|
||||||
|
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bsetWholeWord\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bsetWholeWord\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.setWholeWord' : $1;
|
return $1 === undefined ? 'dk.setWholeWord' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\btransferTo\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\btransferTo\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.transferTo' : $1;
|
return $1 === undefined ? 'dk.transferTo' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bchart\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bchart\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.chart' : $1;
|
return $1 === undefined ? 'dk.chart' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bcreateDeal\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bcreateDeal\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.createDeal' : $1;
|
return $1 === undefined ? 'dk.createDeal' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bfndContact\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bfndContact\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.fndContact' : $1;
|
return $1 === undefined ? 'dk.fndContact' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bgetActiveTasks\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bgetActiveTasks\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.getActiveTasks' : $1;
|
return $1 === undefined ? 'dk.getActiveTasks' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bmenu\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bmenu\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.menu' : $1;
|
return $1 === undefined ? 'dk.menu' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bgetPage\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bgetPage\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.getPage' : $1;
|
return $1 === undefined ? 'dk.getPage' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bclick\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bclick\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.click' : $1;
|
return $1 === undefined ? 'dk.click' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\blinkByText\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\blinkByText\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.linkByText' : $1;
|
return $1 === undefined ? 'dk.linkByText' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bpressKey\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bpressKey\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.pressKey' : $1;
|
return $1 === undefined ? 'dk.pressKey' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bscreenshot\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bscreenshot\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.screenshot' : $1;
|
return $1 === undefined ? 'dk.screenshot' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bhover\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bhover\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.hover' : $1;
|
return $1 === undefined ? 'dk.hover' : $1;
|
||||||
});
|
});
|
||||||
code = code.replace(/("[^"]*"|'[^']*')|\bsendEmail\b/gi, ($0, $1) => {
|
code = code.replace(/("[^"]*"|'[^']*')|\bsendEmail\b/gi, ($0, $1) => {
|
||||||
return $1 === undefined ? 'this.sendEmail' : $1;
|
return $1 === undefined ? 'dk.sendEmail' : $1;
|
||||||
});
|
});
|
||||||
// await insertion.
|
// await insertion.
|
||||||
|
|
||||||
code = code.replace(/this\./gm, 'await this.');
|
code = code.replace(/dk\./gm, 'await dk.');
|
||||||
code = code.replace(/\nfunction/i, 'async function');
|
code = code.replace(/\nfunction/i, 'async function');
|
||||||
code = code.replace('ubound = async', 'ubound ='); // TODO: Improve this.
|
code = code.replace('ubound = async', 'ubound ='); // TODO: Improve this.
|
||||||
code = code.replace('hour = await', 'hour ='); // TODO: Improve this.
|
code = code.replace('hour = await', 'hour ='); // TODO: Improve this.
|
||||||
|
@ -837,38 +778,25 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
// Injects the .gbdialog generated code into the VM.
|
// Injects the .gbdialog generated code into the VM.
|
||||||
|
|
||||||
const context = vm.createContext(sandbox);
|
let code = min.sandBoxMap[text];
|
||||||
const code = min.sandBoxMap[text];
|
|
||||||
|
|
||||||
try {
|
code = `(async () => {${code}})();`;
|
||||||
// SEE https://github.com/patriksimek/vm2
|
sandbox['this'] = sandbox;
|
||||||
vm.runInContext(code, context);
|
const vm = new VM({
|
||||||
} catch (error) {
|
timeout: 600000,
|
||||||
throw new Error(`INVALID BASIC CODE: ${error.message} ${error.stack}`);
|
allowAsync: true,
|
||||||
}
|
sandbox: { dk: sandbox }
|
||||||
|
});
|
||||||
// Tries to find the method related to this call.
|
|
||||||
|
|
||||||
const mainMethod = text.toLowerCase();
|
|
||||||
if (!sandbox[mainMethod]) {
|
|
||||||
GBLog.error(`BASIC: Associated '${mainMethod}' dialog not found for: ${min.instance.botId}. Verify if .gbdialog is correctly published.`);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
sandbox[mainMethod].bind(sandbox);
|
|
||||||
|
|
||||||
// Calls the function.
|
// Calls the function.
|
||||||
|
|
||||||
let ret = null;
|
let ret = null;
|
||||||
try {
|
try {
|
||||||
ret = await sandbox[mainMethod](step);
|
vm.run(code)
|
||||||
if (ret == -1) {
|
|
||||||
await step.endDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`BASIC RUNTIME ERR: ${error.message ? error.message : error}\n Stack:${error.stack}`);
|
throw new Error(`BASIC RUNTIME ERR: ${error.message ? error.message : error}\n Stack:${error.stack}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ function convertImports(input, name) {
|
||||||
result = convertCode(result);
|
result = convertCode(result);
|
||||||
result = convertExpressions(result);
|
result = convertExpressions(result);
|
||||||
result = convertStrings(result);
|
result = convertStrings(result);
|
||||||
result = "\nexport function " + name + "() {\n" + result + "\n}";
|
|
||||||
for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
|
for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
|
||||||
var item = items_1[_i];
|
var item = items_1[_i];
|
||||||
result = "import {" + item.name + "} from \"" + item.path + "\"\n" + result;
|
result = "import {" + item.name + "} from \"" + item.path + "\"\n" + result;
|
||||||
|
|
|
@ -458,7 +458,7 @@ export class GBConversationalService {
|
||||||
? user.systemUser.locale
|
? user.systemUser.locale
|
||||||
: min.core.getParam<string>(min.instance, 'Locale', GBConfigService.get('LOCALE'))
|
: min.core.getParam<string>(min.instance, 'Locale', GBConfigService.get('LOCALE'))
|
||||||
);
|
);
|
||||||
GBLog.info(`Translated text(playMarkdown): ${text}.`);
|
GBLog.verbose(`Translated text(playMarkdown): ${text}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
var renderer = new marked.Renderer();
|
var renderer = new marked.Renderer();
|
||||||
|
@ -925,7 +925,7 @@ export class GBConversationalService {
|
||||||
? systemUser.locale
|
? systemUser.locale
|
||||||
: min.core.getParam<string>(min.instance, 'Locale', GBConfigService.get('LOCALE'))
|
: min.core.getParam<string>(min.instance, 'Locale', GBConfigService.get('LOCALE'))
|
||||||
);
|
);
|
||||||
GBLog.info(`Translated text(prompt): ${text}.`);
|
GBLog.verbose(`Translated text(prompt): ${text}.`);
|
||||||
}
|
}
|
||||||
if (step.activeDialog.state.options['kind'] === "file") {
|
if (step.activeDialog.state.options['kind'] === "file") {
|
||||||
return await step.prompt('attachmentPrompt', {});
|
return await step.prompt('attachmentPrompt', {});
|
||||||
|
@ -981,7 +981,7 @@ export class GBConversationalService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
GBLog.info(`Translated text(sendText): ${text}.`);
|
GBLog.verbose(`Translated text(sendText): ${text}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const analytics = new AnalyticsService();
|
const analytics = new AnalyticsService();
|
||||||
|
@ -1034,12 +1034,17 @@ export class GBConversationalService {
|
||||||
else {
|
else {
|
||||||
const ref = JSON.parse(user.conversationReference);
|
const ref = JSON.parse(user.conversationReference);
|
||||||
MicrosoftAppCredentials.trustServiceUrl(ref.serviceUrl);
|
MicrosoftAppCredentials.trustServiceUrl(ref.serviceUrl);
|
||||||
await min.bot['createConversation'](ref, async (t1) => {
|
try {
|
||||||
const ref2 = TurnContext.getConversationReference(t1.activity);
|
await min.bot['continueConversation'](ref, async (t1) => {
|
||||||
await min.bot.continueConversation(ref2, async (t2) => {
|
const ref2 = TurnContext.getConversationReference(t1.activity);
|
||||||
await t2.sendActivity(message);
|
await min.bot.continueConversation(ref2, async (t2) => {
|
||||||
|
await t2.sendActivity(message);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error) ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
const cliProgress = require('cli-progress');
|
const cliProgress = require('cli-progress');
|
||||||
const { DialogSet, TextPrompt } = require('botbuilder-dialogs');
|
const { DialogSet, TextPrompt } = require('botbuilder-dialogs');
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
const Swagger = require('swagger-client');
|
||||||
const Fs = require('fs');
|
const Fs = require('fs');
|
||||||
const request = require('request-promise-native');
|
const request = require('request-promise-native');
|
||||||
const removeRoute = require('express-remove-route');
|
const removeRoute = require('express-remove-route');
|
||||||
|
@ -171,13 +172,15 @@ export class GBMinService {
|
||||||
GBServer.globals.server.get('/instances/:botId', this.handleGetInstanceForClient.bind(this));
|
GBServer.globals.server.get('/instances/:botId', this.handleGetInstanceForClient.bind(this));
|
||||||
}
|
}
|
||||||
// Calls mountBot event to all bots.
|
// Calls mountBot event to all bots.
|
||||||
|
|
||||||
this.bar1 = new cliProgress.SingleBar({
|
|
||||||
format: '[{bar}] ({value}/{total}) Loading {botId} ...', barsize: 40,
|
|
||||||
forceRedraw: true
|
|
||||||
}, cliProgress.Presets.rect);
|
|
||||||
let i = 1;
|
let i = 1;
|
||||||
this.bar1.start(instances.length, i, { botId: "Boot" });
|
|
||||||
|
if (instances.length > 1) {
|
||||||
|
this.bar1 = new cliProgress.SingleBar({
|
||||||
|
format: '[{bar}] ({value}/{total}) Loading {botId} ...', barsize: 40,
|
||||||
|
forceRedraw: true
|
||||||
|
}, cliProgress.Presets.rect);
|
||||||
|
this.bar1.start(instances.length, i, { botId: "Boot" });
|
||||||
|
}
|
||||||
|
|
||||||
const throttledPromiseAll = async (promises) => {
|
const throttledPromiseAll = async (promises) => {
|
||||||
const MAX_IN_PROCESS = 20;
|
const MAX_IN_PROCESS = 20;
|
||||||
|
@ -204,15 +207,18 @@ export class GBMinService {
|
||||||
try {
|
try {
|
||||||
await this['mountBot'](instance);
|
await this['mountBot'](instance);
|
||||||
|
|
||||||
this.bar1.update(i++, { botId: instance.botId });
|
if (this.bar1) {
|
||||||
|
this.bar1.update(i++, { botId: instance.botId });
|
||||||
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
GBLog.error(`Error mounting bot ${instance.botId}: ${error.message}\n${error.stack}`);
|
GBLog.error(`Error mounting bot ${instance.botId}: ${error.message}\n${error.stack}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}).bind(this)));
|
}).bind(this)));
|
||||||
|
if (this.bar1) {
|
||||||
this.bar1.stop();
|
this.bar1.stop();
|
||||||
|
}
|
||||||
|
|
||||||
// Loads schedules.
|
// Loads schedules.
|
||||||
GBLog.info(`Preparing SET SCHEDULE dialog calls...`);
|
GBLog.info(`Preparing SET SCHEDULE dialog calls...`);
|
||||||
|
@ -321,6 +327,47 @@ export class GBMinService {
|
||||||
});
|
});
|
||||||
GBLog.verbose(`GeneralBots(${instance.engineName}) listening on: ${url}.`);
|
GBLog.verbose(`GeneralBots(${instance.engineName}) listening on: ${url}.`);
|
||||||
|
|
||||||
|
// Test code.
|
||||||
|
if (process.env.TEST_MESSAGE) {
|
||||||
|
const client = await new Swagger({
|
||||||
|
spec: JSON.parse(fs.readFileSync('directline-3.0.json', 'utf8')), usePromise: true
|
||||||
|
});
|
||||||
|
client.clientAuthorizations.add(
|
||||||
|
'AuthorizationBotConnector',
|
||||||
|
new Swagger.ApiKeyAuthorization('Authorization', `Bearer ${min.instance.webchatKey}`, 'header')
|
||||||
|
);
|
||||||
|
const response = await client.Conversations.Conversations_StartConversation();
|
||||||
|
const conversationId = response.obj.conversationId;
|
||||||
|
GBServer.globals.debugConversationId = conversationId;
|
||||||
|
|
||||||
|
const steps = process.env.TEST_MESSAGE.split(';');
|
||||||
|
const sleep = ms => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(resolve, ms);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
await CollectionUtil.asyncForEach(steps, async step => {
|
||||||
|
|
||||||
|
client.Conversations.Conversations_PostActivity({
|
||||||
|
conversationId: conversationId,
|
||||||
|
activity: {
|
||||||
|
textFormat: 'plain',
|
||||||
|
text: step,
|
||||||
|
type: 'message',
|
||||||
|
from: {
|
||||||
|
id: 'test',
|
||||||
|
name: 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await sleep(15000);
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Serves individual URL for each bot user interface.
|
// Serves individual URL for each bot user interface.
|
||||||
|
|
||||||
if (process.env.DISABLE_WEB !== 'true') {
|
if (process.env.DISABLE_WEB !== 'true') {
|
||||||
|
@ -663,7 +710,7 @@ export class GBMinService {
|
||||||
);
|
);
|
||||||
|
|
||||||
WhatsappDirectLine.botGroups[min.botId] = group;
|
WhatsappDirectLine.botGroups[min.botId] = group;
|
||||||
|
|
||||||
// If there is WhatsApp configuration specified, initialize
|
// If there is WhatsApp configuration specified, initialize
|
||||||
// infrastructure objects.
|
// infrastructure objects.
|
||||||
|
|
||||||
|
@ -677,7 +724,7 @@ export class GBMinService {
|
||||||
min.instance.whatsappServiceUrl,
|
min.instance.whatsappServiceUrl,
|
||||||
group
|
group
|
||||||
);
|
);
|
||||||
|
|
||||||
await min.whatsAppDirectLine.setup(true);
|
await min.whatsAppDirectLine.setup(true);
|
||||||
} else {
|
} else {
|
||||||
const minBoot = GBServer.globals.minBoot as any;
|
const minBoot = GBServer.globals.minBoot as any;
|
||||||
|
@ -687,7 +734,7 @@ export class GBMinService {
|
||||||
min.instance.whatsappBotKey,
|
min.instance.whatsappBotKey,
|
||||||
minBoot.instance.whatsappServiceKey,
|
minBoot.instance.whatsappServiceKey,
|
||||||
minBoot.instance.whatsappServiceNumber,
|
minBoot.instance.whatsappServiceNumber,
|
||||||
minBoot.instance.whatsappServiceUrl,
|
minBoot.instance.whatsappServiceUrl,
|
||||||
group
|
group
|
||||||
);
|
);
|
||||||
await min.whatsAppDirectLine.setup(false);
|
await min.whatsAppDirectLine.setup(false);
|
||||||
|
@ -796,11 +843,14 @@ export class GBMinService {
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const sec = new SecService();
|
||||||
const user = await min.userProfile.get(context, {});
|
const user = await min.userProfile.get(context, {});
|
||||||
|
const conversationReference = JSON.stringify(
|
||||||
|
TurnContext.getConversationReference(context.activity)
|
||||||
|
);
|
||||||
|
|
||||||
// First time processing.
|
// First time processing.
|
||||||
|
|
||||||
const sec = new SecService();
|
|
||||||
if (!user.loaded) {
|
if (!user.loaded) {
|
||||||
if (step.context.activity.channelId !== 'msteams') {
|
if (step.context.activity.channelId !== 'msteams') {
|
||||||
await min.conversationalService.sendEvent(min, step, 'loadInstance', {});
|
await min.conversationalService.sendEvent(min, step, 'loadInstance', {});
|
||||||
|
@ -839,6 +889,8 @@ export class GBMinService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await sec.updateConversationReferenceById(user.systemUser.userId, conversationReference);
|
||||||
|
|
||||||
if (step.context.activity.channelId !== 'msteams') {
|
if (step.context.activity.channelId !== 'msteams') {
|
||||||
const service = new KBService(min.core.sequelize);
|
const service = new KBService(min.core.sequelize);
|
||||||
const data = await service.getFaqBySubjectArray(instance.instanceId, 'faq', undefined);
|
const data = await service.getFaqBySubjectArray(instance.instanceId, 'faq', undefined);
|
||||||
|
@ -875,10 +927,7 @@ export class GBMinService {
|
||||||
step.context.activity.text = urlJoin(GBServer.globals.publicAddress, `${min.instance.botId}`, 'cache', filename);
|
step.context.activity.text = urlJoin(GBServer.globals.publicAddress, `${min.instance.botId}`, 'cache', filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
const conversationReference = JSON.stringify(
|
|
||||||
TurnContext.getConversationReference(context.activity)
|
|
||||||
);
|
|
||||||
await sec.updateConversationReferenceById(user.systemUser.userId, conversationReference);
|
|
||||||
|
|
||||||
if (!user.welcomed) {
|
if (!user.welcomed) {
|
||||||
const startDialog = min.core.getParam(min.instance, 'Start Dialog', null);
|
const startDialog = min.core.getParam(min.instance, 'Start Dialog', null);
|
||||||
|
@ -892,7 +941,7 @@ export class GBMinService {
|
||||||
|
|
||||||
// Required for F0 handling of persisted conversations.
|
// Required for F0 handling of persisted conversations.
|
||||||
|
|
||||||
GBLog.info(`User>: text:${context.activity.text} (type: ${context.activity.type}, name: ${context.activity.name}, channelId: ${context.activity.channelId}, value: ${context.activity.value})`);
|
GBLog.info(`Input> ${context.activity.text} (type: ${context.activity.type}, name: ${context.activity.name}, channelId: ${context.activity.channelId})`);
|
||||||
|
|
||||||
// Answer to specific BOT Framework event conversationUpdate to auto start dialogs.
|
// Answer to specific BOT Framework event conversationUpdate to auto start dialogs.
|
||||||
// Skips if the bot is talking.
|
// Skips if the bot is talking.
|
||||||
|
@ -1219,7 +1268,7 @@ export class GBMinService {
|
||||||
GBConfigService.get('DEFAULT_CONTENT_LANGUAGE')
|
GBConfigService.get('DEFAULT_CONTENT_LANGUAGE')
|
||||||
);
|
);
|
||||||
text = await min.conversationalService.translate(min, text, contentLocale);
|
text = await min.conversationalService.translate(min, text, contentLocale);
|
||||||
GBLog.info(`Translated text (processMessageActivity): ${text}.`);
|
GBLog.verbose(`Translated text (processMessageActivity): ${text}.`);
|
||||||
|
|
||||||
// Restores all token text back after spell checking and translation.
|
// Restores all token text back after spell checking and translation.
|
||||||
|
|
||||||
|
@ -1233,7 +1282,7 @@ export class GBMinService {
|
||||||
step.context.activity['text'] = text;
|
step.context.activity['text'] = text;
|
||||||
step.context.activity['originalText'] = originalText;
|
step.context.activity['originalText'] = originalText;
|
||||||
|
|
||||||
GBLog.info(`Final text ready for NLP/Search/.gbapp: ${text}.`);
|
GBLog.info(`Text>: ${text}.`);
|
||||||
|
|
||||||
if (user.systemUser.agentMode === 'self') {
|
if (user.systemUser.agentMode === 'self') {
|
||||||
const manualUser = await sec.getUserFromAgentSystemId(user.systemUser.userSystemId);
|
const manualUser = await sec.getUserFromAgentSystemId(user.systemUser.userSystemId);
|
||||||
|
@ -1258,9 +1307,14 @@ export class GBMinService {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
|
if (min.cbMap[user.systemUser.userId] &&
|
||||||
|
min.cbMap[user.systemUser.userId].promise == '!GBHEAR') {
|
||||||
|
min.cbMap[user.systemUser.userId].promise = text;
|
||||||
|
}
|
||||||
|
|
||||||
// If there is a dialog in course, continue to the next step.
|
// If there is a dialog in course, continue to the next step.
|
||||||
|
|
||||||
if (step.activeDialog !== undefined) {
|
else if (step.activeDialog !== undefined) {
|
||||||
await step.continueDialog();
|
await step.continueDialog();
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ export class RootData {
|
||||||
public minBoot: GBMinInstance; // Reference to boot bot.
|
public minBoot: GBMinInstance; // Reference to boot bot.
|
||||||
public wwwroot: string; // .gbui or a static webapp.
|
public wwwroot: string; // .gbui or a static webapp.
|
||||||
public entryPointDialog: string; // To replace default welcome dialog.
|
public entryPointDialog: string; // To replace default welcome dialog.
|
||||||
|
public debugConversationId: any; // Used to self-message during debug.
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* General Bots open-core entry point.
|
* General Bots open-core entry point.
|
||||||
|
@ -225,7 +226,7 @@ export class GBServer {
|
||||||
|
|
||||||
|
|
||||||
GBLog.info(`The Bot Server is in RUNNING mode...`);
|
GBLog.info(`The Bot Server is in RUNNING mode...`);
|
||||||
|
|
||||||
// Opens Navigator.
|
// Opens Navigator.
|
||||||
|
|
||||||
// TODO: Config: core.openBrowserInDevelopment();
|
// TODO: Config: core.openBrowserInDevelopment();
|
||||||
|
|
Loading…
Add table
Reference in a new issue