new(core.gbapp): Translator on input text available to any language.

This commit is contained in:
Rodrigo Rodriguez 2020-05-17 19:05:18 +00:00
parent 230a9e3cbc
commit f0bb5978d4
9 changed files with 126 additions and 9 deletions

View file

@ -29,4 +29,18 @@ ALTER TABLE [dbo].[GuaribasInstance] DROP COLUMN [authenticatorClientSecret]
GO
```
# 1.7.8
``` SQL
ALTER TABLE dbo.GuaribasUser ADD
locale nvarchar(5) NULL
GO
ALTER TABLE dbo.GuaribasInstance ADD
translatorKey nvarchar(64) NULL
translatorEndpoint nvarchar(64) NULL
GO
```

View file

@ -96,6 +96,14 @@ export class GuaribasInstance extends Model<GuaribasInstance>
@Column
public textAnalyticsEndpoint: string;
@Column({ type: DataType.STRING(64) })
public translatorKey: string;
@Column
@Column({ type: DataType.STRING(64) })
public translatorEndpoint: string;
@Column
public marketplacePassword: string;

View file

@ -44,6 +44,7 @@ import { Messages } from '../strings';
import { GBServer } from '../../../src/app';
import { Readable } from 'stream'
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
import { SecService } from '../../security.gblib/services/SecService';
const urlJoin = require('url-join');
const PasswordGenerator = require("strict-password-generator").default;
const Nexmo = require('nexmo');
@ -53,6 +54,8 @@ const { exec } = require('child_process')
const fs = require('fs')
const prism = require('prism-media')
const sdk = require("microsoft-cognitiveservices-speech-sdk");
const uuidv4 = require('uuid/v4');
const request = require('request-promise-native');
export interface LanguagePickerSettings {
defaultLocale?: string;
@ -513,6 +516,60 @@ export class GBConversationalService {
return Promise.resolve(false);
}
async translate(
key: string,
endPoint: string,
text: string,
language: string
): Promise<string> {
let options = {
method: 'POST',
baseUrl: endPoint,
url: 'translate',
qs: {
'api-version': '3.0',
'to': [language]
},
headers: {
'Ocp-Apim-Subscription-Key': key,
'Ocp-Apim-Subscription-Region': 'westeurope',
'Content-type': 'application/json',
'X-ClientTraceId': uuidv4().toString()
},
body: [{
'text': text
}],
json: true,
}
try {
const results = await request(options);
return results[0].translations[0].text;
} catch (error) {
const msg = `Error calling Translator service layer. Error is: ${error}.`;
return Promise.reject(new Error(msg));
}
}
public async sendText(min, 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);
text = await min.conversationalService.translate(
min.instance.translatorKey,
min.instance.translatorEndpoint,
text,
user.locale
);
}
public async checkLanguage(step: GBDialogStep, min, text) {
const locale = await AzureText.getLocale(min.instance.textAnalyticsKey, min.instance.textAnalyticsEndpoint, text);
if (locale !== step.context.activity.locale.split('-')[0]) {

View file

@ -44,7 +44,7 @@ const removeRoute = require('express-remove-route');
const AuthenticationContext = require('adal-node').AuthenticationContext;
const wash = require('washyourmouthoutwithsoap');
import { AutoSaveStateMiddleware, BotFrameworkAdapter, ConversationState, MemoryStorage, UserState } from 'botbuilder';
import { CollectionUtil } from 'pragmatismo-io-framework';
import { CollectionUtil, AzureText } from 'pragmatismo-io-framework';
import { ConfirmPrompt, WaterfallDialog } from 'botbuilder-dialogs';
import {
GBDialogStep,
@ -210,7 +210,6 @@ export class GBMinService {
const { min, adapter, conversationState } = await this.buildBotAdapter(instance, GBServer.globals.sysPackages);
GBServer.globals.minInstances.push(min);
await this.deployer.deployPackage(min, 'packages/default.gbdialog');
await this.deployer.deployPackage(min, 'packages/default.gbtheme');
// Install per bot deployed packages.
@ -434,7 +433,6 @@ export class GBMinService {
MicrosoftAppCredentials.trustServiceUrl('https://directline.botframework.com',
new Date(new Date().setFullYear(new Date().getFullYear() + 10)));
// The minimal bot is built here.
const min = new GBMinInstance();
@ -646,7 +644,7 @@ export class GBMinService {
// Checks for global exit kewywords cancelling any active dialogs.
const globalQuit = (locale, utterance) => {
return utterance.match(Messages[locale].global_quit);
return utterance.match(Messages.global_quit);
}
const isVMCall = Object.keys(min.scriptMap).find(key => min.scriptMap[key] === context.activity.text) !== undefined;
@ -666,7 +664,7 @@ export class GBMinService {
let args = parts.join(' ');
await step.beginDialog(dialogName, { args: args });
} else if (globalQuit(step.context.activity.locale, context.activity.text)) {
} else if (globalQuit(step.context.activity.locale, context.activity.text)) { // TODO: Hard-code additional languages.
await step.cancelAllDialogs();
await step.context.sendActivity(Messages[step.context.activity.locale].canceled);
} else if (context.activity.text === 'admin') {
@ -680,8 +678,29 @@ export class GBMinService {
if (step.activeDialog !== undefined) {
await step.continueDialog();
} else {
let query = context.activity.text;
const locale = await AzureText.getLocale(min.instance.textAnalyticsKey,
min.instance.textAnalyticsEndpoint, query);
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();
query = await min.conversationalService.translate(
min.instance.translatorKey,
min.instance.translatorEndpoint,
query,
'pt');
GBLog.info(`Translated text: ${query}.`)
await step.beginDialog('/answer', {
query: context.activity.text
query: query
});
}
}

View file

@ -1,5 +1,6 @@
export const Messages = {
global_quit: /^(sair|sai|chega|exit|quit|finish|end|ausfahrt|verlassen)/i,
'en-US': {
show_video: 'I will show you a video, please wait...',
good_morning: 'good morning',
@ -7,7 +8,6 @@ export const Messages = {
good_night: 'good night',
hi: (msg) => `Hello, ${msg}.`,
very_sorry_about_error: `I'm sorry to inform that there was an error which was recorded to be solved.`,
global_quit: /^(quit|Quit)/i,
canceled: 'Canceled. If I can be useful, let me know how',
whats_email: "What's your E-mail address?",
validation_enter_valid_email: "Please enter a valid e-mail."
@ -19,7 +19,6 @@ export const Messages = {
good_night: 'boa noite',
hi: (msg) => `Oi, ${msg}.`,
very_sorry_about_error: `Lamento, ocorreu um erro que já foi registrado para ser tratado.`,
global_quit: /^(sair|Sair)/i,
canceled: 'Cancelado, avise como posso ser útil novamente.',
whats_email: "Qual seu e-mail?",
validation_enter_valid_email: "Por favor digite um email válido."

View file

@ -0,0 +1,13 @@
rem hi
talk "Qual seu nome?"
hear name
talk "Qual seu CPF?"
hear CPF
talk "Por que você abrirá este chamado?"
hear translated motivo
talk "Seu nome: " + name
talk "Você disse em Português " + motivo.

View file

@ -44,6 +44,7 @@ import { Messages } from '../strings';
import { KBService } from './../services/KBService';
import { GuaribasAnswer } from '../models';
import { GBMinService } from '../../../packages/core.gbapp/services/GBMinService';
import { SecService } from '../../security.gblib/services/SecService';
/**
* Dialog arguments.
@ -98,7 +99,9 @@ export class AskDialog extends IGBDialog {
},
async step => {
if (step.result) {
return await step.replaceDialog('/answer', { query: step.result });
let query = step.result;
return await step.replaceDialog('/answer', { query: query });
} else {
return await step.next();
}

View file

@ -68,6 +68,9 @@ export class GuaribasUser extends Model<GuaribasUser> {
@Column public email: string;
@Column(DataType.STRING(5))
@Column public locale: string;
@ForeignKey(() => GuaribasInstance)
@Column
public instanceId: number;

View file

@ -11,6 +11,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 => {