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 .
|
||||
|
|
18592
package-lock.json
generated
18592
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -98,6 +98,7 @@
|
|||
"googleapis": "75.0.0",
|
||||
"ibm-watson": "6.1.1",
|
||||
"js-beautify": "1.13.13",
|
||||
"keyv": "^4.5.0",
|
||||
"lodash": "^4.17.21",
|
||||
"luxon": "2.0.2",
|
||||
"mammoth": "^1.4.21",
|
||||
|
@ -147,6 +148,7 @@
|
|||
"url-join": "4.0.1",
|
||||
"vbscript-to-typescript": "1.0.8",
|
||||
"vhost": "^3.0.2",
|
||||
"vm2": "^3.9.11",
|
||||
"walk-promise": "0.2.0",
|
||||
"washyourmouthoutwithsoap": "1.0.2",
|
||||
"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 { WhatsappDirectLine } from '../../whatsapp.gblib/services/WhatsappDirectLine';
|
||||
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
|
||||
const DateDiff = require('date-diff');
|
||||
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 sgMail = require('@sendgrid/mail');
|
||||
|
@ -881,6 +892,49 @@ export class DialogKeywords {
|
|||
public async showMenu(step) {
|
||||
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.
|
||||
|
@ -898,32 +952,289 @@ export class DialogKeywords {
|
|||
* @example HEAR name
|
||||
*
|
||||
*/
|
||||
public async hear(step, promise, previousResolve, 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;
|
||||
public async hear(step, kind, ...args) {
|
||||
|
||||
let opts = { id: idPromise, previousResolve: previousResolve, kind: kind, args };
|
||||
try {
|
||||
|
||||
let user;
|
||||
const isIntentYes = (locale, utterance) => {
|
||||
return utterance.toLowerCase().match(Messages[locale].affirmative_sentences);
|
||||
}
|
||||
|
||||
if (this.hrOn) {
|
||||
const sec = new SecService();
|
||||
user = await sec.getUserFromAgentSystemId(this.hrOn)
|
||||
}
|
||||
else {
|
||||
user = this.user.systemUser;
|
||||
}
|
||||
const userId = user.userId;
|
||||
let result;
|
||||
|
||||
// Waits for next message in HEAR delegated context.
|
||||
const locale = user.locale ? user.locale : 'en-US';
|
||||
// TODO: https://github.com/GeneralBots/BotServer/issues/266
|
||||
|
||||
const botId = this.min.botId;
|
||||
WhatsappDirectLine.state[botId + this.hrOn] = {
|
||||
promise: promise, previousResolve: previousResolve
|
||||
};
|
||||
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 {
|
||||
|
||||
if (previousResolve !== undefined) {
|
||||
previousResolve(opts);
|
||||
} else {
|
||||
await step.beginDialog('/hear', opts);
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
await this.min.conversationalService['sendTextWithOptions'](this.min, step, text,
|
||||
translate, null);
|
||||
// TODO: Translate.
|
||||
|
||||
|
||||
await this.min.conversationalService['sendOnConversation'](this.min,
|
||||
this.user.systemUser, text);
|
||||
}
|
||||
|
||||
private static getChannel(step): string {
|
||||
|
@ -965,7 +1280,7 @@ export class DialogKeywords {
|
|||
return 'webchat';
|
||||
} else {
|
||||
if (step.context.activity.from && !isNaN(step.context.activity.from.id)) {
|
||||
return 'whatsapp';
|
||||
return 'w}, 0);hatsapp';
|
||||
}
|
||||
return 'webchat';
|
||||
}
|
||||
|
|
|
@ -40,10 +40,11 @@ import { CollectionUtil } from 'pragmatismo-io-framework';
|
|||
const urlJoin = require('url-join');
|
||||
import { DialogKeywords } from './DialogKeywords';
|
||||
import { ScheduleServices } from './ScheduleServices';
|
||||
import { HearDialog } from '../dialogs/HearDialog';
|
||||
import { GBConfigService } from '../../core.gbapp/services/GBConfigService';
|
||||
//tslint:disable-next-line:no-submodule-imports
|
||||
const vm = require('vm');
|
||||
const { VM } = require('vm2');
|
||||
|
||||
|
||||
const vb2ts = require('./vbscript-to-typescript');
|
||||
const beautify = require('js-beautify').js;
|
||||
const textract = require('textract');
|
||||
|
@ -65,7 +66,6 @@ const Path = require('path');
|
|||
export class GBVMService extends GBService {
|
||||
public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) {
|
||||
const files = await walkPromise(folder);
|
||||
HearDialog.addHearDialog(min);
|
||||
|
||||
await CollectionUtil.asyncForEach(files, async file => {
|
||||
if (!file) {
|
||||
|
@ -173,18 +173,18 @@ export class GBVMService extends GBService {
|
|||
|
||||
|
||||
code = `<%\n
|
||||
|
||||
step=dk.step
|
||||
id = sys().getRandomId()
|
||||
username = step ? this.userName(step) : sys().getRandomId();
|
||||
mobile = step ? this.userMobile(step) : sys().getRandomId();
|
||||
username = step ? dk.userName(step) : sys().getRandomId();
|
||||
mobile = step ? dk.userMobile(step) : sys().getRandomId();
|
||||
from = mobile;
|
||||
ENTER = String.fromCharCode(13);
|
||||
ubound = function(array){return array.length};
|
||||
isarray = function(array){return Array.isArray(array) };
|
||||
weekday = this.getWeekFromDate.bind(this);
|
||||
hour = this.getHourFromDate.bind(this);
|
||||
base64 = this.getCoded;
|
||||
tolist = this.getToLst;
|
||||
weekday = dk.getWeekFromDate.bind(dk);
|
||||
hour = dk.getHourFromDate.bind(dk);
|
||||
base64 = dk.getCoded;
|
||||
tolist = dk.getToLst;
|
||||
headers = {};
|
||||
data = {};
|
||||
list = [];
|
||||
|
@ -288,7 +288,7 @@ export class GBVMService extends GBService {
|
|||
});
|
||||
|
||||
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) => {
|
||||
|
@ -604,7 +604,7 @@ export class GBVMService extends GBService {
|
|||
|
||||
const tsfile: string = `${filename}.ts`;
|
||||
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);
|
||||
const tsc = new TSCompiler();
|
||||
tsc.compile([tsfile]);
|
||||
|
@ -621,70 +621,11 @@ export class GBVMService extends GBService {
|
|||
// Finds all hear calls.
|
||||
|
||||
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 = parsedCode.replace(/(\bnow\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'await this.getNow()');
|
||||
parsedCode = parsedCode.replace(/(\btoday\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'await this.getToday(step)');
|
||||
parsedCode = parsedCode.replace(/(\bnow\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'await dk.getNow()');
|
||||
parsedCode = parsedCode.replace(/(\btoday\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'await dk.getToday(step)');
|
||||
parsedCode = parsedCode.replace(/(\bweekday\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'weekday');
|
||||
parsedCode = parsedCode.replace(/(\bhour\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'hour');
|
||||
parsedCode = parsedCode.replace(/(\btolist\b)(?=(?:[^"]|"[^"]*")*$)/gi, 'tolist');
|
||||
|
@ -708,89 +649,89 @@ export class GBVMService extends GBService {
|
|||
private handleThisAndAwait(code: string) {
|
||||
// this insertion.
|
||||
|
||||
code = code.replace(/sys\(\)/gi, 'this.sys()');
|
||||
code = code.replace(/sys\(\)/gi, 'dk.sys()');
|
||||
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) => {
|
||||
return $1 === undefined ? 'this.hear' : $1;
|
||||
return $1 === undefined ? 'dk.hear' : $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) => {
|
||||
return $1 === undefined ? 'this.sendFileTo' : $1;
|
||||
return $1 === undefined ? 'dk.sendFileTo' : $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) => {
|
||||
return $1 === undefined ? 'this.setLanguage' : $1;
|
||||
return $1 === undefined ? 'dk.setLanguage' : $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) => {
|
||||
return $1 === undefined ? 'this.dateDiff' : $1;
|
||||
return $1 === undefined ? 'dk.dateDiff' : $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) => {
|
||||
return $1 === undefined ? 'this.setMaxLines' : $1;
|
||||
return $1 === undefined ? 'dk.setMaxLines' : $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) => {
|
||||
return $1 === undefined ? 'this.setTheme' : $1;
|
||||
return $1 === undefined ? 'dk.setTheme' : $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) => {
|
||||
return $1 === undefined ? 'this.transferTo' : $1;
|
||||
return $1 === undefined ? 'dk.transferTo' : $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) => {
|
||||
return $1 === undefined ? 'this.createDeal' : $1;
|
||||
return $1 === undefined ? 'dk.createDeal' : $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) => {
|
||||
return $1 === undefined ? 'this.getActiveTasks' : $1;
|
||||
return $1 === undefined ? 'dk.getActiveTasks' : $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) => {
|
||||
return $1 === undefined ? 'this.getPage' : $1;
|
||||
return $1 === undefined ? 'dk.getPage' : $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) => {
|
||||
return $1 === undefined ? 'this.linkByText' : $1;
|
||||
return $1 === undefined ? 'dk.linkByText' : $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) => {
|
||||
return $1 === undefined ? 'this.screenshot' : $1;
|
||||
return $1 === undefined ? 'dk.screenshot' : $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) => {
|
||||
return $1 === undefined ? 'this.sendEmail' : $1;
|
||||
return $1 === undefined ? 'dk.sendEmail' : $1;
|
||||
});
|
||||
// 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('ubound = async', 'ubound ='); // 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.
|
||||
|
||||
const context = vm.createContext(sandbox);
|
||||
const code = min.sandBoxMap[text];
|
||||
let code = min.sandBoxMap[text];
|
||||
|
||||
try {
|
||||
// SEE https://github.com/patriksimek/vm2
|
||||
vm.runInContext(code, context);
|
||||
} catch (error) {
|
||||
throw new Error(`INVALID BASIC CODE: ${error.message} ${error.stack}`);
|
||||
}
|
||||
|
||||
// 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);
|
||||
code = `(async () => {${code}})();`;
|
||||
sandbox['this'] = sandbox;
|
||||
const vm = new VM({
|
||||
timeout: 600000,
|
||||
allowAsync: true,
|
||||
sandbox: { dk: sandbox }
|
||||
});
|
||||
|
||||
// Calls the function.
|
||||
|
||||
let ret = null;
|
||||
try {
|
||||
ret = await sandbox[mainMethod](step);
|
||||
if (ret == -1) {
|
||||
await step.endDialog();
|
||||
}
|
||||
|
||||
vm.run(code)
|
||||
} catch (error) {
|
||||
throw new Error(`BASIC RUNTIME ERR: ${error.message ? error.message : error}\n Stack:${error.stack}`);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ function convertImports(input, name) {
|
|||
result = convertCode(result);
|
||||
result = convertExpressions(result);
|
||||
result = convertStrings(result);
|
||||
result = "\nexport function " + name + "() {\n" + result + "\n}";
|
||||
|
||||
for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
|
||||
var item = items_1[_i];
|
||||
result = "import {" + item.name + "} from \"" + item.path + "\"\n" + result;
|
||||
|
|
|
@ -458,7 +458,7 @@ export class GBConversationalService {
|
|||
? user.systemUser.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();
|
||||
|
@ -925,7 +925,7 @@ export class GBConversationalService {
|
|||
? systemUser.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") {
|
||||
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();
|
||||
|
@ -1034,12 +1034,17 @@ export class GBConversationalService {
|
|||
else {
|
||||
const ref = JSON.parse(user.conversationReference);
|
||||
MicrosoftAppCredentials.trustServiceUrl(ref.serviceUrl);
|
||||
await min.bot['createConversation'](ref, async (t1) => {
|
||||
try {
|
||||
await min.bot['continueConversation'](ref, async (t1) => {
|
||||
const ref2 = TurnContext.getConversationReference(t1.activity);
|
||||
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 { DialogSet, TextPrompt } = require('botbuilder-dialogs');
|
||||
const express = require('express');
|
||||
const Swagger = require('swagger-client');
|
||||
const Fs = require('fs');
|
||||
const request = require('request-promise-native');
|
||||
const removeRoute = require('express-remove-route');
|
||||
|
@ -171,13 +172,15 @@ export class GBMinService {
|
|||
GBServer.globals.server.get('/instances/:botId', this.handleGetInstanceForClient.bind(this));
|
||||
}
|
||||
// Calls mountBot event to all bots.
|
||||
let i = 1;
|
||||
|
||||
if (instances.length > 1) {
|
||||
this.bar1 = new cliProgress.SingleBar({
|
||||
format: '[{bar}] ({value}/{total}) Loading {botId} ...', barsize: 40,
|
||||
forceRedraw: true
|
||||
}, cliProgress.Presets.rect);
|
||||
let i = 1;
|
||||
this.bar1.start(instances.length, i, { botId: "Boot" });
|
||||
}
|
||||
|
||||
const throttledPromiseAll = async (promises) => {
|
||||
const MAX_IN_PROCESS = 20;
|
||||
|
@ -204,15 +207,18 @@ export class GBMinService {
|
|||
try {
|
||||
await this['mountBot'](instance);
|
||||
|
||||
if (this.bar1) {
|
||||
this.bar1.update(i++, { botId: instance.botId });
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
GBLog.error(`Error mounting bot ${instance.botId}: ${error.message}\n${error.stack}`);
|
||||
}
|
||||
|
||||
}).bind(this)));
|
||||
|
||||
if (this.bar1) {
|
||||
this.bar1.stop();
|
||||
}
|
||||
|
||||
// Loads schedules.
|
||||
GBLog.info(`Preparing SET SCHEDULE dialog calls...`);
|
||||
|
@ -321,6 +327,47 @@ export class GBMinService {
|
|||
});
|
||||
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.
|
||||
|
||||
if (process.env.DISABLE_WEB !== 'true') {
|
||||
|
@ -796,11 +843,14 @@ export class GBMinService {
|
|||
|
||||
|
||||
try {
|
||||
const sec = new SecService();
|
||||
const user = await min.userProfile.get(context, {});
|
||||
const conversationReference = JSON.stringify(
|
||||
TurnContext.getConversationReference(context.activity)
|
||||
);
|
||||
|
||||
// First time processing.
|
||||
|
||||
const sec = new SecService();
|
||||
if (!user.loaded) {
|
||||
if (step.context.activity.channelId !== 'msteams') {
|
||||
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') {
|
||||
const service = new KBService(min.core.sequelize);
|
||||
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);
|
||||
}
|
||||
|
||||
const conversationReference = JSON.stringify(
|
||||
TurnContext.getConversationReference(context.activity)
|
||||
);
|
||||
await sec.updateConversationReferenceById(user.systemUser.userId, conversationReference);
|
||||
|
||||
|
||||
if (!user.welcomed) {
|
||||
const startDialog = min.core.getParam(min.instance, 'Start Dialog', null);
|
||||
|
@ -892,7 +941,7 @@ export class GBMinService {
|
|||
|
||||
// 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.
|
||||
// Skips if the bot is talking.
|
||||
|
@ -1219,7 +1268,7 @@ export class GBMinService {
|
|||
GBConfigService.get('DEFAULT_CONTENT_LANGUAGE')
|
||||
);
|
||||
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.
|
||||
|
||||
|
@ -1233,7 +1282,7 @@ export class GBMinService {
|
|||
step.context.activity['text'] = text;
|
||||
step.context.activity['originalText'] = originalText;
|
||||
|
||||
GBLog.info(`Final text ready for NLP/Search/.gbapp: ${text}.`);
|
||||
GBLog.info(`Text>: ${text}.`);
|
||||
|
||||
if (user.systemUser.agentMode === 'self') {
|
||||
const manualUser = await sec.getUserFromAgentSystemId(user.systemUser.userSystemId);
|
||||
|
@ -1258,9 +1307,14 @@ export class GBMinService {
|
|||
}
|
||||
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 (step.activeDialog !== undefined) {
|
||||
else if (step.activeDialog !== undefined) {
|
||||
await step.continueDialog();
|
||||
} else {
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ export class RootData {
|
|||
public minBoot: GBMinInstance; // Reference to boot bot.
|
||||
public wwwroot: string; // .gbui or a static webapp.
|
||||
public entryPointDialog: string; // To replace default welcome dialog.
|
||||
public debugConversationId: any; // Used to self-message during debug.
|
||||
}
|
||||
/**
|
||||
* General Bots open-core entry point.
|
||||
|
|
Loading…
Add table
Reference in a new issue