fix(core.gbapp): Language features optmized.

This commit is contained in:
Rodrigo Rodriguez 2020-11-17 08:27:10 -03:00
parent f925eedeea
commit 933729ae4d
11 changed files with 276 additions and 223 deletions

53
package-lock.json generated
View file

@ -1,6 +1,6 @@
{
"name": "botserver",
"version": "2.0.12",
"version": "2.0.42",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -57,9 +57,9 @@
}
},
"@azure/cosmos": {
"version": "3.9.2",
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.9.2.tgz",
"integrity": "sha512-nS02/LyjE22osouSJGWw6DqJ34tbkEgAcysrbKyDzyiqdDKNprP8sAU43WGVr6Jxjw8jGBzg6rkHz9A+IvPcdg==",
"version": "3.9.3",
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.9.3.tgz",
"integrity": "sha512-1mh8a6LAIykz24tJvQpafXiABUfq+HSAZBFJVZXea0Rd0qG8Ia9z8AK9FtPbC1nPvDC2RID2mRIjJvYbxRM/BA==",
"requires": {
"@types/debug": "^4.1.4",
"debug": "^4.1.1",
@ -71,7 +71,7 @@
"semaphore": "^1.0.5",
"tslib": "^2.0.0",
"universal-user-agent": "^6.0.0",
"uuid": "^8.1.0"
"uuid": "^8.3.0"
},
"dependencies": {
"debug": {
@ -2526,9 +2526,9 @@
"integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ=="
},
"@types/documentdb": {
"version": "1.10.7",
"resolved": "https://registry.npmjs.org/@types/documentdb/-/documentdb-1.10.7.tgz",
"integrity": "sha512-IOob9vJEzPqKzSQdgcUrmKBZNx9ngwAB8fldI4B92/mPh3wHgTjRDW7CJDF9yDMOwvr9fM3+hq/d8I4RmbWCYQ==",
"version": "1.10.8",
"resolved": "https://registry.npmjs.org/@types/documentdb/-/documentdb-1.10.8.tgz",
"integrity": "sha512-GkOXovVMlMVTYkPomq9rOI79DmVOMZ0TDziL3H3TSlhUSm1/txi5qA49H/qZRDFsExagjnf5Cd/4xF8mXVxubw==",
"requires": {
"@types/node": "*"
}
@ -4484,9 +4484,9 @@
},
"dependencies": {
"@types/node": {
"version": "10.17.40",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.40.tgz",
"integrity": "sha512-3hZT2z2/531A5pc8hYhn1gU5Qb1SIRSgMLQ6zuHA5xtt16lWAxUGprtr8lJuc9zNJMXEIIBWfSnzqBP/4mglpA=="
"version": "10.17.44",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.44.tgz",
"integrity": "sha512-vHPAyBX1ffLcy4fQHmDyIUMUb42gHZjPHU66nhvbMzAWJqHnySGZ6STwN3rwrnSd1FHB0DI/RWgGELgKSYRDmw=="
}
}
},
@ -4608,9 +4608,9 @@
}
},
"botlib": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/botlib/-/botlib-1.6.5.tgz",
"integrity": "sha512-0K+BNnHGwryID0MCG8s3s9CVGzjyBLph7ngtZp1oBNwvfcMinGGiOtbcV3CRHdiOypPr/FFuKyqe+kBVTbOtlQ==",
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/botlib/-/botlib-1.6.7.tgz",
"integrity": "sha512-KE2WnfqMciWGGZpYcsIrjgwqnZriNhbj5kxwtsrQJbsfmSr4SToPWcP0wPlSuaa2DubtnpYcEjSzmydHH7Ag0A==",
"requires": {
"async": "3.1.0",
"botbuilder": "4.7.0",
@ -8562,9 +8562,9 @@
},
"dependencies": {
"is-buffer": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
"integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A=="
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="
}
}
},
@ -12527,6 +12527,15 @@
"resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-1.1.0.tgz",
"integrity": "sha512-dEYmUqjtbivotqjraOe8UvhT/poFfog1BQRNsZm/MSEDDESk2cQ1tvD8kGyuN07TM/zoW+n42odL8zTeJupYdQ=="
},
"node-cron": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-2.0.3.tgz",
"integrity": "sha512-eJI+QitXlwcgiZwNNSRbqsjeZMp5shyajMR81RZCqeW0ZDEj4zU9tpd4nTh/1JsBiKbF8d08FCewiipDmVIYjg==",
"requires": {
"opencollective-postinstall": "^2.0.0",
"tz-offset": "0.0.1"
}
},
"node-emoji": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
@ -16242,6 +16251,11 @@
"mimic-fn": "^2.1.0"
}
},
"opencollective-postinstall": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
"integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q=="
},
"opn": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/opn/-/opn-6.0.0.tgz",
@ -21082,6 +21096,11 @@
"function.name": "^1.0.3"
}
},
"tz-offset": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/tz-offset/-/tz-offset-0.0.1.tgz",
"integrity": "sha512-kMBmblijHJXyOpKzgDhKx9INYU4u4E1RPMB0HqmKSgWG8vEcf3exEfLh4FFfzd3xdQOw9EuIy/cP0akY6rHopQ=="
},
"uglify-js": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.0.tgz",

View file

@ -70,7 +70,7 @@
"botbuilder-ai": "4.7.0",
"botbuilder-dialogs": "4.7.0",
"botframework-connector": "4.7.0",
"botlib": "1.6.5",
"botlib": "1.6.7",
"cli-spinner": "0.2.10",
"core-js": "^3.6.5",
"dotenv-extended": "2.8.0",

View file

@ -0,0 +1,77 @@
/*****************************************************************************\
| ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' 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. |
| |
\*****************************************************************************/
/**
* @fileoverview General Bots server core.
*/
'use strict';
import { BotAdapter } from 'botbuilder';
import { WaterfallDialog } from 'botbuilder-dialogs';
import { GBMinInstance, IGBDialog } from 'botlib';
import { Messages } from '../strings';
import { SecService } from '../../security.gbapp/services/SecService';
import { GBServer } from '../../../src/app';
import { GBConversationalService } from '../services/GBConversationalService';
/**
* Dialog for the bot explains about itself.
*/
export class LanguageDialog extends IGBDialog {
/**
* Setup dialogs flows and define services call.
*
* @param bot The bot adapter.
* @param min The minimal bot instance data.
*/
public static setup(bot: BotAdapter, min: GBMinInstance) {
min.dialogs.add(new WaterfallDialog('/language', [
async step => {
const locale = step.context.activity.locale;
return await min.conversationalService.prompt (min, step,
Messages[locale].which_language);
},
async step => {
let sec = new SecService();
let from = step.context.activity.from.id;
const botId = step.result;
const instance = await min.core.loadInstanceByBotId(botId);
await sec.updateUserInstance(from, instance.instanceId);
await min.conversationalService.sendText(min, step, `Opa, vamos lá!`);
return await step.next();
}
]));
}
}

View file

@ -134,11 +134,26 @@ export class GBConfigService {
value = undefined;
break;
case 'DISABLE_WEB':
value = "false";
value = 'false';
break;
case 'STORAGE_ACQUIRE_TIMEOUT':
value = 40000;
break;
case 'LOCALE':
value = 'en';
break;
case 'LANGUAGE_DETECTOR':
value = false;
break;
case 'DEFAULT_USER_LANGUAGE':
value = 'en';
break;
case 'DEFAULT_CONTENT_LANGUAGE':
value = 'en';
break;
case 'ENABLE_SPELLING_CHECKER':
value = false;
break;
default:
GBLog.warn(`Invalid key on .env file: '${key}'`);
break;

View file

@ -44,12 +44,12 @@ import { Readable } from 'stream';
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
import { SecService } from '../../security.gbapp/services/SecService';
import { AnalyticsService } from '../../analytics.gblib/services/AnalyticsService';
import { CollectionUtil } from 'pragmatismo-io-framework';
import { WaterfallStep, WaterfallStepContext } from 'botbuilder-dialogs';
import { MicrosoftAppCredentials } from 'botframework-connector';
import { GBConfigService } from './GBConfigService';
const urlJoin = require('url-join');
const PasswordGenerator = require('strict-password-generator').default;
const Nexmo = require('nexmo');
import { CollectionUtil, AzureText } from 'pragmatismo-io-framework';
const { join } = require('path');
const shell = require('any-shell-escape');
const { exec } = require('child_process');
@ -477,7 +477,7 @@ export class GBConversationalService {
let nlp: RecognizerResult;
try {
const saved = step.context.activity.text
const saved = step.context.activity.text;
step.context.activity.text = text;
nlp = await model.recognize(step.context);
step.context.activity.text = saved;
@ -516,7 +516,9 @@ export class GBConversationalService {
return false;
}
GBLog.info(`NLP called: ${intent}, entities: ${nlp.entities.length}, score: ${score} > required (nlpScore): ${min.instance.nlpScore}`);
GBLog.info(
`NLP called: ${intent}, entities: ${nlp.entities.length}, score: ${score} > required (nlpScore): ${min.instance.nlpScore}`
);
try {
step.activeDialog.state.options.entities = nlp.entities;
@ -533,14 +535,39 @@ export class GBConversationalService {
return false;
}
async translate(min: GBMinInstance, key: string, endPoint: string, text: string, language: string): Promise<string> {
public async getLanguage(min: GBMinInstance, text: string): Promise<string> {
return await AzureText.getLocale(
min.instance.textAnalyticsKey ? min.instance.textAnalyticsKey : min.instance.textAnalyticsKey,
min.instance.textAnalyticsEndpoint ? min.instance.textAnalyticsEndpoint :
min.instance.textAnalyticsEndpoint,
text
);
}
public async spellCheck(min: GBMinInstance, text: string): Promise<string> {
const key = min.instance.spellcheckerKey ? min.instance.spellcheckerKey : min.instance.spellcheckerKey;
if (key) {
text = text.charAt(0).toUpperCase() + text.slice(1);
const data = await AzureText.getSpelledText(min.instance.spellcheckerKey, text);
if (data !== text) {
GBLog.info(`Spelling corrected (processMessageActivity): ${data}`);
text = data;
}
}
return text;
}
public async translate(min: GBMinInstance, text: string, language: string): Promise<string> {
const translatorEnabled = () => {
if (min.instance.params) {
const params = JSON.parse(min.instance.params);
return params ? params['Enable Worldwide Translator'] === 'TRUE' : false;
}
return false;
}; // TODO: Encapsulate.
};
const endPoint = min.instance.translatorEndpoint;
const key = min.instance.translatorKey;
if (endPoint === null || !translatorEnabled() || process.env.TRANSLATOR_DISABLED === 'true') {
return text;
@ -585,41 +612,34 @@ export class GBConversationalService {
}
public async prompt(min: GBMinInstance, step: GBDialogStep, text: string) {
const minBoot = GBServer.globals.minBoot as any;
let sec = new SecService();
const member = step.context.activity.from;
const user = await sec.ensureUser(min.instance.instanceId, member.id, member.name, '', 'web', member.name);
if (text !== null) {
text = await min.conversationalService.translate(
min,
min.instance.translatorKey ? min.instance.translatorKey : minBoot.instance.translatorKey,
min.instance.translatorEndpoint ? min.instance.translatorEndpoint : minBoot.instance.translatorEndpoint,
text,
user.locale ? user.locale : 'en'
user.locale ? user.locale : min.core.getParam<string>(min.instance, 'Locale', GBConfigService.get('LOCALE'))
);
GBLog.info(`Translated text(4): ${text}.`);
GBLog.info(`Translated text(prompt): ${text}.`);
}
return await step.prompt('textPrompt', text ? text : {});
}
public async sendText(min, step, text) {
public async sendText(min: GBMinInstance, step, text) {
let sec = new SecService();
const member = step.context.activity.from;
const user = await sec.ensureUser(min.instance.instanceId, member.id, member.name, '', 'web', member.name);
if (user) {
const minBoot = GBServer.globals.minBoot as any;
text = await min.conversationalService.translate(
min,
min.instance.translatorKey ? min.instance.translatorKey : minBoot.instance.translatorKey,
min.instance.translatorEndpoint ? min.instance.translatorEndpoint : minBoot.instance.translatorEndpoint,
text,
user.locale ? user.locale : 'en'
user.locale ? user.locale : min.core.getParam<string>(min.instance, 'Locale', GBConfigService.get('LOCALE'))
);
GBLog.info(`Translated text(5): ${text}.`);
GBLog.info(`Translated text(sendText): ${text}.`);
const analytics = new AnalyticsService();
const userProfile = await min.userProfile.get(step.context, {});
analytics.createMessage(min.instance.instanceId, userProfile.conversation, null, text);

View file

@ -76,8 +76,6 @@ import { AnalyticsService } from '../../analytics.gblib/services/AnalyticsServic
import { WhatsappDirectLine } from '../../whatsapp.gblib/services/WhatsappDirectLine';
import fs = require('fs');
import { GuaribasConversationMessage } from '../../analytics.gblib/models';
import { GBCoreService } from './GBCoreService';
import { DialogClass } from './GBAPIService';
import { GBVMService } from './GBVMService';
/**
@ -163,7 +161,6 @@ export class GBMinService {
activeMin = toSwitchMin ? toSwitchMin : GBServer.globals.minBoot;
let sec = new SecService();
let user = await sec.getUserFromSystemId(id);
if (user === null) {
@ -705,13 +702,13 @@ export class GBMinService {
}
private async processMessageActivity(context, min: GBMinInstance, step: GBDialogStep) {
let message: GuaribasConversationMessage;
const user = await min.userProfile.get(context, {});
let message: GuaribasConversationMessage;
if (process.env.PRIVACY_STORE_MESSAGES === 'true') {
const analytics = new AnalyticsService();
// Adds message to the analytics layer.
const analytics = new AnalyticsService();
const user = await min.userProfile.get(context, {});
if (user) {
message = await analytics.createMessage(
min.instance.instanceId,
@ -744,10 +741,9 @@ export class GBMinService {
parts.splice(0, 1);
let args = parts.join(' ');
if (cmdOrDialogName === '/call'){
if (cmdOrDialogName === '/call') {
await GBVMService.callVM(args, min, step, this.deployer);
}
else{
} else {
await step.beginDialog(cmdOrDialogName, { args: args });
}
} else if (globalQuit(step.context.activity.locale, context.activity.text)) {
@ -767,57 +763,48 @@ export class GBMinService {
);
await step.beginDialog('/publish', { confirm: true, firstTime: true });
} else {
let text = context.activity.text;
text = text.replace(/<([^>]+?)([^>]*?)>(.*?)<\/\1>/gi, '');
// Spells check the input text before translating.
text = await min.conversationalService.spellCheck(min, text);
// Detects user typed language and updates their locale profile if applies.
let locale = min.core.getParam<string>(
min.instance,
'Default User Language',
GBConfigService.get('DEFAULT_USER_LANGUAGE')
);
let detectLanguage = min.core.getParam<boolean>(
min.instance,
'Language Detector',
GBConfigService.get('LANGUAGE_DETECTOR') as any
);
if (detectLanguage) {
locale = await min.conversationalService.getLanguage(min, text);
const systemUser = user.systemUser;
if (systemUser.locale != locale) {
let sec = new SecService();
await sec.updateUserLocale(systemUser.userSystemId, locale);
}
}
// Translates the input text if is turned on instance params.
const originalText = context.text;
text = await min.conversationalService.translate(min, text, locale);
GBLog.info(`Translated text (processMessageActivity): ${text}.`);
context.activity.text = text;
context.activity.originalText = originalText;
// If there is a dialog in course, continue to the next step.
if (step.activeDialog !== undefined) {
await step.continueDialog();
} else {
let text = context.activity.text;
text = text.replace(/<([^>]+?)([^>]*?)>(.*?)<\/\1>/ig, "");
// Spells check the input text before translating.
const key = min.instance.spellcheckerKey ? min.instance.spellcheckerKey : min.instance.spellcheckerKey;
if (key) {
text = text.charAt(0).toUpperCase() + text.slice(1);
const data = await AzureText.getSpelledText(min.instance.spellcheckerKey, text);
if (data !== text) {
GBLog.info(`Spelling corrected: ${data}`);
text = data;
}
}
let locale = 'en';
if (
process.env.TRANSLATOR_DISABLED !== 'true' ||
min.core.getParam<boolean>(min.instance, 'Enable Worldwide Translator')
) {
const minBoot = GBServer.globals.minBoot as any; // TODO: Switch keys automatically to master/per bot.
locale = await AzureText.getLocale(
minBoot.instance.textAnalyticsKey ? minBoot.instance.textAnalyticsKey : minBoot.instance.textAnalyticsKey,
minBoot.instance.textAnalyticsEndpoint
? minBoot.instance.textAnalyticsEndpoint
: minBoot.instance.textAnalyticsEndpoint,
text
);
}
let sec = new SecService();
const member = step.context.activity.from;
const user = await sec.ensureUser(min.instance.instanceId, member.id, member.name, '', 'web', member.name);
user.locale = locale;
await user.save();
const minBoot = GBServer.globals.minBoot as any;
const notTranslatedQuery = text;
text = await min.conversationalService.translate(
min,
min.instance.translatorKey ? min.instance.translatorKey : minBoot.instance.translatorKey,
min.instance.translatorEndpoint ? min.instance.translatorEndpoint : minBoot.instance.translatorEndpoint,
text,
'en'
);
GBLog.info(`Translated text (1): ${text}.`);
// Checks if any .gbapp will handle this answer, if not goes to kb.gbapp.
// Checks if any .gbapp will handle this answer, if not goes to standard kb.gbapp.
let handled = false;
await CollectionUtil.asyncForEach(min.appPackages, async (e: IGBPackage) => {
@ -825,7 +812,7 @@ export class GBMinService {
await e.onExchangeData(min, 'handleAnswer', {
query: text,
step: step,
notTranslatedQuery: notTranslatedQuery,
notTranslatedQuery: originalText,
message: message ? message['dataValues'] : null,
user: user ? user['dataValues'] : null
})
@ -833,7 +820,6 @@ export class GBMinService {
handled = true;
}
});
if (!handled) {
await step.beginDialog('/answer', {
query: text,

View file

@ -10,9 +10,10 @@ export const Messages = {
very_sorry_about_error: `I'm sorry to inform that there was an error which was recorded to be solved.`,
canceled: 'Canceled. If I can be useful, let me know how',
whats_email: "What's your E-mail address?",
which_language: "Which language would you like to choose from?",
validation_enter_valid_email: "Please enter a valid e-mail." ,
affirmative_sentences: /^(sim|s|positivo|afirmativo|claro|evidente|sem dúvida|confirmo|confirmar|confirmado|uhum)/i,
},
'pt-BR': {
show_video: 'Vou te mostrar um vídeo. Por favor, aguarde...',
@ -23,6 +24,7 @@ export const Messages = {
very_sorry_about_error: `Lamento, ocorreu um erro que já foi registrado para ser tratado.`,
canceled: 'Cancelado, avise como posso ser útil novamente.',
whats_email: "Qual seu e-mail?",
which_language: "Qual idioma você gostaria de usar?",
validation_enter_valid_email: "Por favor digite um email válido.",
affirmative_sentences: /^(sim|s|positivo|afirmativo|claro|evidente|sem dúvida|confirmo|confirmar|confirmado|uhum)/i,

View file

@ -106,56 +106,12 @@ export class AskDialog extends IGBDialog {
},
async step => {
if (step.result) {
const translatorEnabled = () => {
if (min.instance.params) {
const params = JSON.parse(min.instance.params);
return params ? params['Enable Worldwide Translator'] === 'TRUE' : false;
}
return false;
}; // TODO: Encapsulate.
let text = step.result;
text = text.replace(/<([^>]+?)([^>]*?)>(.*?)<\/\1>/ig, "");
let locale = 'en';
const minBoot = GBServer.globals.minBoot as any;
if (process.env.TRANSLATOR_DISABLED !== 'true' && translatorEnabled()) {
locale = await AzureText.getLocale(
minBoot.instance.textAnalyticsKey ? minBoot.instance.textAnalyticsKey : minBoot.instance.textAnalyticsKey,
minBoot.instance.textAnalyticsEndpoint
? minBoot.instance.textAnalyticsEndpoint
: minBoot.instance.textAnalyticsEndpoint,
text
);
}
text = text.replace(/<([^>]+?)([^>]*?)>(.*?)<\/\1>/gi, '');
let sec = new SecService();
const member = step.context.activity.from;
// Spells check the input text before translating.
text = text.charAt(0).toUpperCase() + text.slice(1);
const key = min.instance.spellcheckerKey ? min.instance.spellcheckerKey : min.instance.spellcheckerKey;
if (key) {
const data = await AzureText.getSpelledText(min.instance.spellcheckerKey, text);
if (data !== text) {
GBLog.info(`Spelling corrected (3): ${data}`);
text = data;
}
}
const user = await sec.ensureUser(min.instance.instanceId, member.id, member.name, '', 'web', member.name);
user.locale = locale;
await user.save();
const notTranslatedQuery = text;
text = await min.conversationalService.translate(
min,
min.instance.translatorKey ? min.instance.translatorKey : minBoot.instance.translatorKey,
min.instance.translatorEndpoint ? min.instance.translatorEndpoint : minBoot.instance.translatorEndpoint,
text,
'en'
);
GBLog.info(`Translated text (3): ${text}.`);
let handled = false;
await CollectionUtil.asyncForEach(min.appPackages, async (e: IGBPackage) => {
@ -163,7 +119,6 @@ export class AskDialog extends IGBDialog {
await e.onExchangeData(min, 'handleAnswer', {
query: text,
step: step,
notTranslatedQuery: notTranslatedQuery,
message: text,
user: user ? user['dataValues'] : null
})
@ -189,106 +144,92 @@ export class AskDialog extends IGBDialog {
private static getAnswerDialog(min: GBMinInstance, service: KBService) {
return [
async step => {
let answer: GuaribasAnswer = null;
const user = await min.userProfile.get(step.context, {});
let text = step.options.query;
text = text.replace(/<([^>]+?)([^>]*?)>(.*?)<\/\1>/ig, "");
let sec = new SecService();
const member = step.context.activity.from;
const userDb = await sec.ensureUser(min.instance.instanceId, member.id, member.name, '', 'web', member.name);
const minBoot = GBServer.globals.minBoot as any;
// Spells check the input text before translating.
const key = min.instance.spellcheckerKey ? minBoot.instance.spellcheckerKey : min.instance.spellcheckerKey;
if (key) {
text = text.charAt(0).toUpperCase() + text.slice(1);
const data = await AzureText.getSpelledText(min.instance.spellcheckerKey, text);
if (data !== text) {
GBLog.info(`Spelling corrected: ${data}`);
text = data;
}
}
// Translates text before sending Search or NLP.
text = await min.conversationalService.translate(
min,
min.instance.translatorKey ? min.instance.translatorKey : minBoot.instance.translatorKey,
min.instance.translatorEndpoint ? min.instance.translatorEndpoint : minBoot.instance.translatorEndpoint,
text,
userDb.locale ? userDb.locale : 'en'
);
GBLog.info(`Translated text (2): ${text}`);
let text = step.options.query;
text = text.replace(/<([^>]+?)([^>]*?)>(.*?)<\/\1>/gi, '');
if (!text) {
throw new Error(`/answer being called with no args query text.`);
}
const locale = step.context.activity.locale;
// Stops any content on projector.
await min.conversationalService.sendEvent(min, step, 'stop', undefined);
// Handle extra text from FAQ.
if (step.options && step.options.query) {
text = step.options.query;
} else if (step.options && step.options.fromFaq) {
await min.conversationalService.sendText(min, step, Messages[locale].going_answer);
}
const searchScore = min.instance.searchScore ? min.instance.searchScore : minBoot.instance.searchScore;
// Searches KB for the first time.
const searchScore = min.instance.searchScore ? min.instance.searchScore : minBoot.instance.searchScore;
user.lastQuestion = text;
await min.userProfile.set(step.context, user);
const resultsA = await service.ask(min.instance, text, searchScore, user.subjects);
// If there is some result, answer immediately.
if (resultsA !== undefined && resultsA.answer !== undefined) {
// Saves some context info.
user.isAsking = false;
user.lastQuestionId = resultsA.questionId;
await min.userProfile.set(step.context, user);
// Sends the answer to all outputs, including projector.
return await AskDialog.handleAnswer(service, min, step, resultsA.answer);
} else {
// Second time running Search, now with no filter.
answer = resultsA.answer;
// If this search was restricted to some subjects...
} else if (user.subjects) {
// ...second time running Search, now with no filter.
const resultsB = await service.ask(min.instance, text, searchScore, undefined);
// If there is some result, answer immediately.
if (resultsB !== undefined && resultsB.answer !== undefined) {
if (resultsB !== undefined && resultsB.answer !== undefined)
{
// Saves some context info.
const user2 = await min.userProfile.get(step.context, {});
user2.isAsking = false;
user2.lastQuestionId = resultsB.questionId;
await min.userProfile.set(step.context, user2);
// Informs user that a broader search will be used.
if (user2.subjects.length > 0) {
await min.conversationalService.sendText(min, step, Messages[locale].wider_answer);
}
// TODO: Put braces in this IF statment.
if (resultsB.answer)
// Sends the answer to all outputs, including projector.
return await AskDialog.handleAnswer(service, min, step, resultsA.answer);
} else {
if (!(await min.conversationalService.routeNLP(step, min, text))) {
await min.conversationalService.sendText(min, step, Messages[locale].did_not_find);
return await step.replaceDialog('/ask', { isReturning: true });
}
answer = resultsB.answer;
}
}
// Answers using Search or NLP responses.
if (answer) {
return await AskDialog.handleAnswer(service, min, step, answer);
} else if (!(await min.conversationalService.routeNLP(step, min, text))) {
await min.conversationalService.sendText(min, step, Messages[locale].did_not_find);
return await step.replaceDialog('/ask', { isReturning: true });
}
}
];
}
private static async handleAnswer(service: KBService, min: GBMinInstance, step: any, answer: GuaribasAnswer) {
const text = answer.content
const text = answer.content;
if (text.endsWith('.docx')) {
const mainName = GBVMService.getMethodNameFromVBSFilename(text);
return await GBVMService.callVM(mainName, min, step, this.deployer);

View file

@ -205,8 +205,6 @@ export class KBService implements IGBKBService {
const values = results.result.value;
if (values && values.length > 0 && values[0]['@search.score'] >= searchScore) {
const value = await this.getAnswerById(instance.instanceId, values[0].answerId);
if (value !== null) {
@ -216,7 +214,6 @@ export class KBService implements IGBKBService {
}
}
} else {
const data = await this.getAnswerByText(instance.instanceId, query);
if (data) {
return { answer: data.answer, questionId: data.question.questionId };
@ -288,12 +285,11 @@ export class KBService implements IGBKBService {
// Finds a valid worksheet because Excel returns empty slots
// when loading worksheets collection.
let worksheet: any;
for (let t = 0; t < data._worksheets.length; t++) {
worksheet = data._worksheets[t];
if (worksheet)
{
if (worksheet) {
break;
}
}
@ -302,7 +298,6 @@ export class KBService implements IGBKBService {
GBLog.info(`Now importing ${rows.length} rows from tabular file ${filePath}...`);
return asyncPromise.eachSeries(rows, async line => {
// Skips the first line.
if (
@ -313,7 +308,6 @@ export class KBService implements IGBKBService {
line._cells[3] !== undefined &&
line._cells[4] !== undefined
) {
// Extracts values from columns in the current line.
const subjectsText = line._cells[0].text;
@ -437,20 +431,18 @@ export class KBService implements IGBKBService {
step: GBDialogStep,
conversationalService: IGBConversationalService
) {
let sec = new SecService();
const member = step.context.activity.from;
const user = await sec.ensureUser(min.instance.instanceId, member.id, member.name, '', 'web', member.name);
const minBoot = GBServer.globals.minBoot as any;
const user = await min.userProfile.get(step.context, {});
// Calls language translator.
let text = await min.conversationalService.translate(
min,
min.instance.translatorKey ? min.instance.translatorKey : minBoot.instance.translatorKey,
min.instance.translatorEndpoint ? min.instance.translatorEndpoint : minBoot.instance.translatorEndpoint,
answer.content,
user.locale ? user.locale : 'en'
user.systemUser.locale
? user.locale
: min.core.getParam<string>(min.instance, 'Locale', GBConfigService.get('LOCALE'))
);
GBLog.info(`Translated text(playMarkdown): ${text}.`);
// Converts from Markdown to HTML.
@ -492,18 +484,6 @@ export class KBService implements IGBKBService {
html: string,
answer: GuaribasAnswer
) {
let sec = new SecService();
const member = step.context.activity.from;
const user = await sec.ensureUser(min.instance.instanceId, member.id, member.name, '', 'web', member.name);
const minBoot = GBServer.globals.minBoot as any;
html = await min.conversationalService.translate(
min,
min.instance.translatorKey ? min.instance.translatorKey : minBoot.instance.translatorKey,
min.instance.translatorEndpoint ? min.instance.translatorEndpoint : minBoot.instance.translatorEndpoint,
html,
user.locale ? user.locale : 'pt'
);
const locale = step.context.activity.locale;
await min.conversationalService.sendText(min, step, Messages[locale].will_answer_projector);
html = html.replace(/src\=\"kb\//gi, `src=\"../kb/`);

View file

@ -10,6 +10,7 @@ import { CollectionUtil } from 'pragmatismo-io-framework';
* Security service layer.
*/
export class SecService extends GBService {
public async importSecurityFile(localPath: string, instance: IGBInstance) {
const security = JSON.parse(Fs.readFileSync(urlJoin(localPath, 'security.json'), 'utf8'));
await CollectionUtil.asyncForEach(security.groups, async group => {
@ -81,6 +82,17 @@ export class SecService extends GBService {
await user.save();
}
public async updateUserLocale(userSystemId: number, locale: any) : Promise<GuaribasUser> {
let user = await GuaribasUser.findOne({
where: {
userSystemId: userSystemId
}
});
user.locale = locale;
return await user.save();
}
public async updateUserInstance(userSystemId: string, instanceId: number): Promise<GuaribasUser> {
let user = await GuaribasUser.findOne({
where: {
@ -171,6 +183,8 @@ export class SecService extends GBService {
return agentSystemId;
}
public async getUserFromSystemId(systemId: string): Promise<GuaribasUser> {
return await GuaribasUser.findOne({
where: {

View file

@ -419,13 +419,12 @@ export class WhatsappDirectLine extends GBService {
await this.sendFileToDevice(to, url, 'Audio', msg);
}
public async sendToDeviceEx(to, msg, locale) {
private async sendToDeviceEx(to, text, locale) {
const minBoot = GBServer.globals.minBoot as any;
const text = await this.min.conversationalService.translate(this.min,
this.min.instance.translatorKey ? this.min.instance.translatorKey : minBoot.instance.translatorKey,
this.min.instance.translatorEndpoint ? this.min.instance.translatorEndpoint : minBoot.instance.translatorEndpoint,
msg,
text = await minBoot.conversationalService.translate(
minBoot,
text,
locale
);
await this.sendToDevice(to, text);