fix(kb.gbapp): /publish review, error handling improved and clean up.

This commit is contained in:
rodrigorodriguez 2023-02-26 15:03:24 -03:00
parent b30e0160c4
commit c94228cd8d
8 changed files with 148 additions and 159 deletions

View file

@ -39,12 +39,13 @@
import crypto from 'crypto';
import urlJoin from 'url-join';
import { WaterfallDialog } from 'botbuilder-dialogs';
import { GBMinInstance, IGBDialog, GBLog, IGBPackage } from 'botlib';
import { GBMinInstance, IGBDialog } from 'botlib';
import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js';
import { GBImporter } from '../../core.gbapp/services/GBImporterService.js';
import { Messages } from '../strings.js';
import { GBAdminService } from '../services/GBAdminService.js';
import { CollectionUtil } from 'pragmatismo-io-framework';
import { SecService } from '../../security.gbapp/services/SecService.js';
/**
* Dialogs for administration tasks.
@ -144,36 +145,6 @@ export class AdminDialog extends IGBDialog {
try {
if (text === 'quit') {
return await step.replaceDialog('/');
} else if (cmdName === 'deployPackage' || cmdName === 'dp') {
await GBAdminService.deployPackageCommand(min, text, deployer);
return await step.replaceDialog('/admin', { firstRun: false });
} else if (cmdName === 'redeployPackage' || cmdName === 'rp') {
await min.conversationalService.sendText(min, step, 'The package is being *unloaded*...');
await GBAdminService.undeployPackageCommand(text, min);
await min.conversationalService.sendText(min, step, 'Now, *deploying* package...');
await GBAdminService.deployPackageCommand(min, text, deployer);
await min.conversationalService.sendText(
min,
step,
'Package deployed. Just need to rebuild the index... Doing it right now.'
);
await GBAdminService.rebuildIndexPackageCommand(min, deployer);
await min.conversationalService.sendText(min, step, 'Finished importing of that .gbkb package. Thanks.');
return await step.replaceDialog('/admin', { firstRun: false });
} else if (cmdName === 'undeployPackage' || cmdName === 'up') {
await min.conversationalService.sendText(min, step, 'The package is being *undeployed*...');
await GBAdminService.undeployPackageCommand(text, min);
await min.conversationalService.sendText(min, step, 'Package *undeployed*.');
return await step.replaceDialog('/admin', { firstRun: false });
} else if (cmdName === 'rebuildIndex' || cmdName === 'ri' || cmdName === 'Ri') {
await GBAdminService.rebuildIndexPackageCommand(min, deployer);
return await step.replaceDialog('/admin', { firstRun: false });
} else if (cmdName === 'syncBotServer') {
await GBAdminService.syncBotServerCommand(min, deployer);
return await step.replaceDialog('/admin', { firstRun: false });
} else if (cmdName === 'setupSecurity') {
return await step.beginDialog('/setupSecurity');
} else {
@ -325,18 +296,18 @@ export class AdminDialog extends IGBDialog {
packages.push(`${botId}.gbot`);
skipError = true;
} else {
await min.conversationalService.sendText(min, step, `Starting publishing for ${filename}...`);
packages.push(filename);
}
await CollectionUtil.asyncForEach(packages, async packageName => {
let cmd1;
if (
packageName.indexOf('gbdialog') !== -1 ||
packageName.indexOf('gbkb') !== -1 ||
packageName.indexOf('gbot') !== -1 ||
packageName.indexOf('gbtheme') !== -1
packageName.toLowerCase() === 'gbdialog' ||
packageName.toLowerCase() === 'gbkb' ||
packageName.toLowerCase() === 'gbot' ||
packageName.toLowerCase() === 'gbtheme'
) {
packageName = `${min.botId}.${packageName}`;
}
@ -353,10 +324,23 @@ export class AdminDialog extends IGBDialog {
const cmd2 = `undeployPackage ${packageName}`;
await GBAdminService.undeployPackageCommand(cmd2, min);
}
await GBAdminService.deployPackageCommand(min, cmd1, deployer);
await min.conversationalService.sendText(min, step, `Finished publishing ${packageName}.`);
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,
null
);
await GBAdminService.deployPackageCommand(min, user, cmd1, deployer);
});
await min.conversationalService.sendText(min, step, Messages[locale].publish_success);
await min.conversationalService.sendText(min, step, `Training is finished.`);
if (!step.activeDialog.state.options.confirm) {
return await step.replaceDialog('/ask', { isReturning: true });
} else {

View file

@ -53,6 +53,7 @@ import { caseSensitive_Numbs_SpecialCharacters_PW, lowercase_PW } from 'super-st
import crypto from 'crypto';
import Fs from 'fs';
import { GBServer } from '../../../src/app.js';
import { GuaribasUser } from '../../security.gbapp/models/index.js';
/**
* Services for server administration.
@ -138,7 +139,7 @@ export class GBAdminService implements IGBAdminService {
public static isSharePointPath(path: string) {
return path.indexOf('sharepoint.com') !== -1;
}
public static async deployPackageCommand(min: GBMinInstance, text: string, deployer: IGBDeployer) {
public static async deployPackageCommand(min: GBMinInstance, user: GuaribasUser, text: string, deployer: IGBDeployer) {
const packageName = text.split(' ')[1];
if (!this.isSharePointPath(packageName)) {
@ -146,7 +147,7 @@ export class GBAdminService implements IGBAdminService {
if (additionalPath === undefined) {
throw new Error('ADDITIONAL_DEPLOY_PATH is not set and deployPackage was called.');
}
await deployer.deployPackage(min, urlJoin(additionalPath, packageName));
await deployer['deployPackage2'](min, user, urlJoin(additionalPath, packageName));
} else {
const siteName = text.split(' ')[1];
const folderName = text.split(' ')[2];
@ -157,7 +158,7 @@ export class GBAdminService implements IGBAdminService {
// of local resources is required.
await deployer['downloadFolder'](min, Path.join('work', `${min.instance.botId}.gbai`), Path.basename(folderName));
await deployer.deployPackage(min, localFolder);
await deployer['deployPackage2'](min, user, localFolder);
}
}
public static async rebuildIndexPackageCommand(min: GBMinInstance, deployer: GBDeployer) {

View file

@ -362,15 +362,13 @@ export class GBConversationalService {
'content-type': 'application/json',
authorization: `Bearer ${min.instance.smsSecret}`
},
body:
JSON.stringify({
body: JSON.stringify({
numero: `${mobile}`,
servico: 'short',
mensagem: text,
parceiro_id: '',
codificacao: '0'
})
};
try {
@ -383,8 +381,7 @@ export class GBConversationalService {
return Promise.reject(new Error(msg));
}
} else {
return new Promise(
(resolve: any, reject: any): any => {
return new Promise((resolve: any, reject: any): any => {
const nexmo = new Nexmo({
apiKey: min.instance.smsKey,
apiSecret: min.instance.smsSecret
@ -399,8 +396,7 @@ export class GBConversationalService {
resolve(data);
}
});
}
);
});
}
}
@ -439,9 +435,7 @@ export class GBConversationalService {
const transcoder = new prism.FFmpeg({
args: ['-analyzeduration', '0', '-loglevel', '0', '-f', 'opus', '-ar', '16000', '-ac', '1']
});
Fs.createReadStream(waveFilename)
.pipe(transcoder)
.pipe(output);
Fs.createReadStream(waveFilename).pipe(transcoder).pipe(output);
let url = urlJoin(GBServer.globals.publicAddress, 'audios', oggFilenameOnly);
resolve(url);
@ -528,9 +522,7 @@ export class GBConversationalService {
text = await min.conversationalService.translate(
min,
answer,
user.locale
? user.locale
: min.core.getParam<string>(min.instance, 'Locale', GBConfigService.get('LOCALE'))
user.locale ? user.locale : min.core.getParam<string>(min.instance, 'Locale', GBConfigService.get('LOCALE'))
);
GBLog.verbose(`Translated text(playMarkdown): ${text}.`);
}
@ -851,9 +843,7 @@ export class GBConversationalService {
}
GBLog.info(
`NLP called: ${intent}, entities: ${
nlp.entities.length
}, score: ${score} > required (nlpScore): ${instanceScore}`
`NLP called: ${intent}, entities: ${nlp.entities.length}, score: ${score} > required (nlpScore): ${instanceScore}`
);
step.activeDialog.state.options.entities = nlp.entities;
@ -956,10 +946,14 @@ export class GBConversationalService {
return Promise.reject(new Error(msg));
}
} else {
const url = urlJoin(endPoint, 'translate', new URLSearchParams({
const url = urlJoin(
endPoint,
'translate',
new URLSearchParams({
'api-version': '3.0',
to: language
}).toString());
}).toString()
);
let options = {
method: 'POST',
headers: {
@ -992,9 +986,7 @@ export class GBConversationalService {
text = await min.conversationalService.translate(
min,
text,
user.locale
? user.locale
: min.core.getParam<string>(min.instance, 'Locale', GBConfigService.get('LOCALE'))
user.locale ? user.locale : min.core.getParam<string>(min.instance, 'Locale', GBConfigService.get('LOCALE'))
);
GBLog.verbose(`Translated text(prompt): ${text}.`);
}
@ -1013,10 +1005,15 @@ export class GBConversationalService {
const member = step.context.activity.from;
let sec = new SecService();
let user = await sec.getUserFromSystemId(step.context.activity.from.id);
await this['sendTextWithOptionsAndUser'](min, user, step, text, true, null);
}
public async sendTextWithOptionsAndUser(min: GBMinInstance, user, step, text, translate, keepTextList) {
const member = step ? step.context.activity.from : null;
if (translate) {
let replacements = [];
if (translate) {
// To fix MSFT bug.
if (keepTextList) {
@ -1058,7 +1055,7 @@ export class GBConversationalService {
}
analytics.createMessage(min.instance.instanceId, conversation, null, text);
if (!isNaN(member.id) && !member.id.startsWith('1000')) {
if (member && !isNaN(member.id) && !member.id.startsWith('1000')) {
const to = step.context.activity.group ? step.context.activity.group : member.id;
await min.whatsAppDirectLine.sendToDevice(to, text, step.context.activity.conversation.id);
@ -1066,7 +1063,6 @@ export class GBConversationalService {
await step.context.sendActivity(text);
}
}
public async broadcast(min: GBMinInstance, message: string) {
GBLog.info(`Sending broadcast notifications...`);

View file

@ -559,11 +559,13 @@ export class GBDeployer implements IGBDeployer {
instanceId: instanceId
});
}
public async deployPackage(min: GBMinInstance, localPath: string) {
// TODO: @alanperdomo: Adjust interface mismatch.
}
/**
* Deploys a folder into the bot storage.
*/
public async deployPackage(min: GBMinInstance, localPath: string) {
public async deployPackage2(min: GBMinInstance, user, localPath: string) {
const packageType = Path.extname(localPath);
let handled = false;
let pck = null;
@ -717,7 +719,7 @@ export class GBDeployer implements IGBDeployer {
try {
GBLogEx.info(instance.instanceId, `Acquiring rebuildIndex mutex...`);
release = await GBServer.globals.indexSemaphore.acquire();
GBLogEx.info(instance.instanceId, `Acquire rebuildIndex done.`);
const search = new AzureSearch(
instance.searchKey,
instance.searchHost,
@ -729,7 +731,11 @@ export class GBDeployer implements IGBDeployer {
try {
await search.createDataSource(dsName, dsName, 'GuaribasQuestion', 'azuresql', connectionString);
} catch (err) {
GBLog.error(err);
// If it is a 404 there is nothing to delete as it is the first creation.
if (err.code !== 400 && err.message.indexOf('already exists') !==-1) {
throw err;
}
}
// Removes the index.
@ -739,11 +745,11 @@ export class GBDeployer implements IGBDeployer {
} catch (err) {
// If it is a 404 there is nothing to delete as it is the first creation.
if (err.code !== 404 && err.code !== 'OperationNotAllowed') {
if (err.code !== 'ResourceNameAlreadyInUse') {
throw err;
}
}
GBLogEx.info(instance.instanceId, `Acquire rebuildIndex done.`);
await search.rebuildIndex(instance.searchIndexer);
release();
GBLogEx.info(instance.instanceId, `Released rebuildIndex mutex.`);

View file

@ -282,26 +282,27 @@ export class GBMinService {
// min['groupCache'] = await KBService.getGroupReplies(instance.instanceId);
GBServer.globals.minInstances.push(min);
const user = null; // No user context.
await this.deployer.deployPackage(min, 'packages/default.gbtheme');
await this.deployer['deployPackage2'](min, user, 'packages/default.gbtheme');
// Install per bot deployed packages.
let packagePath = `work/${min.botId}.gbai/${min.botId}.gbdialog`;
if (Fs.existsSync(packagePath)) {
await this.deployer.deployPackage(min, packagePath);
await this.deployer['deployPackage2'](min, user, packagePath);
}
packagePath = `work/${min.botId}.gbai/${min.botId}.gbapp`;
if (Fs.existsSync(packagePath)) {
await this.deployer.deployPackage(min, packagePath);
await this.deployer['deployPackage2'](min, user, packagePath);
}
packagePath = `work/${min.botId}.gbai/${min.botId}.gbtheme`;
if (Fs.existsSync(packagePath)) {
await this.deployer.deployPackage(min, packagePath);
await this.deployer['deployPackage2'](min, user, packagePath);
}
packagePath = `work/${min.botId}.gbai/${min.botId}.gblib`;
if (Fs.existsSync(packagePath)) {
await this.deployer.deployPackage(min, packagePath);
await this.deployer['deployPackage2'](min, user, packagePath);
}
let dir = `work/${min.botId}.gbai/cache`;
@ -375,6 +376,7 @@ export class GBMinService {
};
await CollectionUtil.asyncForEach(steps, async step => {
client.apis.Conversations.Conversations_PostActivity({
conversationId: conversationId,
activity: {
@ -388,7 +390,7 @@ export class GBMinService {
}
});
await sleep(5000);
await sleep(3000);
});
}

View file

@ -65,53 +65,52 @@ export class GuaribasSubject extends Model<GuaribasSubject> {
@PrimaryKey
@AutoIncrement
@Column(DataType.INTEGER)
subjectId: number;
@Column(DataType.INTEGER)
internalId: string;
declare subjectId: number;
@Column(DataType.STRING(255))
title: string;
declare internalId: string;
declare title: string;
@Column(DataType.STRING(512))
description: string;
declare description: string;
@Column(DataType.STRING(255))
from: string;
declare from: string;
@Column(DataType.STRING(255))
to: string;
declare to: string;
@ForeignKey(() => GuaribasSubject)
@Column(DataType.INTEGER)
parentSubjectId: number;
declare parentSubjectId: number;
@BelongsTo(() => GuaribasSubject, 'parentSubjectId')
parentSubject: GuaribasSubject;
@HasMany(() => GuaribasSubject, { foreignKey: 'parentSubjectId' })
childrenSubjects: GuaribasSubject[];
declare childrenSubjects: GuaribasSubject[];
@ForeignKey(() => GuaribasInstance)
@Column(DataType.INTEGER)
instanceId: number;
declare instanceId: number;
@BelongsTo(() => GuaribasInstance)
instance: GuaribasInstance;
declare instance: GuaribasInstance;
@ForeignKey(() => GuaribasUser)
@Column(DataType.INTEGER)
responsibleUserId: number;
declare responsibleUserId: number;
@BelongsTo(() => GuaribasUser)
responsibleUser: GuaribasUser;
declare responsibleUser: GuaribasUser;
@ForeignKey(() => GuaribasPackage)
@Column(DataType.INTEGER)
packageId: number;
declare packageId: number;
@BelongsTo(() => GuaribasPackage)
package: GuaribasPackage;
declare package: GuaribasPackage;
}
/**

View file

@ -869,8 +869,9 @@ export class KBService implements IGBKBService {
let level;
for (level = 0; level < MAX_LEVEL; level++) {
menu = row._cells[level];
if (menu && menu.text) {
const cell = row._cells[level];
if (cell && cell.text) {
menu = cell.text;
break;
}
}
@ -890,10 +891,10 @@ export class KBService implements IGBKBService {
activeChildrenGivenLevel[level] = childrenNode;
// Insert the object into JSON.
const description = row._cells[level + 1]?row._cells[level + 1].text: null;
activeObj = {
title: menu,
description: row._cells[level + 1],
description: description,
id: menu,
children: []
};
@ -984,7 +985,7 @@ export class KBService implements IGBKBService {
min['groupCache'] = await KBService.getGroupReplies(instance.instanceId);
await KBService.RefreshNER(min);
GBLog.info(`[GBDeployer] Opening package: ${localPath}`);
GBLog.info(`[GBDeployer] Start Bot Server Side Rendering... ${localPath}`);
const html = await GBSSR.getHTML(min);
const path = Path.join(
process.env.PWD,
@ -993,7 +994,7 @@ export class KBService implements IGBKBService {
`${min.instance.botId}.gbui`,
'index.html'
);
GBLogEx.info(min, `[GBDeployer] Generating SSR HTML in ${path}.`);
GBLogEx.info(min, `[GBDeployer] Saving SSR HTML in ${path}.`);
Fs.writeFileSync(path, html, 'utf8');
GBLog.info(`[GBDeployer] Finished import of ${localPath}`);

View file

@ -103,11 +103,11 @@ export class GBServer {
server.use(bodyParser.urlencoded({ extended: true }));
process.on('unhandledRejection', (err, p) => {
GBLog.error(`UNHANDLED_REJECTION(promises): ${p} ${err.toString()}`);
GBLog.error(`UNHANDLED_REJECTION(promises): ${err.toString()} ${err['stack']?'\n'+err['stack']:''}`);
});
process.on('uncaughtException', (err, origin) => {
GBLog.error(`UNCAUGHT_EXCEPTION: ${err.toString()}`);
process.on('uncaughtException', (err, p) => {
GBLog.error(`UNCAUGHT_EXCEPTION: ${err.toString()} ${err['stack']?'\n'+err['stack']:''}`);
});
// Creates working directory.