new(core.gbapp): Translator on input text available to any language.
This commit is contained in:
parent
230a9e3cbc
commit
f0bb5978d4
9 changed files with 126 additions and 9 deletions
|
@ -29,4 +29,18 @@ ALTER TABLE [dbo].[GuaribasInstance] DROP COLUMN [authenticatorClientSecret]
|
||||||
GO
|
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
|
||||||
|
|
||||||
```
|
```
|
|
@ -96,6 +96,14 @@ export class GuaribasInstance extends Model<GuaribasInstance>
|
||||||
@Column
|
@Column
|
||||||
public textAnalyticsEndpoint: string;
|
public textAnalyticsEndpoint: string;
|
||||||
|
|
||||||
|
|
||||||
|
@Column({ type: DataType.STRING(64) })
|
||||||
|
public translatorKey: string;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Column({ type: DataType.STRING(64) })
|
||||||
|
public translatorEndpoint: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
public marketplacePassword: string;
|
public marketplacePassword: string;
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ import { Messages } from '../strings';
|
||||||
import { GBServer } from '../../../src/app';
|
import { GBServer } from '../../../src/app';
|
||||||
import { Readable } from 'stream'
|
import { Readable } from 'stream'
|
||||||
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
|
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
|
||||||
|
import { SecService } from '../../security.gblib/services/SecService';
|
||||||
const urlJoin = require('url-join');
|
const urlJoin = require('url-join');
|
||||||
const PasswordGenerator = require("strict-password-generator").default;
|
const PasswordGenerator = require("strict-password-generator").default;
|
||||||
const Nexmo = require('nexmo');
|
const Nexmo = require('nexmo');
|
||||||
|
@ -53,6 +54,8 @@ const { exec } = require('child_process')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const prism = require('prism-media')
|
const prism = require('prism-media')
|
||||||
const sdk = require("microsoft-cognitiveservices-speech-sdk");
|
const sdk = require("microsoft-cognitiveservices-speech-sdk");
|
||||||
|
const uuidv4 = require('uuid/v4');
|
||||||
|
const request = require('request-promise-native');
|
||||||
|
|
||||||
export interface LanguagePickerSettings {
|
export interface LanguagePickerSettings {
|
||||||
defaultLocale?: string;
|
defaultLocale?: string;
|
||||||
|
@ -513,6 +516,60 @@ export class GBConversationalService {
|
||||||
return Promise.resolve(false);
|
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) {
|
public async checkLanguage(step: GBDialogStep, min, text) {
|
||||||
const locale = await AzureText.getLocale(min.instance.textAnalyticsKey, min.instance.textAnalyticsEndpoint, text);
|
const locale = await AzureText.getLocale(min.instance.textAnalyticsKey, min.instance.textAnalyticsEndpoint, text);
|
||||||
if (locale !== step.context.activity.locale.split('-')[0]) {
|
if (locale !== step.context.activity.locale.split('-')[0]) {
|
||||||
|
|
|
@ -44,7 +44,7 @@ const removeRoute = require('express-remove-route');
|
||||||
const AuthenticationContext = require('adal-node').AuthenticationContext;
|
const AuthenticationContext = require('adal-node').AuthenticationContext;
|
||||||
const wash = require('washyourmouthoutwithsoap');
|
const wash = require('washyourmouthoutwithsoap');
|
||||||
import { AutoSaveStateMiddleware, BotFrameworkAdapter, ConversationState, MemoryStorage, UserState } from 'botbuilder';
|
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 { ConfirmPrompt, WaterfallDialog } from 'botbuilder-dialogs';
|
||||||
import {
|
import {
|
||||||
GBDialogStep,
|
GBDialogStep,
|
||||||
|
@ -210,7 +210,6 @@ export class GBMinService {
|
||||||
const { min, adapter, conversationState } = await this.buildBotAdapter(instance, GBServer.globals.sysPackages);
|
const { min, adapter, conversationState } = await this.buildBotAdapter(instance, GBServer.globals.sysPackages);
|
||||||
GBServer.globals.minInstances.push(min);
|
GBServer.globals.minInstances.push(min);
|
||||||
|
|
||||||
await this.deployer.deployPackage(min, 'packages/default.gbdialog');
|
|
||||||
await this.deployer.deployPackage(min, 'packages/default.gbtheme');
|
await this.deployer.deployPackage(min, 'packages/default.gbtheme');
|
||||||
|
|
||||||
// Install per bot deployed packages.
|
// Install per bot deployed packages.
|
||||||
|
@ -434,7 +433,6 @@ export class GBMinService {
|
||||||
MicrosoftAppCredentials.trustServiceUrl('https://directline.botframework.com',
|
MicrosoftAppCredentials.trustServiceUrl('https://directline.botframework.com',
|
||||||
new Date(new Date().setFullYear(new Date().getFullYear() + 10)));
|
new Date(new Date().setFullYear(new Date().getFullYear() + 10)));
|
||||||
|
|
||||||
|
|
||||||
// The minimal bot is built here.
|
// The minimal bot is built here.
|
||||||
|
|
||||||
const min = new GBMinInstance();
|
const min = new GBMinInstance();
|
||||||
|
@ -646,7 +644,7 @@ export class GBMinService {
|
||||||
// Checks for global exit kewywords cancelling any active dialogs.
|
// Checks for global exit kewywords cancelling any active dialogs.
|
||||||
|
|
||||||
const globalQuit = (locale, utterance) => {
|
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;
|
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(' ');
|
let args = parts.join(' ');
|
||||||
await step.beginDialog(dialogName, { args: args });
|
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.cancelAllDialogs();
|
||||||
await step.context.sendActivity(Messages[step.context.activity.locale].canceled);
|
await step.context.sendActivity(Messages[step.context.activity.locale].canceled);
|
||||||
} else if (context.activity.text === 'admin') {
|
} else if (context.activity.text === 'admin') {
|
||||||
|
@ -680,8 +678,29 @@ export class GBMinService {
|
||||||
if (step.activeDialog !== undefined) {
|
if (step.activeDialog !== undefined) {
|
||||||
await step.continueDialog();
|
await step.continueDialog();
|
||||||
} else {
|
} 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', {
|
await step.beginDialog('/answer', {
|
||||||
query: context.activity.text
|
query: query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
export const Messages = {
|
export const Messages = {
|
||||||
|
global_quit: /^(sair|sai|chega|exit|quit|finish|end|ausfahrt|verlassen)/i,
|
||||||
'en-US': {
|
'en-US': {
|
||||||
show_video: 'I will show you a video, please wait...',
|
show_video: 'I will show you a video, please wait...',
|
||||||
good_morning: 'good morning',
|
good_morning: 'good morning',
|
||||||
|
@ -7,7 +8,6 @@ export const Messages = {
|
||||||
good_night: 'good night',
|
good_night: 'good night',
|
||||||
hi: (msg) => `Hello, ${msg}.`,
|
hi: (msg) => `Hello, ${msg}.`,
|
||||||
very_sorry_about_error: `I'm sorry to inform that there was an error which was recorded to be solved.`,
|
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',
|
canceled: 'Canceled. If I can be useful, let me know how',
|
||||||
whats_email: "What's your E-mail address?",
|
whats_email: "What's your E-mail address?",
|
||||||
validation_enter_valid_email: "Please enter a valid e-mail."
|
validation_enter_valid_email: "Please enter a valid e-mail."
|
||||||
|
@ -19,7 +19,6 @@ export const Messages = {
|
||||||
good_night: 'boa noite',
|
good_night: 'boa noite',
|
||||||
hi: (msg) => `Oi, ${msg}.`,
|
hi: (msg) => `Oi, ${msg}.`,
|
||||||
very_sorry_about_error: `Lamento, ocorreu um erro que já foi registrado para ser tratado.`,
|
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.',
|
canceled: 'Cancelado, avise como posso ser útil novamente.',
|
||||||
whats_email: "Qual seu e-mail?",
|
whats_email: "Qual seu e-mail?",
|
||||||
validation_enter_valid_email: "Por favor digite um email válido."
|
validation_enter_valid_email: "Por favor digite um email válido."
|
||||||
|
|
13
packages/default.gbdialog/translator.gbignore
Normal file
13
packages/default.gbdialog/translator.gbignore
Normal 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.
|
|
@ -44,6 +44,7 @@ import { Messages } from '../strings';
|
||||||
import { KBService } from './../services/KBService';
|
import { KBService } from './../services/KBService';
|
||||||
import { GuaribasAnswer } from '../models';
|
import { GuaribasAnswer } from '../models';
|
||||||
import { GBMinService } from '../../../packages/core.gbapp/services/GBMinService';
|
import { GBMinService } from '../../../packages/core.gbapp/services/GBMinService';
|
||||||
|
import { SecService } from '../../security.gblib/services/SecService';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog arguments.
|
* Dialog arguments.
|
||||||
|
@ -98,7 +99,9 @@ export class AskDialog extends IGBDialog {
|
||||||
},
|
},
|
||||||
async step => {
|
async step => {
|
||||||
if (step.result) {
|
if (step.result) {
|
||||||
return await step.replaceDialog('/answer', { query: step.result });
|
|
||||||
|
let query = step.result;
|
||||||
|
return await step.replaceDialog('/answer', { query: query });
|
||||||
} else {
|
} else {
|
||||||
return await step.next();
|
return await step.next();
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,9 @@ export class GuaribasUser extends Model<GuaribasUser> {
|
||||||
|
|
||||||
@Column public email: string;
|
@Column public email: string;
|
||||||
|
|
||||||
|
@Column(DataType.STRING(5))
|
||||||
|
@Column public locale: string;
|
||||||
|
|
||||||
@ForeignKey(() => GuaribasInstance)
|
@ForeignKey(() => GuaribasInstance)
|
||||||
@Column
|
@Column
|
||||||
public instanceId: number;
|
public instanceId: number;
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
* Security service layer.
|
* Security service layer.
|
||||||
*/
|
*/
|
||||||
export class SecService extends GBService {
|
export class SecService extends GBService {
|
||||||
|
|
||||||
public async importSecurityFile(localPath: string, instance: IGBInstance) {
|
public async importSecurityFile(localPath: string, instance: IGBInstance) {
|
||||||
const security = JSON.parse(Fs.readFileSync(urlJoin(localPath, 'security.json'), 'utf8'));
|
const security = JSON.parse(Fs.readFileSync(urlJoin(localPath, 'security.json'), 'utf8'));
|
||||||
await CollectionUtil.asyncForEach(security.groups, async group => {
|
await CollectionUtil.asyncForEach(security.groups, async group => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue