New promises and compiling.
This commit is contained in:
parent
96f78956b6
commit
0ce8d48f09
21 changed files with 1136 additions and 1191 deletions
|
@ -19,7 +19,7 @@
|
||||||
| in the LICENSE file you have received along with this program. |
|
| in the LICENSE file you have received along with this program. |
|
||||||
| |
|
| |
|
||||||
| This program is distributed in the hope that it will be useful, |
|
| This program is distributed in the hope that it will be useful, |
|
||||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| but WITHOUT ANY WARRANTY without even the implied warranty of |
|
||||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
| GNU Affero General Public License for more details. |
|
| GNU Affero General Public License for more details. |
|
||||||
| |
|
| |
|
||||||
|
@ -30,157 +30,140 @@
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
"use strict";
|
"use strict"
|
||||||
|
|
||||||
const UrlJoin = require("url-join");
|
const UrlJoin = require("url-join")
|
||||||
|
import { AzureSearch } from "pragmatismo-io-framework"
|
||||||
import { AzureSearch } from "pragmatismo-io-framework";
|
import { GBMinInstance } from "botlib"
|
||||||
const { DialogSet, TextPrompt, NumberPrompt } = require('botbuilder-dialogs');
|
import { IGBDialog } from "botlib"
|
||||||
const { createTextPrompt, createNumberPrompt } = require('botbuilder-prompts');
|
import { GBDeployer } from '../../core.gbapp/services/GBDeployer'
|
||||||
import { GBMinInstance } from "botlib";
|
import { GBImporter } from '../../core.gbapp/services/GBImporter'
|
||||||
import { IGBDialog } from "botlib";
|
import { GBConfigService } from '../../core.gbapp/services/GBConfigService'
|
||||||
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
|
import { KBService } from './../../kb.gbapp/services/KBService'
|
||||||
import { GBImporter } from '../../core.gbapp/services/GBImporter';
|
import { BotAdapter } from "botbuilder"
|
||||||
import { GBConfigService } from '../../core.gbapp/services/GBConfigService';
|
import { reject } from "async"
|
||||||
import { KBService } from './../../kb.gbapp/services/KBService';
|
|
||||||
import { BotAdapter } from "botbuilder";
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dialogs for administration tasks.
|
||||||
|
*/
|
||||||
export class AdminDialog extends IGBDialog {
|
export class AdminDialog extends IGBDialog {
|
||||||
|
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
|
||||||
|
|
||||||
let importer = new GBImporter(min.core);
|
static async undeployPackageCommand(text: any, min: GBMinInstance, dc) {
|
||||||
let deployer = new GBDeployer(min.core, importer);
|
let packageName = text.split(" ")[1]
|
||||||
|
let importer = new GBImporter(min.core)
|
||||||
min.dialogs.add("/admin", [
|
let deployer = new GBDeployer(min.core, importer)
|
||||||
async (dc, args) => {
|
dc.context.sendActivity(`Undeploying package ${packageName}...`)
|
||||||
const prompt = "Please, authenticate:";
|
let data = await deployer.undeployPackageFromLocalPath(
|
||||||
await dc.prompt('textPrompt', prompt);
|
|
||||||
},
|
|
||||||
async (dc, value) => {
|
|
||||||
let text = value;
|
|
||||||
const user = min.userState.get(dc.context);
|
|
||||||
|
|
||||||
if (
|
|
||||||
!user.authenticated ||
|
|
||||||
text === GBConfigService.get("ADMIN_PASS")
|
|
||||||
) {
|
|
||||||
user.authenticated = true;
|
|
||||||
dc.context.sendActivity(
|
|
||||||
"Welcome to Pragmatismo.io GeneralBots Administration."
|
|
||||||
);
|
|
||||||
await dc.prompt('textPrompt', "Which task do you wanna run now?");
|
|
||||||
} else {
|
|
||||||
dc.endAll();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async (dc, value) => {
|
|
||||||
var text = value;
|
|
||||||
const user = min.userState.get(dc.context);
|
|
||||||
|
|
||||||
if (text === "quit") {
|
|
||||||
user.authenticated = false;
|
|
||||||
dc.replace("/");
|
|
||||||
} else if (text === "sync") {
|
|
||||||
min.core.syncDatabaseStructure(() => { });
|
|
||||||
dc.context.sendActivity("Sync started...");
|
|
||||||
dc.replace("/admin", {
|
|
||||||
firstRun: false
|
|
||||||
});
|
|
||||||
} else if (text.split(" ")[0] === "rebuildIndex") {
|
|
||||||
AdminDialog.rebuildIndexCommand(min, dc, () =>
|
|
||||||
dc.replace("/admin", {
|
|
||||||
firstRun: false
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else if (text.split(" ")[0] === "deployPackage") {
|
|
||||||
AdminDialog.deployPackageCommand(text, dc, deployer, min, () =>
|
|
||||||
dc.replace("/admin", {
|
|
||||||
firstRun: false
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else if (text.split(" ")[0] === "redeployPackage") {
|
|
||||||
AdminDialog.undeployPackageCommand(text, min, dc, () => {
|
|
||||||
AdminDialog.deployPackageCommand(text, dc, deployer, min, () => {
|
|
||||||
dc.context.sendActivity("Redeploy done.");
|
|
||||||
dc.replace("/admin", {
|
|
||||||
firstRun: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else if (text.split(" ")[0] === "undeployPackage") {
|
|
||||||
AdminDialog.undeployPackageCommand(text, min, dc, () =>
|
|
||||||
dc.replace("/admin", {
|
|
||||||
firstRun: false
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else if (text.split(" ")[0] === "applyPackage") {
|
|
||||||
dc.context.sendActivity("Applying in progress...");
|
|
||||||
min.core.loadInstance(text.split(" ")[1], (item, err) => {
|
|
||||||
dc.context.sendActivity("Applying done...");
|
|
||||||
dc.replace("/");
|
|
||||||
});
|
|
||||||
dc.replace("/admin", {
|
|
||||||
firstRun: false
|
|
||||||
});
|
|
||||||
} else if (text.split(" ")[0] === "rat") {
|
|
||||||
min.conversationalService.sendEvent(dc, "play", { playerType: "login", data: null });
|
|
||||||
dc.context.sendActivity("Realize login clicando no botão de login, por favor...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
static undeployPackageCommand(text: any, min: GBMinInstance, dc, cb) {
|
|
||||||
let packageName = text.split(" ")[1];
|
|
||||||
let importer = new GBImporter(min.core);
|
|
||||||
let deployer = new GBDeployer(min.core, importer);
|
|
||||||
dc.context.sendActivity(`Undeploying package ${packageName}...`);
|
|
||||||
deployer.undeployPackageFromLocalPath(
|
|
||||||
min.instance,
|
min.instance,
|
||||||
UrlJoin("deploy", packageName),
|
UrlJoin("deploy", packageName))
|
||||||
(data, err) => {
|
dc.context.sendActivity(`Package ${packageName} undeployed...`)
|
||||||
dc.context.sendActivity(`Package ${packageName} undeployed...`);
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static deployPackageCommand(
|
static async deployPackageCommand(
|
||||||
text: string,
|
text: string,
|
||||||
dc,
|
dc,
|
||||||
deployer: GBDeployer,
|
deployer: GBDeployer,
|
||||||
min: GBMinInstance,
|
min: GBMinInstance,
|
||||||
cb
|
|
||||||
) {
|
) {
|
||||||
let packageName = text.split(" ")[1];
|
let packageName = text.split(" ")[1]
|
||||||
dc.context.sendActivity(`Deploying package ${packageName}... (It may take a few seconds)`);
|
dc.context.sendActivity(`Deploying package ${packageName}... (It may take a few seconds)`)
|
||||||
|
|
||||||
// TODO: Find packages in all possible locations.
|
// TODO: Find packages in all possible locations.
|
||||||
let additionalPath = GBConfigService.get("ADDITIONAL_DEPLOY_PATH");
|
let additionalPath = GBConfigService.get("ADDITIONAL_DEPLOY_PATH")
|
||||||
|
|
||||||
deployer.deployPackageFromLocalPath(
|
let data = deployer.deployPackageFromLocalPath(
|
||||||
UrlJoin(additionalPath, packageName),
|
UrlJoin(additionalPath, packageName))
|
||||||
(data, err) => {
|
dc.context.sendActivity(`Package ${packageName} deployed... Please run rebuildIndex command.`)
|
||||||
dc.context.sendActivity(`Package ${packageName} deployed... Please run rebuildIndex command.`);
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static rebuildIndexCommand(min: GBMinInstance, dc, cb) {
|
static async rebuildIndexCommand(min: GBMinInstance, dc) {
|
||||||
let search = new AzureSearch(
|
let search = new AzureSearch(
|
||||||
min.instance.searchKey,
|
min.instance.searchKey,
|
||||||
min.instance.searchHost,
|
min.instance.searchHost,
|
||||||
min.instance.searchIndex,
|
min.instance.searchIndex,
|
||||||
min.instance.searchIndexer
|
min.instance.searchIndexer
|
||||||
);
|
)
|
||||||
dc.context.sendActivity("Rebuilding index...");
|
dc.context.sendActivity("Rebuilding index...")
|
||||||
search.deleteIndex((data, err) => {
|
await search.deleteIndex()
|
||||||
let kbService = new KBService();
|
let kbService = new KBService()
|
||||||
search.createIndex(kbService.getSearchSchema(min.instance.searchIndex), "gb", (data, err) => {
|
await search.createIndex(kbService.getSearchSchema(min.instance.searchIndex), "gb")
|
||||||
dc.context.sendActivity("Index rebuilt.");
|
await dc.context.sendActivity("Index rebuilt.")
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup dialogs flows and define services call.
|
||||||
|
*
|
||||||
|
* @param bot The bot adapter.
|
||||||
|
* @param min The minimal bot instance data.
|
||||||
|
*/
|
||||||
|
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
|
|
||||||
|
// Setup services.
|
||||||
|
|
||||||
|
let importer = new GBImporter(min.core)
|
||||||
|
let deployer = new GBDeployer(min.core, importer)
|
||||||
|
|
||||||
|
min.dialogs.add("/admin", [
|
||||||
|
|
||||||
|
async (dc, args) => {
|
||||||
|
const prompt = "Please, authenticate:"
|
||||||
|
await dc.prompt('textPrompt', prompt)
|
||||||
|
},
|
||||||
|
async (dc, value) => {
|
||||||
|
let text = value
|
||||||
|
const user = min.userState.get(dc.context)
|
||||||
|
|
||||||
|
if (
|
||||||
|
!user.authenticated ||
|
||||||
|
text === GBConfigService.get("ADMIN_PASS")
|
||||||
|
) {
|
||||||
|
user.authenticated = true
|
||||||
|
await dc.context.sendActivity(
|
||||||
|
"Welcome to Pragmatismo.io GeneralBots Administration."
|
||||||
|
)
|
||||||
|
await dc.prompt('textPrompt', "Which task do you wanna run now?")
|
||||||
|
} else {
|
||||||
|
await dc.endAll()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async (dc, value) => {
|
||||||
|
var text = value
|
||||||
|
const user = min.userState.get(dc.context)
|
||||||
|
|
||||||
|
if (text === "quit") {
|
||||||
|
user.authenticated = false
|
||||||
|
await dc.replace("/")
|
||||||
|
} else if (text === "sync") {
|
||||||
|
await min.core.syncDatabaseStructure();
|
||||||
|
await dc.context.sendActivity("Sync started...")
|
||||||
|
await dc.replace("/admin", { firstRun: false })
|
||||||
|
} else if (text.split(" ")[0] === "rebuildIndex") {
|
||||||
|
await AdminDialog.rebuildIndexCommand(min, dc)
|
||||||
|
await dc.replace("/admin", { firstRun: false })
|
||||||
|
} else if (text.split(" ")[0] === "deployPackage") {
|
||||||
|
await AdminDialog.deployPackageCommand(text, dc, deployer, min)
|
||||||
|
await dc.replace("/admin", { firstRun: false })
|
||||||
|
} else if (text.split(" ")[0] === "redeployPackage") {
|
||||||
|
await AdminDialog.undeployPackageCommand(text, min, dc)
|
||||||
|
await AdminDialog.deployPackageCommand(text, dc, deployer, min)
|
||||||
|
await dc.context.sendActivity("Redeploy done.")
|
||||||
|
await dc.replace("/admin", { firstRun: false })
|
||||||
|
} else if (text.split(" ")[0] === "undeployPackage") {
|
||||||
|
await AdminDialog.undeployPackageCommand(text, min, dc)
|
||||||
|
await dc.replace("/admin", { firstRun: false })
|
||||||
|
} else if (text.split(" ")[0] === "applyPackage") {
|
||||||
|
await dc.context.sendActivity("Applying in progress...")
|
||||||
|
await min.core.loadInstance(text.split(" ")[1]);
|
||||||
|
await dc.context.sendActivity("Applying done...")
|
||||||
|
await dc.replace("/admin", { firstRun: false })
|
||||||
|
} else if (text.split(" ")[0] === "rat") {
|
||||||
|
await min.conversationalService.sendEvent(dc, "play", { playerType: "login", data: null })
|
||||||
|
await dc.context.sendActivity("Realize login clicando no botão de login, por favor...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,38 +30,38 @@
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
import { GBServiceCallback } from "botlib";
|
|
||||||
import { GuaribasUser } from "../../security.gblib/models";
|
import { GuaribasUser } from "../../security.gblib/models";
|
||||||
import { GuaribasConversation, GuaribasConversationMessage } from "../models";
|
import { GuaribasConversation, GuaribasConversationMessage } from "../models";
|
||||||
|
|
||||||
export class AnalyticsService {
|
export class AnalyticsService {
|
||||||
|
async createConversation(
|
||||||
|
user: GuaribasUser
|
||||||
createConversation(
|
): Promise<GuaribasConversation> {
|
||||||
user: GuaribasUser,
|
return new Promise<GuaribasConversation>(
|
||||||
cb: GBServiceCallback<GuaribasConversation>
|
(resolve, reject) => {
|
||||||
) {
|
let conversation = new GuaribasConversation();
|
||||||
let conversation = new GuaribasConversation();
|
conversation.startedBy = user;
|
||||||
conversation.startedBy = user;
|
conversation.startedByUserId = user.userId;
|
||||||
conversation.startedByUserId = user.userId;
|
conversation.save().then((value: GuaribasConversation) => {
|
||||||
conversation.save().then((value: GuaribasConversation) => {
|
resolve(value);
|
||||||
cb(conversation, null);
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createMessage(
|
createMessage(
|
||||||
conversation: GuaribasConversation,
|
conversation: GuaribasConversation,
|
||||||
user: GuaribasUser,
|
user: GuaribasUser,
|
||||||
content: string,
|
content: string
|
||||||
cb: GBServiceCallback<GuaribasConversationMessage>
|
): Promise<GuaribasConversationMessage> {
|
||||||
) {
|
return new Promise<GuaribasConversationMessage>(
|
||||||
let message = GuaribasConversationMessage.build();
|
(resolve, reject) => {
|
||||||
message.conversation = conversation;
|
let message = GuaribasConversationMessage.build();
|
||||||
message.user = user;
|
message.conversation = conversation;
|
||||||
message.content = content;
|
message.user = user;
|
||||||
message.save().then((value: GuaribasConversationMessage) => {
|
message.content = content;
|
||||||
cb(value, null);
|
message.save().then((value: GuaribasConversationMessage) => {
|
||||||
});
|
resolve(value);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,9 +40,7 @@ const Walk = require("fs-walk");
|
||||||
const logger = require("../../../src/logger");
|
const logger = require("../../../src/logger");
|
||||||
const Swagger = require('swagger-client');
|
const Swagger = require('swagger-client');
|
||||||
const rp = require('request-promise');
|
const rp = require('request-promise');
|
||||||
import * as request from "request-promise-native";
|
import { GBService } from "botlib";
|
||||||
|
|
||||||
import { GBServiceCallback, GBService, IGBInstance } from "botlib";
|
|
||||||
|
|
||||||
export class ConsoleDirectLine extends GBService {
|
export class ConsoleDirectLine extends GBService {
|
||||||
|
|
||||||
|
@ -193,7 +191,4 @@ export class ConsoleDirectLine extends GBService {
|
||||||
console.log('*' + contentLine(attachment.content.text) + '*');
|
console.log('*' + contentLine(attachment.content.text) + '*');
|
||||||
console.log('*'.repeat(width + 1) + '/');
|
console.log('*'.repeat(width + 1) + '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -40,6 +40,12 @@ import { GBMinInstance } from "botlib";
|
||||||
import { BotAdapter } from "botbuilder";
|
import { BotAdapter } from "botbuilder";
|
||||||
|
|
||||||
export class WelcomeDialog extends IGBDialog {
|
export class WelcomeDialog extends IGBDialog {
|
||||||
|
/**
|
||||||
|
* Setup dialogs flows and define services call.
|
||||||
|
*
|
||||||
|
* @param bot The bot adapter.
|
||||||
|
* @param min The minimal bot instance data.
|
||||||
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
|
|
||||||
min.dialogs.add("/", [
|
min.dialogs.add("/", [
|
||||||
|
|
|
@ -40,7 +40,15 @@ import { BotAdapter } from "botbuilder";
|
||||||
|
|
||||||
|
|
||||||
export class WhoAmIDialog extends IGBDialog {
|
export class WhoAmIDialog extends IGBDialog {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup dialogs flows and define services call.
|
||||||
|
*
|
||||||
|
* @param bot The bot adapter.
|
||||||
|
* @param min The minimal bot instance data.
|
||||||
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
|
|
||||||
min.dialogs.add("/whoAmI", [
|
min.dialogs.add("/whoAmI", [
|
||||||
async (dc, args) => {
|
async (dc, args) => {
|
||||||
dc.context.sendActivity(`${min.instance.description}`);
|
dc.context.sendActivity(`${min.instance.description}`);
|
||||||
|
|
|
@ -1,49 +1,47 @@
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| ( )_ _ |
|
| ( )_ _ |
|
||||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||||
| | | ( )_) | |
|
| | | ( )_) | |
|
||||||
| (_) \___/' |
|
| (_) \___/' |
|
||||||
| |
|
| |
|
||||||
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
|
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
|
||||||
| Licensed under the AGPL-3.0. |
|
| Licensed under the AGPL-3.0. |
|
||||||
| |
|
| |
|
||||||
| According to our dual licensing model, this program can be used either |
|
| According to our dual licensing model, this program can be used either |
|
||||||
| under the terms of the GNU Affero General Public License, version 3, |
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
| or under a proprietary license. |
|
| or under a proprietary license. |
|
||||||
| |
|
| |
|
||||||
| The texts of the GNU Affero General Public License with an additional |
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
| permission and of our proprietary license can be found at and |
|
| permission and of our proprietary license can be found at and |
|
||||||
| in the LICENSE file you have received along with this program. |
|
| in the LICENSE file you have received along with this program. |
|
||||||
| |
|
| |
|
||||||
| This program is distributed in the hope that it will be useful, |
|
| This program is distributed in the hope that it will be useful, |
|
||||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
| GNU Affero General Public License for more details. |
|
| GNU Affero General Public License for more details. |
|
||||||
| |
|
| |
|
||||||
| "General Bots" is a registered trademark of Pragmatismo.io. |
|
| "General Bots" is a registered trademark of Pragmatismo.io. |
|
||||||
| The licensing of the program under the AGPLv3 does not imply a |
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
| trademark license. Therefore any rights, title and interest in |
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
| our trademarks remain entirely with us. |
|
| our trademarks remain entirely with us. |
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const UrlJoin = require("url-join");
|
|
||||||
const gBuilder = require("botbuilder");
|
|
||||||
const logger = require("../../../src/logger");
|
const logger = require("../../../src/logger");
|
||||||
|
|
||||||
import { GBConfigService } from "./GBConfigService";
|
|
||||||
import { GBCoreService } from "./GBCoreService";
|
import { GBCoreService } from "./GBCoreService";
|
||||||
import { GBService, GBServiceCallback, IGBConversationalService } from "botlib";
|
import { IGBConversationalService } from "botlib";
|
||||||
import { GBError } from "botlib";
|
import { GBError } from "botlib";
|
||||||
import { GBERROR_TYPE } from "botlib";
|
import { GBERROR_TYPE } from "botlib";
|
||||||
import { GBMinInstance } from "botlib";
|
import { GBMinInstance } from "botlib";
|
||||||
import { LuisRecognizer } from "botbuilder-ai";
|
import { LuisRecognizer } from "botbuilder-ai";
|
||||||
import {MessageFactory} from "botbuilder";
|
import { MessageFactory } from "botbuilder";
|
||||||
|
import { resolve } from "bluebird";
|
||||||
|
|
||||||
export class GBConversationalService implements IGBConversationalService {
|
export class GBConversationalService implements IGBConversationalService {
|
||||||
|
|
||||||
|
@ -64,9 +62,8 @@ export class GBConversationalService implements IGBConversationalService {
|
||||||
async runNLP(
|
async runNLP(
|
||||||
dc: any,
|
dc: any,
|
||||||
min: GBMinInstance,
|
min: GBMinInstance,
|
||||||
text: string,
|
text: string
|
||||||
cb: GBServiceCallback<any>
|
): Promise<any> {
|
||||||
) {
|
|
||||||
|
|
||||||
const model = new LuisRecognizer({
|
const model = new LuisRecognizer({
|
||||||
appId: min.instance.nlpAppId,
|
appId: min.instance.nlpAppId,
|
||||||
|
@ -74,12 +71,12 @@ export class GBConversationalService implements IGBConversationalService {
|
||||||
serviceEndpoint: min.instance.nlpServerUrl
|
serviceEndpoint: min.instance.nlpServerUrl
|
||||||
});
|
});
|
||||||
|
|
||||||
await model.recognize(dc.context).then(res => {
|
return await model.recognize(dc.context).then(res => {
|
||||||
|
|
||||||
// Resolve intents returned from LUIS
|
// Resolve intents returned from LUIS
|
||||||
let topIntent = LuisRecognizer.topIntent(res);
|
let topIntent = LuisRecognizer.topIntent(res);
|
||||||
|
|
||||||
if (topIntent) {
|
if (topIntent) {
|
||||||
var intent = topIntent;
|
var intent = topIntent;
|
||||||
var entity =
|
var entity =
|
||||||
res.entities && res.entities.length > 0
|
res.entities && res.entities.length > 0
|
||||||
|
@ -93,21 +90,21 @@ export class GBConversationalService implements IGBConversationalService {
|
||||||
dc.replace("/" + intent);
|
dc.replace("/" + intent);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.info("error: intent: [" + intent + "] error: [" + error + "]");
|
logger.info("error: intent: [" + intent + "] error: [" + error + "]");
|
||||||
|
|
||||||
dc.context.sendActivity("Desculpe-me, não encontrei nada a respeito...");
|
dc.context.sendActivity("Desculpe-me, não encontrei nada a respeito...");
|
||||||
dc.replace("/ask", { isReturning: true });
|
dc.replace("/ask", { isReturning: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
cb({ intent, entities: res.entities }, null);
|
return Promise.resolve({ intent, entities: res.entities });
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
dc.context.sendActivity("Lamento, não achei nada a respeito...");
|
dc.context.sendActivity("Lamento, não achei nada a respeito...");
|
||||||
dc.replace("/ask", { isReturning: true });
|
dc.replace("/ask", { isReturning: true });
|
||||||
cb(null, null);
|
resolve(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
).catch(err => {
|
).catch(err => {
|
||||||
cb(null, new GBError(err, GBERROR_TYPE.nlpGeneralError));
|
return Promise.reject(new GBError(err, GBERROR_TYPE.nlpGeneralError));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,21 +32,10 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const Path = require("path");
|
|
||||||
const Fs = require("fs");
|
|
||||||
const _ = require("lodash");
|
|
||||||
const Parse = require("csv-parse");
|
|
||||||
const Async = require("async");
|
|
||||||
const UrlJoin = require("url-join");
|
|
||||||
const Walk = require("fs-walk");
|
|
||||||
const logger = require("../../../src/logger");
|
const logger = require("../../../src/logger");
|
||||||
|
|
||||||
import { Sequelize } from 'sequelize-typescript';
|
import { Sequelize } from 'sequelize-typescript';
|
||||||
import { Promise } from "bluebird";
|
|
||||||
import { GBConfigService } from "./GBConfigService";
|
import { GBConfigService } from "./GBConfigService";
|
||||||
import { DataTypeUUIDv1 } from "sequelize";
|
import { IGBInstance, IGBCoreService } from 'botlib';
|
||||||
|
|
||||||
import { GBServiceCallback, IGBInstance, IGBCoreService } from 'botlib';
|
|
||||||
import { GuaribasInstance } from "../models/GBModel";
|
import { GuaribasInstance } from "../models/GBModel";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,76 +43,103 @@ import { GuaribasInstance } from "../models/GBModel";
|
||||||
*/
|
*/
|
||||||
export class GBCoreService implements IGBCoreService {
|
export class GBCoreService implements IGBCoreService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data access layer instance.
|
||||||
|
*/
|
||||||
public sequelize: Sequelize;
|
public sequelize: Sequelize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows filtering on SQL generated before send to the database.
|
||||||
|
*/
|
||||||
private queryGenerator: any;
|
private queryGenerator: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom create table query.
|
||||||
|
*/
|
||||||
private createTableQuery: (tableName, attributes, options) => string;
|
private createTableQuery: (tableName, attributes, options) => string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom change column query.
|
||||||
|
*/
|
||||||
private changeColumnQuery: (tableName, attributes) => string;
|
private changeColumnQuery: (tableName, attributes) => string;
|
||||||
|
|
||||||
/** Dialect used. Tested: mssql and sqlite. */
|
/**
|
||||||
|
* Dialect used. Tested: mssql and sqlite.
|
||||||
|
*/
|
||||||
private dialect: string;
|
private dialect: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor retrieves default values.
|
||||||
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
this.dialect = GBConfigService.get("DATABASE_DIALECT");
|
this.dialect = GBConfigService.get("DATABASE_DIALECT");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get config and connect to storage. */
|
/**
|
||||||
initDatabase(cb) {
|
* Gets database config and connect to storage.
|
||||||
|
*/
|
||||||
|
async initDatabase() {
|
||||||
|
return new Promise(
|
||||||
|
(resolve, reject) => {
|
||||||
|
|
||||||
let host: string | undefined;
|
try {
|
||||||
let database: string | undefined;
|
|
||||||
let username: string | undefined;
|
|
||||||
let password: string | undefined;
|
|
||||||
let storage: string | undefined;
|
|
||||||
|
|
||||||
if (this.dialect === "mssql") {
|
let host: string | undefined;
|
||||||
host = GBConfigService.get("DATABASE_HOST");
|
let database: string | undefined;
|
||||||
database = GBConfigService.get("DATABASE_NAME");
|
let username: string | undefined;
|
||||||
username = GBConfigService.get("DATABASE_USERNAME");
|
let password: string | undefined;
|
||||||
password = GBConfigService.get("DATABASE_PASSWORD");
|
let storage: string | undefined;
|
||||||
} else if (this.dialect === "sqlite") {
|
|
||||||
storage = GBConfigService.get("DATABASE_STORAGE");
|
|
||||||
}
|
|
||||||
|
|
||||||
let logging = (GBConfigService.get("DATABASE_LOGGING") === "true")
|
if (this.dialect === "mssql") {
|
||||||
? (str: string) => { logger.info(str); }
|
host = GBConfigService.get("DATABASE_HOST");
|
||||||
: false;
|
database = GBConfigService.get("DATABASE_NAME");
|
||||||
|
username = GBConfigService.get("DATABASE_USERNAME");
|
||||||
|
password = GBConfigService.get("DATABASE_PASSWORD");
|
||||||
|
} else if (this.dialect === "sqlite") {
|
||||||
|
storage = GBConfigService.get("DATABASE_STORAGE");
|
||||||
|
}
|
||||||
|
|
||||||
let encrypt = (GBConfigService.get("DATABASE_ENCRYPT") === "true");
|
let logging = (GBConfigService.get("DATABASE_LOGGING") === "true")
|
||||||
|
? (str: string) => { logger.info(str); }
|
||||||
|
: false;
|
||||||
|
|
||||||
this.sequelize = new Sequelize({
|
let encrypt = (GBConfigService.get("DATABASE_ENCRYPT") === "true");
|
||||||
host: host,
|
|
||||||
database: database,
|
|
||||||
username: username,
|
|
||||||
password: password,
|
|
||||||
logging: logging,
|
|
||||||
operatorsAliases: false,
|
|
||||||
dialect: this.dialect,
|
|
||||||
storage: storage,
|
|
||||||
dialectOptions: {
|
|
||||||
encrypt: encrypt
|
|
||||||
},
|
|
||||||
pool: {
|
|
||||||
max: 32,
|
|
||||||
min: 8,
|
|
||||||
idle: 40000,
|
|
||||||
evict: 40000,
|
|
||||||
acquire: 40000
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.dialect === "mssql") {
|
this.sequelize = new Sequelize({
|
||||||
this.queryGenerator = this.sequelize.getQueryInterface().QueryGenerator;
|
host: host,
|
||||||
this.createTableQuery = this.queryGenerator.createTableQuery;
|
database: database,
|
||||||
this.queryGenerator.createTableQuery = (tableName, attributes, options) =>
|
username: username,
|
||||||
this.createTableQueryOverride(tableName, attributes, options);
|
password: password,
|
||||||
this.changeColumnQuery = this.queryGenerator.changeColumnQuery;
|
logging: logging,
|
||||||
this.queryGenerator.changeColumnQuery = (tableName, attributes) =>
|
operatorsAliases: false,
|
||||||
this.changeColumnQueryOverride(tableName, attributes);
|
dialect: this.dialect,
|
||||||
}
|
storage: storage,
|
||||||
|
dialectOptions: {
|
||||||
|
encrypt: encrypt
|
||||||
|
},
|
||||||
|
pool: {
|
||||||
|
max: 32,
|
||||||
|
min: 8,
|
||||||
|
idle: 40000,
|
||||||
|
evict: 40000,
|
||||||
|
acquire: 40000
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
setImmediate(cb);
|
if (this.dialect === "mssql") {
|
||||||
|
this.queryGenerator = this.sequelize.getQueryInterface().QueryGenerator;
|
||||||
|
this.createTableQuery = this.queryGenerator.createTableQuery;
|
||||||
|
this.queryGenerator.createTableQuery = (tableName, attributes, options) =>
|
||||||
|
this.createTableQueryOverride(tableName, attributes, options);
|
||||||
|
this.changeColumnQuery = this.queryGenerator.changeColumnQuery;
|
||||||
|
this.queryGenerator.changeColumnQuery = (tableName, attributes) =>
|
||||||
|
this.changeColumnQueryOverride(tableName, attributes);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private createTableQueryOverride(tableName, attributes, options): string {
|
private createTableQueryOverride(tableName, attributes, options): string {
|
||||||
|
@ -192,70 +208,79 @@ export class GBCoreService implements IGBCoreService {
|
||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
syncDatabaseStructure(cb) {
|
async syncDatabaseStructure() {
|
||||||
if (GBConfigService.get("DATABASE_SYNC") === "true") {
|
return new Promise(
|
||||||
const alter = (GBConfigService.get("DATABASE_SYNC_ALTER") === "true");
|
(resolve, reject) => {
|
||||||
const force = (GBConfigService.get("DATABASE_SYNC_FORCE") === "true");
|
if (GBConfigService.get("DATABASE_SYNC") === "true") {
|
||||||
logger.info("Syncing database...");
|
const alter = (GBConfigService.get("DATABASE_SYNC_ALTER") === "true");
|
||||||
this.sequelize.sync({
|
const force = (GBConfigService.get("DATABASE_SYNC_FORCE") === "true");
|
||||||
alter: alter,
|
logger.info("Syncing database...");
|
||||||
force: force
|
this.sequelize.sync({
|
||||||
}).then(value => {
|
alter: alter,
|
||||||
logger.info("Database synced.");
|
force: force
|
||||||
cb();
|
}).then(value => {
|
||||||
}, err => logger.error(err));
|
logger.info("Database synced.");
|
||||||
} else {
|
resolve(value);
|
||||||
logger.info("Database synchronization is disabled.");
|
}, err => reject(err));
|
||||||
cb();
|
} else {
|
||||||
}
|
logger.info("Database synchronization is disabled.");
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all items to start several listeners.
|
* Loads all items to start several listeners.
|
||||||
* @param cb Instances loaded or error info.
|
|
||||||
*/
|
*/
|
||||||
loadInstances(cb: GBServiceCallback<IGBInstance[]>) {
|
async loadInstances(): Promise<IGBInstance> {
|
||||||
GuaribasInstance.findAll({})
|
return new Promise(
|
||||||
.then((items: IGBInstance[]) => {
|
(resolve, reject) => {
|
||||||
if (!items) items = [];
|
GuaribasInstance.findAll({})
|
||||||
|
.then((items: IGBInstance[]) => {
|
||||||
|
if (!items) items = [];
|
||||||
|
|
||||||
if (items.length == 0) {
|
if (items.length == 0) {
|
||||||
cb([], null);
|
resolve([]);
|
||||||
} else {
|
} else {
|
||||||
cb(items, null);
|
resolve(items);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(reason => {
|
.catch(reason => {
|
||||||
if (reason.message.indexOf("no such table: GuaribasInstance") != -1) {
|
if (reason.message.indexOf("no such table: GuaribasInstance") != -1) {
|
||||||
cb([], null);
|
resolve([]);
|
||||||
} else {
|
} else {
|
||||||
logger.info(`GuaribasServiceError: ${reason}`);
|
logger.info(`GuaribasServiceError: ${reason}`);
|
||||||
cb(null, reason);
|
reject(reason);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads just one Bot instance.
|
* Loads just one Bot instance.
|
||||||
*/
|
*/
|
||||||
loadInstance(botId: string, cb: GBServiceCallback<IGBInstance>) {
|
async loadInstance(botId: string): Promise<IGBInstance> {
|
||||||
let options = { where: {} };
|
return new Promise<IGBInstance>(
|
||||||
|
(resolve, reject) => {
|
||||||
|
|
||||||
if (botId != "[default]") {
|
let options = { where: {} };
|
||||||
options.where = { botId: botId };
|
|
||||||
}
|
|
||||||
|
|
||||||
GuaribasInstance.findOne(options)
|
if (botId != "[default]") {
|
||||||
.then((instance: IGBInstance) => {
|
options.where = { botId: botId };
|
||||||
if (instance) {
|
|
||||||
cb(instance, null);
|
|
||||||
} else {
|
|
||||||
cb(null, null);
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.catch(err => {
|
GuaribasInstance.findOne(options)
|
||||||
cb(null, err);
|
.then((instance: IGBInstance) => {
|
||||||
logger.info(`GuaribasServiceError: ${err}`);
|
if (instance) {
|
||||||
|
resolve(instance);
|
||||||
|
} else {
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
logger.info(`GuaribasServiceError: ${err}`);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,25 +34,14 @@
|
||||||
|
|
||||||
const logger = require("../../../src/logger");
|
const logger = require("../../../src/logger");
|
||||||
const Path = require("path");
|
const Path = require("path");
|
||||||
const Fs = require("fs");
|
|
||||||
const FsExtra = require("fs-extra");
|
|
||||||
const _ = require("lodash");
|
const _ = require("lodash");
|
||||||
const Async = require("async");
|
|
||||||
const UrlJoin = require("url-join");
|
const UrlJoin = require("url-join");
|
||||||
const Walk = require("fs-walk");
|
|
||||||
const WaitUntil = require("wait-until");
|
|
||||||
|
|
||||||
import { KBService } from './../../kb.gbapp/services/KBService';
|
import { KBService } from './../../kb.gbapp/services/KBService';
|
||||||
import { GBImporter } from "./GBImporter";
|
import { GBImporter } from "./GBImporter";
|
||||||
import { GBCoreService } from "./GBCoreService";
|
|
||||||
import { GBServiceCallback, IGBCoreService, IGBInstance } from "botlib";
|
import { GBServiceCallback, IGBCoreService, IGBInstance } from "botlib";
|
||||||
import { Sequelize } from 'sequelize-typescript';
|
|
||||||
import { Promise } from "bluebird";
|
|
||||||
import { GBConfigService } from "./GBConfigService";
|
import { GBConfigService } from "./GBConfigService";
|
||||||
import { DataTypeUUIDv1 } from "sequelize";
|
import { GBError } from "botlib";
|
||||||
import { GBError, GBERROR_TYPE } from "botlib";
|
|
||||||
|
|
||||||
import { GBConversationalService } from "./GBConversationalService";
|
|
||||||
import { GuaribasPackage } from '../models/GBModel';
|
import { GuaribasPackage } from '../models/GBModel';
|
||||||
|
|
||||||
/** Deployer service for bots, themes, ai and more. */
|
/** Deployer service for bots, themes, ai and more. */
|
||||||
|
@ -69,156 +58,131 @@ export class GBDeployer {
|
||||||
this.importer = importer;
|
this.importer = importer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Deploys a bot to the storage. */
|
/**
|
||||||
deployBot(localPath: string, cb: GBServiceCallback<any>) {
|
* Deploys a bot to the storage.
|
||||||
|
*/
|
||||||
|
|
||||||
|
async deployBot(localPath: string): Promise<IGBInstance> {
|
||||||
let packageType = Path.extname(localPath);
|
let packageType = Path.extname(localPath);
|
||||||
let packageName = Path.basename(localPath);
|
let packageName = Path.basename(localPath);
|
||||||
|
let instance = await this.importer.importIfNotExistsBotPackage(
|
||||||
this.importer.importIfNotExistsBotPackage(
|
|
||||||
packageName,
|
packageName,
|
||||||
localPath,
|
localPath
|
||||||
(data, err) => {
|
|
||||||
if (err) {
|
|
||||||
logger.info(err);
|
|
||||||
} else {
|
|
||||||
cb(data, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
deployPackageToStorage(
|
async deployPackageToStorage(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
packageName: string,
|
packageName: string): Promise<GuaribasPackage> {
|
||||||
cb: GBServiceCallback<GuaribasPackage>
|
return GuaribasPackage.create({
|
||||||
) {
|
|
||||||
GuaribasPackage.create({
|
|
||||||
packageName: packageName,
|
packageName: packageName,
|
||||||
instanceId: instanceId
|
instanceId: instanceId
|
||||||
}).then((item: GuaribasPackage) => {
|
|
||||||
cb(item, null);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deployTheme(localPath: string, cb: GBServiceCallback<any>) {
|
deployTheme(localPath: string) {
|
||||||
// DISABLED: Until completed, "/ui/public".
|
// DISABLED: Until completed, "/ui/public".
|
||||||
// FsExtra.copy(localPath, this.workDir + packageName)
|
// FsExtra.copy(localPath, this.workDir + packageName)
|
||||||
// .then(() => {
|
// .then(() => {
|
||||||
// cb(null, null);
|
|
||||||
// })
|
// })
|
||||||
// .catch(err => {
|
// .catch(err => {
|
||||||
// var gberr = GBError.create(
|
// var gberr = GBError.create(
|
||||||
// `GuaribasBusinessError: Error copying package: ${localPath}.`
|
// `GuaribasBusinessError: Error copying package: ${localPath}.`
|
||||||
// );
|
// );
|
||||||
// cb(null, gberr);
|
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
deployPackageFromLocalPath(localPath: string, cb: GBServiceCallback<any>) {
|
async deployPackageFromLocalPath(localPath: string) {
|
||||||
|
|
||||||
let packageType = Path.extname(localPath);
|
let packageType = Path.extname(localPath);
|
||||||
|
|
||||||
switch (packageType) {
|
switch (packageType) {
|
||||||
case ".gbot":
|
case ".gbot":
|
||||||
this.deployBot(localPath, cb);
|
return this.deployBot(localPath);
|
||||||
break;
|
|
||||||
|
|
||||||
case ".gbtheme":
|
case ".gbtheme":
|
||||||
this.deployTheme(localPath, cb);
|
return this.deployTheme(localPath);
|
||||||
break;
|
|
||||||
|
|
||||||
// PACKAGE: Put in package logic.
|
// PACKAGE: Put in package logic.
|
||||||
case ".gbkb":
|
case ".gbkb":
|
||||||
let service = new KBService();
|
let service = new KBService();
|
||||||
service.deployKb(this.core, this, localPath, cb);
|
return service.deployKb(this.core, this, localPath);
|
||||||
break;
|
|
||||||
|
|
||||||
case ".gbui":
|
case ".gbui":
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var err = GBError.create(
|
var err = GBError.create(
|
||||||
`GuaribasBusinessError: Unknow package type: ${packageType}.`
|
`GuaribasBusinessError: Unknow package type: ${packageType}.`
|
||||||
);
|
);
|
||||||
cb(null, err);
|
Promise.reject(err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
undeployPackageFromLocalPath(
|
async undeployPackageFromLocalPath(
|
||||||
instance: IGBInstance,
|
instance: IGBInstance,
|
||||||
localPath: string,
|
localPath: string
|
||||||
cb: GBServiceCallback<any>
|
|
||||||
) {
|
) {
|
||||||
let packageType = Path.extname(localPath);
|
let packageType = Path.extname(localPath);
|
||||||
let packageName = Path.basename(localPath);
|
let packageName = Path.basename(localPath);
|
||||||
|
|
||||||
this.getPackageByName(instance.instanceId, packageName, (p, err) => {
|
let p = await this.getPackageByName(instance.instanceId, packageName);
|
||||||
switch (packageType) {
|
|
||||||
case ".gbot":
|
|
||||||
// TODO: this.undeployBot(packageName, localPath, cb);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ".gbtheme":
|
switch (packageType) {
|
||||||
// TODO: this.undeployTheme(packageName, localPath, cb);
|
case ".gbot":
|
||||||
break;
|
// TODO: this.undeployBot(packageName, localPath);
|
||||||
|
break;
|
||||||
|
|
||||||
case ".gbkb":
|
case ".gbtheme":
|
||||||
let service = new KBService();
|
// TODO: this.undeployTheme(packageName, localPath);
|
||||||
service.undeployKbFromStorage(instance, p.packageId, cb);
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case ".gbui":
|
case ".gbkb":
|
||||||
break;
|
let service = new KBService();
|
||||||
|
return service.undeployKbFromStorage(instance, p.packageId);
|
||||||
|
|
||||||
default:
|
case ".gbui":
|
||||||
var err = GBError.create(
|
|
||||||
`GuaribasBusinessError: Unknow package type: ${packageType}.`
|
break;
|
||||||
);
|
|
||||||
cb(null, err);
|
default:
|
||||||
break;
|
var err = GBError.create(
|
||||||
}
|
`GuaribasBusinessError: Unknown package type: ${packageType}.`
|
||||||
|
);
|
||||||
|
Promise.reject(err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getPackageByName(instanceId: number, packageName: string):
|
||||||
|
Promise<GuaribasPackage> {
|
||||||
|
var where = { packageName: packageName, instanceId: instanceId };
|
||||||
|
return GuaribasPackage.findOne({
|
||||||
|
where: where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getPackageByName(
|
|
||||||
instanceId: number,
|
|
||||||
packageName: string,
|
|
||||||
cb: GBServiceCallback<GuaribasPackage>
|
|
||||||
) {
|
|
||||||
|
|
||||||
var where = { packageName: packageName, instanceId: instanceId };
|
|
||||||
|
|
||||||
GuaribasPackage.findOne({
|
|
||||||
where: where
|
|
||||||
})
|
|
||||||
.then((value: GuaribasPackage) => {
|
|
||||||
cb(value, null);
|
|
||||||
})
|
|
||||||
.error(reason => {
|
|
||||||
cb(null, reason);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Hot deploy processing.
|
* Hot deploy processing.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
scanBootPackage(cb: GBServiceCallback<boolean>) {
|
async scanBootPackage() {
|
||||||
|
|
||||||
const deployFolder = "deploy";
|
const deployFolder = "deploy";
|
||||||
let bootPackage = GBConfigService.get("BOOT_PACKAGE");
|
let bootPackage = GBConfigService.get("BOOT_PACKAGE");
|
||||||
|
|
||||||
if (bootPackage === "none") {
|
if (bootPackage === "none") {
|
||||||
cb(true, null);
|
return Promise.resolve(true);
|
||||||
} else {
|
} else {
|
||||||
this.deployPackageFromLocalPath(
|
return this.deployPackageFromLocalPath(
|
||||||
UrlJoin(deployFolder, bootPackage),
|
UrlJoin(deployFolder, bootPackage)
|
||||||
(data, err) => {
|
|
||||||
logger.info(`Boot package deployed: ${bootPackage}`);
|
|
||||||
if (err) logger.info(err);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,22 +33,10 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const _ = require("lodash");
|
|
||||||
const Parse = require("csv-parse");
|
|
||||||
const Async = require("async");
|
|
||||||
const UrlJoin = require("url-join");
|
const UrlJoin = require("url-join");
|
||||||
const Walk = require("fs-walk");
|
|
||||||
const logger = require("../../../src/logger");
|
|
||||||
|
|
||||||
import { KBService } from './../../kb.gbapp/services/KBService';
|
|
||||||
import { Sequelize } from 'sequelize-typescript';
|
|
||||||
import { Promise } from "bluebird";
|
|
||||||
import Fs = require("fs");
|
import Fs = require("fs");
|
||||||
import Path = require("path");
|
import Path = require("path");
|
||||||
import { DataTypeUUIDv1 } from "sequelize";
|
import { IGBCoreService, IGBInstance } from "botlib";
|
||||||
import { GBConfigService } from "./GBConfigService";
|
|
||||||
import { GBCoreService } from "./GBCoreService";
|
|
||||||
import { GBServiceCallback, IGBCoreService, IGBInstance } from "botlib";
|
|
||||||
import { SecService } from "../../security.gblib/services/SecService";
|
import { SecService } from "../../security.gblib/services/SecService";
|
||||||
import { GuaribasInstance } from "../models/GBModel";
|
import { GuaribasInstance } from "../models/GBModel";
|
||||||
|
|
||||||
|
@ -58,12 +46,10 @@ export class GBImporter {
|
||||||
constructor(core: IGBCoreService) {
|
constructor(core: IGBCoreService) {
|
||||||
this.core = core;
|
this.core = core;
|
||||||
}
|
}
|
||||||
importIfNotExistsBotPackage(
|
|
||||||
|
async importIfNotExistsBotPackage(
|
||||||
packageName: string,
|
packageName: string,
|
||||||
localPath: string,
|
localPath: string) {
|
||||||
cb: GBServiceCallback<IGBInstance>
|
|
||||||
) {
|
|
||||||
let _this_ = this;
|
|
||||||
|
|
||||||
let packageJson = JSON.parse(
|
let packageJson = JSON.parse(
|
||||||
Fs.readFileSync(UrlJoin(localPath, "package.json"), "utf8")
|
Fs.readFileSync(UrlJoin(localPath, "package.json"), "utf8")
|
||||||
|
@ -71,20 +57,18 @@ export class GBImporter {
|
||||||
|
|
||||||
let botId = packageJson.botId;
|
let botId = packageJson.botId;
|
||||||
|
|
||||||
this.core.loadInstance(botId, (instance, err) => {
|
let instance = await this.core.loadInstance(botId);
|
||||||
if (instance) {
|
if (instance) {
|
||||||
cb(instance, null);
|
return Promise.resolve(instance);
|
||||||
} else {
|
} else {
|
||||||
this.createInstanceInternal(packageName, localPath, packageJson, cb);
|
return this.createInstanceInternal(packageName, localPath, packageJson);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private createInstanceInternal(
|
private async createInstanceInternal(
|
||||||
packageName: string,
|
packageName: string,
|
||||||
localPath: string,
|
localPath: string,
|
||||||
packageJson: any,
|
packageJson: any
|
||||||
cb: GBServiceCallback<IGBInstance>
|
|
||||||
) {
|
) {
|
||||||
const settings = JSON.parse(
|
const settings = JSON.parse(
|
||||||
Fs.readFileSync(UrlJoin(localPath, "settings.json"), "utf8")
|
Fs.readFileSync(UrlJoin(localPath, "settings.json"), "utf8")
|
||||||
|
@ -97,11 +81,10 @@ export class GBImporter {
|
||||||
|
|
||||||
GuaribasInstance.create(packageJson).then((instance: IGBInstance) => {
|
GuaribasInstance.create(packageJson).then((instance: IGBInstance) => {
|
||||||
|
|
||||||
// PACKAGE: security.json loading
|
|
||||||
let service = new SecService();
|
let service = new SecService();
|
||||||
// TODO: service.importSecurityFile(localPath, instance);
|
// TODO: service.importSecurityFile(localPath, instance);
|
||||||
|
|
||||||
cb(instance, null);
|
Promise.resolve(instance);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -77,7 +77,6 @@ export class GBMinService {
|
||||||
* Static initialization of minimal instance.
|
* Static initialization of minimal instance.
|
||||||
*
|
*
|
||||||
* @param core Basic database services to identify instance, for example.
|
* @param core Basic database services to identify instance, for example.
|
||||||
* @param cb Returns the loaded instance.
|
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
core: GBCoreService,
|
core: GBCoreService,
|
||||||
|
@ -91,9 +90,7 @@ export class GBMinService {
|
||||||
|
|
||||||
/** Constructs a new minimal instance for each bot. */
|
/** Constructs a new minimal instance for each bot. */
|
||||||
|
|
||||||
buildMin(cb: GBServiceCallback<GBMinInstance>, server: any, appPackages: Array<IGBPackage>) {
|
async buildMin(server: any, appPackages: Array<IGBPackage>): Promise<GBMinInstance> {
|
||||||
|
|
||||||
var _this_ = this;
|
|
||||||
|
|
||||||
// Serves default UI on root address '/'.
|
// Serves default UI on root address '/'.
|
||||||
|
|
||||||
|
@ -105,246 +102,232 @@ export class GBMinService {
|
||||||
|
|
||||||
// Loads all bot instances from storage.
|
// Loads all bot instances from storage.
|
||||||
|
|
||||||
_this_.core.loadInstances((instances: IGBInstance[], err) => {
|
let instances = await this.core.loadInstances();
|
||||||
|
|
||||||
// Gets the authorization key for each instance from Bot Service.
|
// Gets the authorization key for each instance from Bot Service.
|
||||||
|
|
||||||
instances.forEach(instance => {
|
Promise.all(instances).then(async (instance: IGBInstance) => {
|
||||||
let options = {
|
|
||||||
url:
|
|
||||||
"https://directline.botframework.com/v3/directline/tokens/generate",
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${instance.webchatKey}`
|
|
||||||
}
|
|
||||||
};
|
|
||||||
request(options).then((response:
|
|
||||||
string) => {
|
|
||||||
|
|
||||||
// Serves the bot information object via http so clients can get
|
let options = {
|
||||||
// instance information stored on server.
|
url:
|
||||||
|
"https://directline.botframework.com/v3/directline/tokens/generate",
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${instance.webchatKey}`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let responseObject = JSON.parse(response);
|
let response = await request(options);
|
||||||
server.get("/instances/:botId", (req, res) => {
|
|
||||||
|
|
||||||
// Returns the instance object to clients requesting bot info.
|
// Serves the bot information object via http so clients can get
|
||||||
|
// instance information stored on server.
|
||||||
|
|
||||||
let botId = req.params.botId;
|
let responseObject = JSON.parse(response);
|
||||||
_this_.core.loadInstance(
|
server.get("/instances/:botId", (req, res) => {
|
||||||
botId,
|
(async () => {
|
||||||
(instance: IGBInstance, err) => {
|
|
||||||
if (instance) {
|
|
||||||
|
|
||||||
// TODO: Make dynamic: https://CHANGE.api.cognitive.microsoft.com/sts/v1.0
|
// Returns the instance object to clients requesting bot info.
|
||||||
|
|
||||||
let options = {
|
let botId = req.params.botId;
|
||||||
url:
|
let instance = await this.core.loadInstance(botId);
|
||||||
"https://westus.api.cognitive.microsoft.com/sts/v1.0/issueToken",
|
if (instance) {
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Ocp-Apim-Subscription-Key": instance.speechKey
|
|
||||||
}
|
|
||||||
};
|
|
||||||
request(options).then((response:
|
|
||||||
string) => {
|
|
||||||
|
|
||||||
res.send(
|
// TODO: Make dynamic: https://CHANGE.api.cognitive.microsoft.com/sts/v1.0
|
||||||
JSON.stringify({
|
|
||||||
instanceId: instance.instanceId,
|
let options = {
|
||||||
botId: botId,
|
url:
|
||||||
theme: instance.theme,
|
"https://westus.api.cognitive.microsoft.com/sts/v1.0/issueToken",
|
||||||
secret: instance.webchatKey, // TODO: Use token.
|
method: "POST",
|
||||||
speechToken: response,
|
headers: {
|
||||||
conversationId: responseObject.conversationId
|
"Ocp-Apim-Subscription-Key": instance.speechKey
|
||||||
})
|
|
||||||
);
|
|
||||||
}).catch((reason) => {
|
|
||||||
let error = `Error loading Speech Service: ${reason}.`;
|
|
||||||
res.send(error);
|
|
||||||
logger.error(error);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
let error = `Instance not found: ${botId}.`;
|
|
||||||
res.send(error);
|
|
||||||
logger.error(error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
response = await request(options);
|
||||||
|
|
||||||
|
res.send(
|
||||||
|
JSON.stringify({
|
||||||
|
instanceId: instance.instanceId,
|
||||||
|
botId: botId,
|
||||||
|
theme: instance.theme,
|
||||||
|
secret: instance.webchatKey, // TODO: Use token.
|
||||||
|
speechToken: response,
|
||||||
|
conversationId: responseObject.conversationId
|
||||||
|
})
|
||||||
);
|
);
|
||||||
});
|
} else {
|
||||||
|
let error = `Instance not found: ${botId}.`;
|
||||||
|
res.send(error);
|
||||||
|
logger.error(error);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Build bot adapter.
|
// Build bot adapter.
|
||||||
|
|
||||||
let adapter = new BotFrameworkAdapter({
|
let adapter = new BotFrameworkAdapter({
|
||||||
appId: instance.marketplaceId,
|
appId: instance.marketplaceId,
|
||||||
appPassword: instance.marketplacePassword
|
appPassword: instance.marketplacePassword
|
||||||
});
|
});
|
||||||
const storage = new MemoryStorage();
|
const storage = new MemoryStorage();
|
||||||
const conversationState = new ConversationState(storage);
|
const conversationState = new ConversationState(storage);
|
||||||
const userState = new UserState(storage);
|
const userState = new UserState(storage);
|
||||||
adapter.use(new BotStateSet(conversationState, userState));
|
adapter.use(new BotStateSet(conversationState, userState));
|
||||||
|
|
||||||
// The minimal bot is built here.
|
// The minimal bot is built here.
|
||||||
|
|
||||||
let min = new GBMinInstance();
|
let min = new GBMinInstance();
|
||||||
min.botId = instance.botId;
|
min.botId = instance.botId;
|
||||||
min.bot = adapter;
|
min.bot = adapter;
|
||||||
min.userState = userState;
|
min.userState = userState;
|
||||||
min.core = _this_.core;
|
min.core = this.core;
|
||||||
min.conversationalService = _this_.conversationalService;
|
min.conversationalService = this.conversationalService;
|
||||||
|
|
||||||
_this_.core.loadInstance(min.botId, (data, err) => {
|
min.instance = await this.core.loadInstance(min.botId);
|
||||||
|
|
||||||
min.instance = data;
|
// Call the loadBot context.activity for all packages.
|
||||||
|
|
||||||
// Call the loadBot context.activity for all packages.
|
appPackages.forEach(e => {
|
||||||
|
e.sysPackages = new Array<IGBPackage>();
|
||||||
appPackages.forEach(e => {
|
[GBAdminPackage, GBAnalyticsPackage, GBCorePackage, GBSecurityPackage,
|
||||||
e.sysPackages = new Array<IGBPackage>();
|
GBKBPackage, GBCustomerSatisfactionPackage, GBWhatsappPackage].forEach(sysPackage => {
|
||||||
[GBAdminPackage, GBAnalyticsPackage, GBCorePackage, GBSecurityPackage,
|
logger.info(`Loading sys package: ${sysPackage.name}...`);
|
||||||
GBKBPackage, GBCustomerSatisfactionPackage, GBWhatsappPackage].forEach(sysPackage => {
|
let p = Object.create(sysPackage.prototype) as IGBPackage;
|
||||||
logger.info(`Loading sys package: ${sysPackage.name}...`);
|
p.loadBot(min);
|
||||||
let p = Object.create(sysPackage.prototype) as IGBPackage;
|
e.sysPackages.push(p);
|
||||||
p.loadBot(min);
|
|
||||||
e.sysPackages.push(p);
|
|
||||||
|
|
||||||
if (sysPackage.name === "GBWhatsappPackage") {
|
|
||||||
let url = "/instances/:botId/whatsapp";
|
|
||||||
server.post(url, (req, res) => {
|
|
||||||
p["channel"].received(req, res);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (sysPackage.name === "GBWhatsappPackage") {
|
||||||
|
let url = "/instances/:botId/whatsapp";
|
||||||
|
server.post(url, (req, res) => {
|
||||||
|
p["channel"].received(req, res);
|
||||||
});
|
});
|
||||||
|
|
||||||
e.loadBot(min);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// Serves individual URL for each bot conversational interface...
|
|
||||||
|
|
||||||
let url = `/api/messages/${instance.botId}`;
|
|
||||||
logger.info(
|
|
||||||
`GeneralBots(${instance.engineName}) listening on: ${url}.`
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
min.dialogs.add('textPrompt', new TextPrompt());
|
|
||||||
|
|
||||||
server.post(`/api/messages/${instance.botId}`, (req, res) => {
|
|
||||||
|
|
||||||
adapter.processActivity(req, res, async (context) => {
|
|
||||||
|
|
||||||
const state = conversationState.get(context);
|
|
||||||
const dc = min.dialogs.createContext(context, state);
|
|
||||||
|
|
||||||
const user = min.userState.get(dc.context);
|
|
||||||
if (!user.loaded) {
|
|
||||||
min.conversationalService.sendEvent(
|
|
||||||
dc,
|
|
||||||
"loadInstance",
|
|
||||||
{
|
|
||||||
instanceId: instance.instanceId,
|
|
||||||
botId: instance.botId,
|
|
||||||
theme: instance.theme,
|
|
||||||
secret: instance.webchatKey, // TODO: Use token.
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
user.loaded = true;
|
|
||||||
user.subjects = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(
|
});
|
||||||
`[RCV]: ${context.activity.type}, ChannelID: ${context.activity.channelId},
|
|
||||||
|
e.loadBot(min);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Serves individual URL for each bot conversational interface...
|
||||||
|
|
||||||
|
let url = `/api/messages/${instance.botId}`;
|
||||||
|
logger.info(
|
||||||
|
`GeneralBots(${instance.engineName}) listening on: ${url}.`
|
||||||
|
);
|
||||||
|
|
||||||
|
min.dialogs.add('textPrompt', new TextPrompt());
|
||||||
|
|
||||||
|
server.post(`/api/messages/${instance.botId}`, (req, res) => {
|
||||||
|
|
||||||
|
adapter.processActivity(req, res, async (context) => {
|
||||||
|
|
||||||
|
const state = conversationState.get(context);
|
||||||
|
const dc = min.dialogs.createContext(context, state);
|
||||||
|
|
||||||
|
const user = min.userState.get(dc.context);
|
||||||
|
if (!user.loaded) {
|
||||||
|
min.conversationalService.sendEvent(
|
||||||
|
dc,
|
||||||
|
"loadInstance",
|
||||||
|
{
|
||||||
|
instanceId: instance.instanceId,
|
||||||
|
botId: instance.botId,
|
||||||
|
theme: instance.theme,
|
||||||
|
secret: instance.webchatKey, // TODO: Use token.
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
user.loaded = true;
|
||||||
|
user.subjects = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
`[RCV]: ${context.activity.type}, ChannelID: ${context.activity.channelId},
|
||||||
ConversationID: ${context.activity.conversation.id},
|
ConversationID: ${context.activity.conversation.id},
|
||||||
Name: ${context.activity.name}, Text: ${context.activity.text}.`
|
Name: ${context.activity.name}, Text: ${context.activity.text}.`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (context.activity.type === "conversationUpdate" &&
|
if (context.activity.type === "conversationUpdate" &&
|
||||||
context.activity.membersAdded.length > 0) {
|
context.activity.membersAdded.length > 0) {
|
||||||
|
|
||||||
let member = context.activity.membersAdded[0];
|
|
||||||
if (member.name === "GeneralBots") {
|
|
||||||
logger.info(`Bot added to conversation, starting chat...`);
|
|
||||||
appPackages.forEach(e => {
|
|
||||||
e.onNewSession(min, dc);
|
|
||||||
});
|
|
||||||
await dc.begin('/');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
logger.info(`Member added to conversation: ${member.name}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (context.activity.type === 'message') {
|
|
||||||
|
|
||||||
// Check to see if anyone replied. If not then start echo dialog
|
|
||||||
|
|
||||||
if (context.activity.text === "admin") {
|
|
||||||
dc.begin("/admin");
|
|
||||||
} else {
|
|
||||||
await dc.continue();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (context.activity.type === 'event') {
|
|
||||||
if (context.activity.name === "whoAmI") {
|
|
||||||
dc.begin("/whoAmI");
|
|
||||||
} else if (context.activity.name === "showSubjects") {
|
|
||||||
dc.begin("/menu");
|
|
||||||
} else if (context.activity.name === "giveFeedback") {
|
|
||||||
dc.begin("/feedback", {
|
|
||||||
fromMenu: true
|
|
||||||
});
|
|
||||||
} else if (context.activity.name === "showFAQ") {
|
|
||||||
dc.begin("/faq");
|
|
||||||
} else if (context.activity.name === "ask") {
|
|
||||||
dc.begin("/answer", {
|
|
||||||
// TODO: query: context.activity.data,
|
|
||||||
fromFaq: true
|
|
||||||
});
|
|
||||||
} else if (context.activity.name === "quality") {
|
|
||||||
dc.begin("/quality", {
|
|
||||||
// TODO: score: context.activity.data
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await dc.continue();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let member = context.activity.membersAdded[0];
|
||||||
|
if (member.name === "GeneralBots") {
|
||||||
|
logger.info(`Bot added to conversation, starting chat...`);
|
||||||
|
appPackages.forEach(e => {
|
||||||
|
e.onNewSession(min, dc);
|
||||||
|
});
|
||||||
|
await dc.begin('/');
|
||||||
}
|
}
|
||||||
});
|
else {
|
||||||
|
logger.info(`Member added to conversation: ${member.name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (context.activity.type === 'message') {
|
||||||
|
|
||||||
|
// Check to see if anyone replied. If not then start echo dialog
|
||||||
|
|
||||||
|
if (context.activity.text === "admin") {
|
||||||
|
dc.begin("/admin");
|
||||||
|
} else {
|
||||||
|
await dc.continue();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (context.activity.type === 'event') {
|
||||||
|
if (context.activity.name === "whoAmI") {
|
||||||
|
dc.begin("/whoAmI");
|
||||||
|
} else if (context.activity.name === "showSubjects") {
|
||||||
|
dc.begin("/menu");
|
||||||
|
} else if (context.activity.name === "giveFeedback") {
|
||||||
|
dc.begin("/feedback", {
|
||||||
|
fromMenu: true
|
||||||
|
});
|
||||||
|
} else if (context.activity.name === "showFAQ") {
|
||||||
|
dc.begin("/faq");
|
||||||
|
} else if (context.activity.name === "ask") {
|
||||||
|
dc.begin("/answer", {
|
||||||
|
// TODO: query: context.activity.data,
|
||||||
|
fromFaq: true
|
||||||
|
});
|
||||||
|
} else if (context.activity.name === "quality") {
|
||||||
|
dc.begin("/quality", {
|
||||||
|
// TODO: score: context.activity.data
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await dc.continue();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Serves individual URL for each bot user interface.
|
|
||||||
|
|
||||||
let uiUrl = `/${instance.botId}`;
|
|
||||||
server.use(
|
|
||||||
uiUrl,
|
|
||||||
express.static(UrlJoin(this.deployFolder, uiPackage, "build"))
|
|
||||||
);
|
|
||||||
logger.info(`Bot UI ${uiPackage} acessible at: ${uiUrl}.`);
|
|
||||||
|
|
||||||
// Setups handlers.
|
|
||||||
// send: function (context.activity, next) {
|
|
||||||
// logger.info(
|
|
||||||
// `[SND]: ChannelID: ${context.activity.address.channelId}, ConversationID: ${context.activity.address.conversation},
|
|
||||||
// Type: ${context.activity.type} `);
|
|
||||||
// this.core.createMessage(
|
|
||||||
// this.min.conversation,
|
|
||||||
// this.min.conversation.startedBy,
|
|
||||||
// context.activity.source,
|
|
||||||
// (data, err) => {
|
|
||||||
// logger.info(context.activity.source);
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
// next();
|
|
||||||
|
|
||||||
// Specialized load for each min instance.
|
|
||||||
|
|
||||||
cb(min, null);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Serves individual URL for each bot user interface.
|
||||||
|
|
||||||
|
let uiUrl = `/${instance.botId}`;
|
||||||
|
server.use(
|
||||||
|
uiUrl,
|
||||||
|
express.static(UrlJoin(this.deployFolder, uiPackage, "build"))
|
||||||
|
);
|
||||||
|
logger.info(`Bot UI ${uiPackage} acessible at: ${uiUrl}.`);
|
||||||
|
|
||||||
|
// Setups handlers.
|
||||||
|
// send: function (context.activity, next) {
|
||||||
|
// logger.info(
|
||||||
|
// `[SND]: ChannelID: ${context.activity.address.channelId}, ConversationID: ${context.activity.address.conversation},
|
||||||
|
// Type: ${context.activity.type} `);
|
||||||
|
// this.core.createMessage(
|
||||||
|
// this.min.conversation,
|
||||||
|
// this.min.conversation.startedBy,
|
||||||
|
// context.activity.source,
|
||||||
|
// (data, err) => {
|
||||||
|
// logger.info(context.activity.source);
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// next();
|
||||||
|
|
||||||
|
// Specialized load for each min instance.
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Performs package deployment in all .gbai or default. */
|
/** Performs package deployment in all .gbai or default. */
|
||||||
|
@ -352,7 +335,6 @@ export class GBMinService {
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
var _this_ = this;
|
|
||||||
let totalPackages = 0;
|
let totalPackages = 0;
|
||||||
let additionalPath = GBConfigService.get("ADDITIONAL_DEPLOY_PATH");
|
let additionalPath = GBConfigService.get("ADDITIONAL_DEPLOY_PATH");
|
||||||
let paths = [this.deployFolder];
|
let paths = [this.deployFolder];
|
||||||
|
@ -388,19 +370,19 @@ export class GBMinService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`Starting looking for generalPackages...`);
|
logger.info(`Starting looking for packages (.gbot, .gbtheme, .gbkb, .gbapp)...`);
|
||||||
paths.forEach(e => {
|
paths.forEach(e => {
|
||||||
logger.info(`Looking in: ${e}...`);
|
logger.info(`Looking in: ${e}...`);
|
||||||
doIt(e);
|
doIt(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/** Deploys all .gbapp files first. */
|
/** Deploys all .gbapp files first. */
|
||||||
|
|
||||||
let appPackagesProcessed = 0;
|
let appPackagesProcessed = 0;
|
||||||
|
|
||||||
gbappPackages.forEach(e => {
|
gbappPackages.forEach(e => {
|
||||||
logger.info(`Deploying app: ${e}...`);
|
logger.info(`Deploying app: ${e}...`);
|
||||||
|
|
||||||
// Skips .gbapp inside deploy folder.
|
// Skips .gbapp inside deploy folder.
|
||||||
if (!e.startsWith('deploy')) {
|
if (!e.startsWith('deploy')) {
|
||||||
import(e).then(m => {
|
import(e).then(m => {
|
||||||
|
@ -435,13 +417,11 @@ export class GBMinService {
|
||||||
|
|
||||||
botPackages.forEach(e => {
|
botPackages.forEach(e => {
|
||||||
logger.info(`Deploying bot: ${e}...`);
|
logger.info(`Deploying bot: ${e}...`);
|
||||||
_this_.deployer.deployBot(e, (data, err) => {
|
this.deployer.deployBot(e, (data, err) => {
|
||||||
logger.info(`Bot: ${e} deployed...`);
|
logger.info(`Bot: ${e} deployed...`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Wait here.
|
|
||||||
|
|
||||||
/** Then all remaining generalPackages are loaded. */
|
/** Then all remaining generalPackages are loaded. */
|
||||||
|
|
||||||
generalPackages.forEach(filename => {
|
generalPackages.forEach(filename => {
|
||||||
|
|
|
@ -41,6 +41,12 @@ import { BotAdapter } from 'botbuilder';
|
||||||
|
|
||||||
export class FeedbackDialog extends IGBDialog {
|
export class FeedbackDialog extends IGBDialog {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup dialogs flows and define services call.
|
||||||
|
*
|
||||||
|
* @param bot The bot adapter.
|
||||||
|
* @param min The minimal bot instance data.
|
||||||
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
|
|
||||||
const service = new CSService();
|
const service = new CSService();
|
||||||
|
@ -58,10 +64,9 @@ export class FeedbackDialog extends IGBDialog {
|
||||||
async (dc, value) => {
|
async (dc, value) => {
|
||||||
let rate = value.entity;
|
let rate = value.entity;
|
||||||
const user = min.userState.get(dc.context);
|
const user = min.userState.get(dc.context);
|
||||||
service.updateConversationRate(user.conversation, rate, item => {
|
await service.updateConversationRate(user.conversation, rate);
|
||||||
let messages = ["Obrigado!", "Obrigado por responder."];
|
let messages = ["Obrigado!", "Obrigado por responder."];
|
||||||
dc.context.sendActivity(messages[0]); // TODO: Handle rnd.
|
await dc.context.sendActivity(messages[0]); // TODO: Handle rnd.
|
||||||
});
|
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,12 @@ const logger = require("../../../src/logger");
|
||||||
|
|
||||||
export class QualityDialog extends IGBDialog {
|
export class QualityDialog extends IGBDialog {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup dialogs flows and define services call.
|
||||||
|
*
|
||||||
|
* @param bot The bot adapter.
|
||||||
|
* @param min The minimal bot instance data.
|
||||||
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
|
|
||||||
const service = new CSService();
|
const service = new CSService();
|
||||||
|
@ -61,25 +67,22 @@ export class QualityDialog extends IGBDialog {
|
||||||
"Lamento... Vamos tentar novamente!",
|
"Lamento... Vamos tentar novamente!",
|
||||||
"Desculpe-me. Por favor, tente escrever de outra forma?"
|
"Desculpe-me. Por favor, tente escrever de outra forma?"
|
||||||
];
|
];
|
||||||
dc.context.sendActivity(msg[0]);
|
await dc.context.sendActivity(msg[0]);
|
||||||
} else {
|
} else {
|
||||||
let msg = [
|
let msg = [
|
||||||
"Ótimo, obrigado por contribuir com sua resposta.",
|
"Ótimo, obrigado por contribuir com sua resposta.",
|
||||||
"Certo, obrigado pela informação.",
|
"Certo, obrigado pela informação.",
|
||||||
"Obrigado pela contribuição."
|
"Obrigado pela contribuição."
|
||||||
];
|
];
|
||||||
dc.context.sendActivity(msg[0]);
|
await dc.context.sendActivity(msg[0]);
|
||||||
|
|
||||||
service.insertQuestionAlternate(
|
await service.insertQuestionAlternate(
|
||||||
min.instance.instanceId,
|
min.instance.instanceId,
|
||||||
user.lastQuestion,
|
user.lastQuestion,
|
||||||
user.lastQuestionId,
|
user.lastQuestionId
|
||||||
(data, err) => {
|
|
||||||
logger.info("QuestionAlternate inserted.");
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
dc.replace('/ask', {isReturning: true});
|
await dc.replace('/ask', {isReturning: true});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -30,19 +30,6 @@
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
const logger = require("../../../src/logger");
|
|
||||||
const Path = require("path");
|
|
||||||
const Fs = require("fs");
|
|
||||||
const FsExtra = require("fs-extra");
|
|
||||||
const _ = require("lodash");
|
|
||||||
const Parse = require("csv-parse");
|
|
||||||
const Async = require("async");
|
|
||||||
const UrlJoin = require("url-join");
|
|
||||||
const Walk = require("fs-walk");
|
|
||||||
const WaitUntil = require("wait-until");
|
|
||||||
|
|
||||||
import { GBServiceCallback } from "botlib";
|
|
||||||
import { GBDeployer } from "../../core.gbapp/services/GBDeployer";
|
|
||||||
import { GuaribasQuestionAlternate } from '../models';
|
import { GuaribasQuestionAlternate } from '../models';
|
||||||
import { GuaribasConversation } from '../../analytics.gblib/models';
|
import { GuaribasConversation } from '../../analytics.gblib/models';
|
||||||
|
|
||||||
|
@ -50,44 +37,45 @@ export class CSService {
|
||||||
|
|
||||||
resolveQuestionAlternate(
|
resolveQuestionAlternate(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
questionTyped: string,
|
questionTyped: string): Promise<GuaribasQuestionAlternate> {
|
||||||
cb: GBServiceCallback<GuaribasQuestionAlternate>
|
return new Promise<GuaribasQuestionAlternate>(
|
||||||
) {
|
(resolve, reject) => {
|
||||||
GuaribasQuestionAlternate.findOne({
|
GuaribasQuestionAlternate.findOne({
|
||||||
where: {
|
where: {
|
||||||
instanceId: instanceId,
|
instanceId: instanceId,
|
||||||
questionTyped: questionTyped
|
questionTyped: questionTyped
|
||||||
}
|
}
|
||||||
}).then((value: GuaribasQuestionAlternate) => {
|
}).then((value: GuaribasQuestionAlternate) => {
|
||||||
cb(value, null);
|
resolve(value);
|
||||||
});
|
}).error(reason => reject(reason));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
insertQuestionAlternate(
|
insertQuestionAlternate(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
questionTyped: string,
|
questionTyped: string,
|
||||||
questionText: string,
|
questionText: string): Promise<GuaribasQuestionAlternate> {
|
||||||
cb: GBServiceCallback<GuaribasQuestionAlternate>
|
return new Promise<GuaribasQuestionAlternate>(
|
||||||
) {
|
(resolve, reject) => {
|
||||||
GuaribasQuestionAlternate.create({
|
GuaribasQuestionAlternate.create({
|
||||||
questionTyped: questionTyped,
|
questionTyped: questionTyped,
|
||||||
questionText: questionText
|
questionText: questionText
|
||||||
}).then(item => {
|
}).then(item => {
|
||||||
if (cb) {
|
resolve(item);
|
||||||
cb(item, null);
|
}).error(reason => reject(reason));
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateConversationRate(
|
updateConversationRate(
|
||||||
conversation: GuaribasConversation,
|
conversation: GuaribasConversation,
|
||||||
rate: number,
|
rate: number
|
||||||
cb: GBServiceCallback<GuaribasConversation>
|
): Promise<GuaribasConversation> {
|
||||||
) {
|
return new Promise<GuaribasConversation>(
|
||||||
conversation.rate = rate;
|
(resolve, reject) => {
|
||||||
conversation.save().then((value: GuaribasConversation) => {
|
conversation.rate = rate;
|
||||||
cb(conversation, null);
|
conversation.save().then((value: GuaribasConversation) => {
|
||||||
});
|
resolve(conversation);
|
||||||
|
}).error(reason => reject(reason));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,12 @@ import { LuisRecognizer } from "botbuilder-ai";
|
||||||
const logger = require("../../../src/logger");
|
const logger = require("../../../src/logger");
|
||||||
|
|
||||||
export class AskDialog extends IGBDialog {
|
export class AskDialog extends IGBDialog {
|
||||||
|
/**
|
||||||
|
* Setup dialogs flows and define services call.
|
||||||
|
*
|
||||||
|
* @param bot The bot adapter.
|
||||||
|
* @param min The minimal bot instance data.
|
||||||
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
|
|
||||||
const service = new KBService();
|
const service = new KBService();
|
||||||
|
|
|
@ -38,31 +38,35 @@ import { BotAdapter } from "botbuilder";
|
||||||
import { GBMinInstance } from "botlib";
|
import { GBMinInstance } from "botlib";
|
||||||
|
|
||||||
export class FaqDialog extends IGBDialog {
|
export class FaqDialog extends IGBDialog {
|
||||||
|
/**
|
||||||
|
* Setup dialogs flows and define services call.
|
||||||
|
*
|
||||||
|
* @param bot The bot adapter.
|
||||||
|
* @param min The minimal bot instance data.
|
||||||
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
|
|
||||||
const service = new KBService();
|
const service = new KBService();
|
||||||
|
|
||||||
min.dialogs.add("/faq", [
|
min.dialogs.add("/faq", [
|
||||||
async (dc, args) => {
|
async (dc, args) => {
|
||||||
service.getFaqBySubjectArray("faq", null, (data, err) => {
|
let data = await service.getFaqBySubjectArray("faq", null);
|
||||||
if (data) {
|
if (data) {
|
||||||
min.conversationalService.sendEvent(dc, "play", {
|
await min.conversationalService.sendEvent(dc, "play", {
|
||||||
playerType: "bullet",
|
playerType: "bullet",
|
||||||
data: data.slice(0, 10)
|
data: data.slice(0, 10)
|
||||||
});
|
});
|
||||||
|
|
||||||
let messages = [
|
let messages = [
|
||||||
"Veja algumas perguntas mais frequentes logo na tela. Clique numa delas para eu responder.",
|
"Veja algumas perguntas mais frequentes logo na tela. Clique numa delas para eu responder.",
|
||||||
"Você pode clicar em alguma destas perguntas da tela que eu te respondo de imediato.",
|
"Você pode clicar em alguma destas perguntas da tela que eu te respondo de imediato.",
|
||||||
"Veja a lista que eu preparei logo aí na tela..."
|
"Veja a lista que eu preparei logo aí na tela..."
|
||||||
];
|
];
|
||||||
|
|
||||||
dc.context.sendActivity(messages[0]); // TODO: RND messages.
|
await dc.context.sendActivity(messages[0]); // TODO: RND messages.
|
||||||
dc.endAll();
|
await dc.endAll();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,12 @@ const WaitUntil = require("wait-until");
|
||||||
|
|
||||||
export class MenuDialog extends IGBDialog {
|
export class MenuDialog extends IGBDialog {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup dialogs flows and define services call.
|
||||||
|
*
|
||||||
|
* @param bot The bot adapter.
|
||||||
|
* @param min The minimal bot instance data.
|
||||||
|
*/
|
||||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||||
|
|
||||||
var service = new KBService();
|
var service = new KBService();
|
||||||
|
@ -83,16 +89,12 @@ export class MenuDialog extends IGBDialog {
|
||||||
|
|
||||||
if (user.subjects.length > 0) {
|
if (user.subjects.length > 0) {
|
||||||
|
|
||||||
service.getFaqBySubjectArray(
|
let data = await service.getFaqBySubjectArray("menu", user.subjects);
|
||||||
"menu",
|
await min.conversationalService.sendEvent(dc, "play", {
|
||||||
user.subjects,
|
playerType: "bullet",
|
||||||
(data, err) => {
|
data: data.slice(0, 6)
|
||||||
min.conversationalService.sendEvent(dc, "play", {
|
});
|
||||||
playerType: "bullet",
|
|
||||||
data: data.slice(0, 6)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const user = min.userState.get(dc.context);
|
const user = min.userState.get(dc.context);
|
||||||
|
@ -119,64 +121,63 @@ export class MenuDialog extends IGBDialog {
|
||||||
const msg = MessageFactory.text('Greetings from example message');
|
const msg = MessageFactory.text('Greetings from example message');
|
||||||
var attachments = [];
|
var attachments = [];
|
||||||
|
|
||||||
service.getSubjectItems(
|
let data = await service.getSubjectItems(
|
||||||
min.instance.instanceId,
|
min.instance.instanceId,
|
||||||
rootSubjectId,
|
rootSubjectId);
|
||||||
data => {
|
|
||||||
|
|
||||||
msg.attachmentLayout='carousel';
|
|
||||||
|
|
||||||
|
|
||||||
data.forEach(function (item: GuaribasSubject) {
|
|
||||||
|
|
||||||
var subject = item;
|
msg.attachmentLayout = 'carousel';
|
||||||
|
|
||||||
var card = CardFactory.heroCard(
|
|
||||||
subject.title,
|
|
||||||
CardFactory.images([UrlJoin(
|
|
||||||
"/kb",
|
|
||||||
min.instance.kb,
|
|
||||||
"subjects",
|
|
||||||
subject.internalId + ".png" // TODO: or fallback to subject.png
|
|
||||||
)]),
|
|
||||||
CardFactory.actions([
|
|
||||||
{
|
|
||||||
type: 'postBack',
|
|
||||||
title: 'Selecionar',
|
|
||||||
value: JSON.stringify({
|
|
||||||
title: subject.title,
|
|
||||||
subjectId: subject.subjectId,
|
|
||||||
to: subject.to
|
|
||||||
})
|
|
||||||
}]));
|
|
||||||
|
|
||||||
attachments.push(card);
|
data.forEach(function (item: GuaribasSubject) {
|
||||||
|
|
||||||
});
|
var subject = item;
|
||||||
|
|
||||||
if (attachments.length == 0) {
|
var card = CardFactory.heroCard(
|
||||||
const user = min.userState.get(dc.context);
|
subject.title,
|
||||||
if (user.subjects && user.subjects.length > 0) {
|
CardFactory.images([UrlJoin(
|
||||||
dc.context.sendActivity(
|
"/kb",
|
||||||
`Vamos pesquisar sobre ${KBService.getFormattedSubjectItems(
|
min.instance.kb,
|
||||||
user.subjects
|
"subjects",
|
||||||
)}?`
|
subject.internalId + ".png" // TODO: or fallback to subject.png
|
||||||
);
|
)]),
|
||||||
}
|
CardFactory.actions([
|
||||||
|
{
|
||||||
|
type: 'postBack',
|
||||||
|
title: 'Selecionar',
|
||||||
|
value: JSON.stringify({
|
||||||
|
title: subject.title,
|
||||||
|
subjectId: subject.subjectId,
|
||||||
|
to: subject.to
|
||||||
|
})
|
||||||
|
}]));
|
||||||
|
|
||||||
dc.replace("/ask", {});
|
attachments.push(card);
|
||||||
} else {
|
|
||||||
msg.attachments = attachments;
|
});
|
||||||
dc.context.sendActivity(msg);
|
|
||||||
}
|
if (attachments.length == 0) {
|
||||||
|
const user = min.userState.get(dc.context);
|
||||||
|
if (user.subjects && user.subjects.length > 0) {
|
||||||
|
await dc.context.sendActivity(
|
||||||
|
`Vamos pesquisar sobre ${KBService.getFormattedSubjectItems(
|
||||||
|
user.subjects
|
||||||
|
)}?`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
await dc.replace("/ask", {});
|
||||||
|
} else {
|
||||||
|
msg.attachments = attachments;
|
||||||
|
await dc.context.sendActivity(msg);
|
||||||
|
}
|
||||||
|
|
||||||
const user = min.userState.get(dc.context);
|
const user = min.userState.get(dc.context);
|
||||||
user.isAsking = true;
|
user.isAsking = true;
|
||||||
},
|
},
|
||||||
async (dc, value) => {
|
async (dc, value) => {
|
||||||
var text = value;
|
var text = value;
|
||||||
if (AzureText.isIntentNo(text)) {
|
if (text==="no"||text==="n") { // TODO: Migrate to a common.
|
||||||
dc.replace("/feedback");
|
dc.replace("/feedback");
|
||||||
} else {
|
} else {
|
||||||
dc.replace("/ask");
|
dc.replace("/ask");
|
||||||
|
|
|
@ -33,14 +33,17 @@
|
||||||
const logger = require("../../../src/logger");
|
const logger = require("../../../src/logger");
|
||||||
const Path = require("path");
|
const Path = require("path");
|
||||||
const Fs = require("fs");
|
const Fs = require("fs");
|
||||||
const Parse = require("csv-parse");
|
const promise = require('bluebird');
|
||||||
const Async = require("async");
|
const parse = promise.promisify(require('csv-parse'));
|
||||||
const UrlJoin = require("url-join");
|
const UrlJoin = require("url-join");
|
||||||
const Walk = require("fs-walk");
|
|
||||||
const marked = require("marked");
|
const marked = require("marked");
|
||||||
|
const path = require("path");
|
||||||
|
const asyncPromise = require('async-promises');
|
||||||
|
const walkPromise = require('walk-promise');
|
||||||
|
|
||||||
import { GBConfigService } from './../../core.gbapp/services/GBConfigService';
|
import { GBConfigService } from './../../core.gbapp/services/GBConfigService';
|
||||||
import { GuaribasQuestion, GuaribasAnswer, GuaribasSubject } from "../models";
|
import { GuaribasQuestion, GuaribasAnswer, GuaribasSubject } from "../models";
|
||||||
import { GBServiceCallback, IGBCoreService, IGBConversationalService, IGBInstance } from "botlib";
|
import { IGBCoreService, IGBConversationalService, IGBInstance } from "botlib";
|
||||||
import { AzureSearch } from "pragmatismo-io-framework";
|
import { AzureSearch } from "pragmatismo-io-framework";
|
||||||
import { GBDeployer } from "../../core.gbapp/services/GBDeployer";
|
import { GBDeployer } from "../../core.gbapp/services/GBDeployer";
|
||||||
import { GuaribasPackage } from "../../core.gbapp/models/GBModel";
|
import { GuaribasPackage } from "../../core.gbapp/models/GBModel";
|
||||||
|
@ -52,55 +55,66 @@ export class KBServiceSearchResults {
|
||||||
|
|
||||||
export class KBService {
|
export class KBService {
|
||||||
|
|
||||||
getAnswerById(
|
async getAnswerById(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
answerId: number,
|
answerId: number
|
||||||
cb: GBServiceCallback<GuaribasAnswer>
|
): Promise<GuaribasAnswer> {
|
||||||
) {
|
return new Promise<GuaribasAnswer>(
|
||||||
GuaribasAnswer.findAll({
|
(resolve, reject) => {
|
||||||
where: {
|
|
||||||
instanceId: instanceId,
|
|
||||||
answerId: answerId
|
|
||||||
}
|
|
||||||
}).then((item: GuaribasAnswer[]) => {
|
|
||||||
cb(item[0], null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getAnswerByText(
|
|
||||||
instanceId: number,
|
|
||||||
text: string,
|
|
||||||
cb: GBServiceCallback<any>
|
|
||||||
) {
|
|
||||||
GuaribasQuestion.findOne({
|
|
||||||
where: {
|
|
||||||
instanceId: instanceId,
|
|
||||||
content: `%${text.trim()}%`
|
|
||||||
}
|
|
||||||
}).then((question: GuaribasQuestion) => {
|
|
||||||
if (question) {
|
|
||||||
GuaribasAnswer.findAll({
|
GuaribasAnswer.findAll({
|
||||||
where: {
|
where: {
|
||||||
instanceId: instanceId,
|
instanceId: instanceId,
|
||||||
answerId: question.answerId
|
answerId: answerId
|
||||||
}
|
}
|
||||||
}).then((answer: GuaribasAnswer[]) => {
|
}).then((item: GuaribasAnswer[]) => {
|
||||||
cb({ question: question, answer: answer[0] }, null);
|
resolve(item[0]);
|
||||||
|
}).error((reason) => {
|
||||||
|
reject(reason);
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
else {
|
|
||||||
cb(null, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAnswerByText(
|
||||||
|
instanceId: number,
|
||||||
|
text: string
|
||||||
|
): Promise<any> {
|
||||||
|
return new Promise(
|
||||||
|
(resolve, reject) => {
|
||||||
|
|
||||||
addAnswer(obj: GuaribasAnswer, cb: GBServiceCallback<GuaribasAnswer>) {
|
GuaribasQuestion.findOne({
|
||||||
GuaribasAnswer.create(obj).then(item => {
|
where: {
|
||||||
if (cb) {
|
instanceId: instanceId,
|
||||||
cb(item, null);
|
content: `%${text.trim()}%`
|
||||||
}
|
}
|
||||||
});
|
}).then((question: GuaribasQuestion) => {
|
||||||
|
if (question) {
|
||||||
|
GuaribasAnswer.findAll({
|
||||||
|
where: {
|
||||||
|
instanceId: instanceId,
|
||||||
|
answerId: question.answerId
|
||||||
|
}
|
||||||
|
}).then((answer: GuaribasAnswer[]) => {
|
||||||
|
resolve({ question: question, answer: answer[0] });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
}).error((reason) => {
|
||||||
|
reject(reason);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async addAnswer(obj: GuaribasAnswer): Promise<GuaribasAnswer> {
|
||||||
|
return new Promise<GuaribasAnswer>(
|
||||||
|
(resolve, reject) => {
|
||||||
|
GuaribasAnswer.create(obj).then(item => {
|
||||||
|
resolve(item);
|
||||||
|
}).error((reason) => {
|
||||||
|
reject(reason);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async ask(
|
async ask(
|
||||||
|
@ -110,32 +124,25 @@ export class KBService {
|
||||||
subjects: GuaribasSubject[]
|
subjects: GuaribasSubject[]
|
||||||
): Promise<KBServiceSearchResults> {
|
): Promise<KBServiceSearchResults> {
|
||||||
|
|
||||||
return new Promise<KBServiceSearchResults>((resolve, reject) => {
|
// Builds search query.
|
||||||
|
|
||||||
// Builds search query.
|
what = what.toLowerCase();
|
||||||
|
what = what.replace("?", " ");
|
||||||
|
what = what.replace("!", " ");
|
||||||
|
what = what.replace(".", " ");
|
||||||
|
what = what.replace("/", " ");
|
||||||
|
what = what.replace("\\", " ");
|
||||||
|
|
||||||
what = what.toLowerCase();
|
if (subjects) {
|
||||||
what = what.replace("?", " ");
|
let text = KBService.getSubjectItemsSeparatedBySpaces(
|
||||||
what = what.replace("!", " ");
|
subjects
|
||||||
what = what.replace(".", " ");
|
);
|
||||||
what = what.replace("/", " ");
|
if (text) {
|
||||||
what = what.replace("\\", " ");
|
what = `${what} ${text}`;
|
||||||
|
|
||||||
if (subjects) {
|
|
||||||
let text = KBService.getSubjectItemsSeparatedBySpaces(
|
|
||||||
subjects
|
|
||||||
);
|
|
||||||
if (text) {
|
|
||||||
what = `${what} ${text}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// TODO: Filter by instance. what = `${what}&$filter=instanceId eq ${instanceId}`;
|
// TODO: Filter by instance. what = `${what}&$filter=instanceId eq ${instanceId}`;
|
||||||
|
try {
|
||||||
// Performs search.
|
|
||||||
|
|
||||||
var _this_ = this;
|
|
||||||
|
|
||||||
if (instance.searchKey && GBConfigService.get("DATABASE_DIALECT") == "mssql") {
|
if (instance.searchKey && GBConfigService.get("DATABASE_DIALECT") == "mssql") {
|
||||||
let service = new AzureSearch(
|
let service = new AzureSearch(
|
||||||
instance.searchKey,
|
instance.searchKey,
|
||||||
|
@ -143,41 +150,24 @@ export class KBService {
|
||||||
instance.searchIndex,
|
instance.searchIndex,
|
||||||
instance.searchIndexer
|
instance.searchIndexer
|
||||||
);
|
);
|
||||||
|
let results = await service.search(what);
|
||||||
service.search(what, (err: any, results: any) => {
|
if (results && results.length > 0 &&
|
||||||
if (results && results.length > 0) {
|
results[0]["@search.score"] >= searchScore) {
|
||||||
// Ponders over configuration.
|
let value = await this.getAnswerById(
|
||||||
|
instance.instanceId,
|
||||||
if (results[0]["@search.score"] >= searchScore) {
|
results[0].answerId);
|
||||||
_this_.getAnswerById(
|
return Promise.resolve({ answer: value, questionId: results[0].questionId });
|
||||||
instance.instanceId,
|
}
|
||||||
results[0].answerId,
|
|
||||||
(answer, err) => {
|
|
||||||
if (err) { reject(err); } else {
|
|
||||||
resolve({ answer: answer, questionId: results[0].questionId });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
resolve(null);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
resolve(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
this.getAnswerByText(instance.instanceId, what, (data, err) => {
|
let data = await this.getAnswerByText(instance.instanceId, what);
|
||||||
if (data) {
|
return Promise.resolve(
|
||||||
resolve({ answer: data.answer, questionId: data.question.questionId });
|
{ answer: data.answer, questionId: data.question.questionId }
|
||||||
}
|
);
|
||||||
else {
|
|
||||||
if (err) { reject(err); } else {
|
|
||||||
resolve(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
catch (reason) {
|
||||||
|
return Promise.reject(reason);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getSearchSchema(indexName) {
|
getSearchSchema(indexName) {
|
||||||
|
@ -298,166 +288,179 @@ export class KBService {
|
||||||
return out.join(" ");
|
return out.join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
getSubjectItems(
|
async getSubjectItems(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
parentId: number,
|
parentId: number
|
||||||
cb: GBServiceCallback<GuaribasSubject[]>
|
): Promise<GuaribasSubject[]> {
|
||||||
) {
|
return new Promise<GuaribasSubject[]>(
|
||||||
var where = { parentSubjectId: parentId, instanceId: instanceId };
|
(resolve, reject) => {
|
||||||
GuaribasSubject.findAll({
|
var where = { parentSubjectId: parentId, instanceId: instanceId };
|
||||||
where: where
|
GuaribasSubject.findAll({
|
||||||
})
|
where: where
|
||||||
.then((values: GuaribasSubject[]) => {
|
})
|
||||||
cb(values, null);
|
.then((values: GuaribasSubject[]) => {
|
||||||
})
|
resolve(values);
|
||||||
.error(reason => {
|
})
|
||||||
cb(null, reason);
|
.error(reason => {
|
||||||
|
reject(reason);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getFaqBySubjectArray(from: string, subjects: any, cb) {
|
async getFaqBySubjectArray(from: string, subjects: any): Promise<GuaribasQuestion[]> {
|
||||||
let where = {
|
return new Promise<GuaribasQuestion[]>(
|
||||||
from: from
|
(resolve, reject) => {
|
||||||
};
|
|
||||||
|
|
||||||
if (subjects) {
|
let where = {
|
||||||
if (subjects[0]) {
|
from: from
|
||||||
where["subject1"] = subjects[0].title;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
if (subjects[1]) {
|
if (subjects) {
|
||||||
where["subject2"] = subjects[1].title;
|
if (subjects[0]) {
|
||||||
}
|
where["subject1"] = subjects[0].title;
|
||||||
|
|
||||||
if (subjects[2]) {
|
|
||||||
where["subject3"] = subjects[2].title;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subjects[3]) {
|
|
||||||
where["subject4"] = subjects[3].title;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GuaribasQuestion.findAll({
|
|
||||||
where: where
|
|
||||||
})
|
|
||||||
.then((items: GuaribasQuestion[]) => {
|
|
||||||
if (!items) items = [];
|
|
||||||
if (items.length == 0) {
|
|
||||||
cb([], null);
|
|
||||||
} else {
|
|
||||||
cb(items, null);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(reason => {
|
|
||||||
if (reason.message.indexOf("no such table: IGBInstance") != -1) {
|
|
||||||
cb([], null);
|
|
||||||
} else {
|
|
||||||
cb(null, reason);
|
|
||||||
logger.info(`GuaribasServiceError: ${reason}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
importKbTabularFile(
|
|
||||||
basedir: string,
|
|
||||||
filename: string,
|
|
||||||
instanceId: number,
|
|
||||||
packageId: number,
|
|
||||||
cb
|
|
||||||
) {
|
|
||||||
var filePath = UrlJoin(basedir, filename);
|
|
||||||
|
|
||||||
var parser = Parse(
|
|
||||||
{
|
|
||||||
delimiter: "\t"
|
|
||||||
},
|
|
||||||
function (err, data) {
|
|
||||||
Async.eachSeries(data, function (line, callback) {
|
|
||||||
callback();
|
|
||||||
let subjectsText = line[0];
|
|
||||||
var from = line[1];
|
|
||||||
var to = line[2];
|
|
||||||
var question = line[3];
|
|
||||||
var answer = line[4];
|
|
||||||
|
|
||||||
// Skip the first line.
|
|
||||||
|
|
||||||
if (!(subjectsText === "subjects" && from == "from")) {
|
|
||||||
let format = ".txt";
|
|
||||||
|
|
||||||
// Extract answer from external media if any.
|
|
||||||
|
|
||||||
if (answer.indexOf(".md") > -1) {
|
|
||||||
let mediaFilename = UrlJoin(basedir, "..", "articles", answer);
|
|
||||||
if (Fs.existsSync(mediaFilename)) {
|
|
||||||
answer = Fs.readFileSync(mediaFilename, "utf8");
|
|
||||||
format = ".md";
|
|
||||||
} else {
|
|
||||||
logger.info("[GBImporter] File not found: ", mediaFilename);
|
|
||||||
answer =
|
|
||||||
"Por favor, contate a administração para rever esta pergunta.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let subjectArray = subjectsText.split(".");
|
|
||||||
let subject1: string,
|
|
||||||
subject2: string,
|
|
||||||
subject3: string,
|
|
||||||
subject4: string;
|
|
||||||
|
|
||||||
var indexer = 0;
|
|
||||||
subjectArray.forEach(element => {
|
|
||||||
if (indexer == 0) {
|
|
||||||
subject1 = subjectArray[indexer].substring(0, 63);
|
|
||||||
} else if (indexer == 1) {
|
|
||||||
subject2 = subjectArray[indexer].substring(0, 63);
|
|
||||||
} else if (indexer == 2) {
|
|
||||||
subject3 = subjectArray[indexer].substring(0, 63);
|
|
||||||
} else if (indexer == 3) {
|
|
||||||
subject4 = subjectArray[indexer].substring(0, 63);
|
|
||||||
}
|
|
||||||
indexer++;
|
|
||||||
});
|
|
||||||
|
|
||||||
GuaribasAnswer.create({
|
|
||||||
instanceId: instanceId,
|
|
||||||
content: answer,
|
|
||||||
format: format,
|
|
||||||
packageId: packageId
|
|
||||||
}).then(function (answer: GuaribasAnswer) {
|
|
||||||
GuaribasQuestion.create({
|
|
||||||
from: from,
|
|
||||||
to: to,
|
|
||||||
subject1: subject1,
|
|
||||||
subject2: subject2,
|
|
||||||
subject3: subject3,
|
|
||||||
subject4: subject4,
|
|
||||||
content: question,
|
|
||||||
instanceId: instanceId,
|
|
||||||
answerId: answer.answerId,
|
|
||||||
packageId: packageId
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
logger.warn("[GBImporter] Missing header in file: ", filename);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
if (subjects[1]) {
|
||||||
);
|
where["subject2"] = subjects[1].title;
|
||||||
Fs.createReadStream(filePath, {
|
}
|
||||||
encoding: "UCS-2"
|
|
||||||
}).pipe(parser);
|
if (subjects[2]) {
|
||||||
|
where["subject3"] = subjects[2].title;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subjects[3]) {
|
||||||
|
where["subject4"] = subjects[3].title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GuaribasQuestion.findAll({
|
||||||
|
where: where
|
||||||
|
})
|
||||||
|
.then((items: GuaribasQuestion[]) => {
|
||||||
|
if (!items) items = [];
|
||||||
|
if (items.length == 0) {
|
||||||
|
resolve([]);
|
||||||
|
} else {
|
||||||
|
resolve(items);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(reason => {
|
||||||
|
if (reason.message.indexOf("no such table: IGBInstance") != -1) {
|
||||||
|
resolve([]);
|
||||||
|
} else {
|
||||||
|
reject(reason);
|
||||||
|
logger.info(`GuaribasServiceError: ${reason}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sendAnswer(conversationalService: IGBConversationalService, dc: any, answer: GuaribasAnswer) {
|
async importKbTabularFile(
|
||||||
|
filePath: string,
|
||||||
|
instanceId: number,
|
||||||
|
packageId: number
|
||||||
|
): Promise<GuaribasQuestion[]> {
|
||||||
|
return new Promise<GuaribasQuestion[]>(
|
||||||
|
(resolve, reject) => {
|
||||||
|
|
||||||
|
let file = Fs.readFileSync(filePath, "UCS-2");
|
||||||
|
let opts = {
|
||||||
|
delimiter: "\t"
|
||||||
|
};
|
||||||
|
|
||||||
|
var parser = parse(file, opts).then((data) => {
|
||||||
|
asyncPromise.eachSeries(data, (line) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
// Extracts values from columns in the current line.
|
||||||
|
|
||||||
|
let subjectsText = line[0];
|
||||||
|
var from = line[1];
|
||||||
|
var to = line[2];
|
||||||
|
var question = line[3];
|
||||||
|
var answer = line[4];
|
||||||
|
|
||||||
|
// Skips the first line.
|
||||||
|
|
||||||
|
if (!(subjectsText === "subjects" && from == "from")) {
|
||||||
|
let format = ".txt";
|
||||||
|
|
||||||
|
// Extracts answer from external media if any.
|
||||||
|
|
||||||
|
if (answer.indexOf(".md") > -1) {
|
||||||
|
let mediaFilename = UrlJoin(path.dirname(filePath), "..", "articles", answer);
|
||||||
|
if (Fs.existsSync(mediaFilename)) {
|
||||||
|
answer = Fs.readFileSync(mediaFilename, "utf8");
|
||||||
|
format = ".md";
|
||||||
|
} else {
|
||||||
|
logger.info("[GBImporter] File not found: ", mediaFilename);
|
||||||
|
answer =
|
||||||
|
"Por favor, contate a administração para rever esta pergunta.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Processes subjects hierarchy splitting by dots.
|
||||||
|
|
||||||
|
let subjectArray = subjectsText.split(".");
|
||||||
|
let subject1: string, subject2: string, subject3: string,
|
||||||
|
subject4: string;
|
||||||
|
var indexer = 0;
|
||||||
|
|
||||||
|
subjectArray.forEach(element => {
|
||||||
|
if (indexer == 0) {
|
||||||
|
subject1 = subjectArray[indexer].substring(0, 63);
|
||||||
|
} else if (indexer == 1) {
|
||||||
|
subject2 = subjectArray[indexer].substring(0, 63);
|
||||||
|
} else if (indexer == 2) {
|
||||||
|
subject3 = subjectArray[indexer].substring(0, 63);
|
||||||
|
} else if (indexer == 3) {
|
||||||
|
subject4 = subjectArray[indexer].substring(0, 63);
|
||||||
|
}
|
||||||
|
indexer++;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Now with all the data ready, creates entities in the store.
|
||||||
|
|
||||||
|
GuaribasAnswer.create({
|
||||||
|
instanceId: instanceId,
|
||||||
|
content: answer,
|
||||||
|
format: format,
|
||||||
|
packageId: packageId
|
||||||
|
}).then((answer: GuaribasAnswer) => {
|
||||||
|
GuaribasQuestion.create({
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
subject1: subject1,
|
||||||
|
subject2: subject2,
|
||||||
|
subject3: subject3,
|
||||||
|
subject4: subject4,
|
||||||
|
content: question,
|
||||||
|
instanceId: instanceId,
|
||||||
|
answerId: answer.answerId,
|
||||||
|
packageId: packageId
|
||||||
|
}).then((question: GuaribasQuestion) => {
|
||||||
|
resolve(question);
|
||||||
|
}).error(reason => reject(reason));
|
||||||
|
}).error(reason => reject(reason));;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
logger.warn("[GBImporter] Missing header in file: ", filePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).error(reason => reject(reason));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendAnswer(conversationalService: IGBConversationalService,
|
||||||
|
dc: any, answer: GuaribasAnswer) {
|
||||||
|
|
||||||
if (answer.content.endsWith('.mp4')) {
|
if (answer.content.endsWith('.mp4')) {
|
||||||
conversationalService.sendEvent(dc, "play", {
|
conversationalService.sendEvent(dc, "play", {
|
||||||
playerType: "video",
|
playerType: "video",
|
||||||
data: answer.content
|
data: answer.content
|
||||||
});
|
});
|
||||||
} else if (answer.content.length > 140 && dc.message.source != "directline") {
|
} else if (answer.content.length > 140 &&
|
||||||
|
dc.message.source != "directline") {
|
||||||
let messages = [
|
let messages = [
|
||||||
"Vou te responder na tela para melhor visualização...",
|
"Vou te responder na tela para melhor visualização...",
|
||||||
"A resposta está na tela...",
|
"A resposta está na tela...",
|
||||||
|
@ -486,120 +489,124 @@ export class KBService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async importKbPackage(
|
||||||
importKbPackage(
|
|
||||||
localPath: string,
|
localPath: string,
|
||||||
packageStorage: GuaribasPackage,
|
packageStorage: GuaribasPackage,
|
||||||
instance: IGBInstance
|
instance: IGBInstance
|
||||||
) {
|
): Promise<GuaribasQuestion[]> {
|
||||||
this.importSubjectFile(
|
return new Promise<GuaribasQuestion[]>(
|
||||||
packageStorage.packageId,
|
(resolve, reject) => {
|
||||||
UrlJoin(localPath, "subjects.json"),
|
|
||||||
instance
|
// Imports subjects tree into database and return it.
|
||||||
);
|
|
||||||
let _this_ = this;
|
this.importSubjectFile(
|
||||||
setTimeout(() => {
|
packageStorage.packageId,
|
||||||
_this_.importKbTabularDirectory(
|
UrlJoin(localPath, "subjects.json"),
|
||||||
localPath,
|
instance
|
||||||
instance,
|
).then((value: GuaribasQuestion[]) => {
|
||||||
packageStorage.packageId
|
|
||||||
);
|
// Import all .tsv files in the tabular directory.
|
||||||
}, 3000);
|
|
||||||
|
this.importKbTabularDirectory(
|
||||||
|
localPath,
|
||||||
|
instance,
|
||||||
|
packageStorage.packageId
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
importKbTabularDirectory(
|
importKbTabularDirectory(
|
||||||
localPath: string,
|
localPath: string,
|
||||||
instance: IGBInstance,
|
instance: IGBInstance,
|
||||||
packageId: number
|
packageId: number
|
||||||
) {
|
): Promise<GuaribasQuestion[]> {
|
||||||
let _this_ = this;
|
return new Promise(
|
||||||
Walk.files(
|
(resolve, reject) => {
|
||||||
UrlJoin(localPath, "tabular"),
|
|
||||||
(basedir, filename, stat, next) => {
|
walkPromise(UrlJoin(localPath, "tabular")).then((files) => {
|
||||||
if (filename.endsWith(".tsv")) {
|
files.array.forEach(file => {
|
||||||
_this_.importKbTabularFile(
|
if (file.endsWith(".tsv")) {
|
||||||
basedir,
|
this.importKbTabularFile(
|
||||||
filename,
|
file,
|
||||||
instance.instanceId,
|
instance.instanceId,
|
||||||
packageId,
|
packageId);
|
||||||
(data, err) => {
|
|
||||||
if (err) {
|
|
||||||
logger.info(err);
|
|
||||||
} else {
|
|
||||||
logger.info("Import KB done.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function (err) {
|
|
||||||
if (err) logger.info(err);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
importSubjectFile(
|
|
||||||
packageId: number,
|
|
||||||
filename: string,
|
|
||||||
instance: IGBInstance
|
|
||||||
) {
|
|
||||||
var subjects = JSON.parse(Fs.readFileSync(filename, "utf8"));
|
|
||||||
|
|
||||||
function doIt(subjects: GuaribasSubject[], parentSubjectId: number) {
|
|
||||||
Async.eachSeries(subjects, (item, callback) => {
|
|
||||||
let mediaFilename = item.id + ".png";
|
|
||||||
GuaribasSubject.create({
|
|
||||||
internalId: item.id,
|
|
||||||
parentSubjectId: parentSubjectId,
|
|
||||||
instanceId: instance.instanceId,
|
|
||||||
from: item.from,
|
|
||||||
to: item.to,
|
|
||||||
title: item.title,
|
|
||||||
description: item.description,
|
|
||||||
packageId: packageId
|
|
||||||
}).then((value: any) => {
|
|
||||||
if (item.children) {
|
|
||||||
doIt(item.children, value.subjectId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
doIt(subjects.children, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
undeployKbFromStorage(
|
|
||||||
instance: IGBInstance,
|
|
||||||
packageId: number,
|
|
||||||
cb: GBServiceCallback<any>
|
|
||||||
) {
|
|
||||||
GuaribasQuestion.destroy({
|
|
||||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
|
||||||
}).then(value => {
|
|
||||||
GuaribasAnswer.destroy({
|
|
||||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
|
||||||
}).then(value => {
|
|
||||||
GuaribasSubject.destroy({
|
|
||||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
|
||||||
}).then(value => {
|
|
||||||
GuaribasPackage.destroy({
|
|
||||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
|
||||||
}).then(value => {
|
|
||||||
cb(null, null);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
|
async importSubjectFile(
|
||||||
|
packageId: number,
|
||||||
|
filename: string,
|
||||||
|
instance: IGBInstance
|
||||||
|
): Promise<GuaribasQuestion[]> {
|
||||||
|
return new Promise<GuaribasQuestion[]>(
|
||||||
|
(resolve, reject) => {
|
||||||
|
|
||||||
|
var subjects = JSON.parse(Fs.readFileSync(filename, "utf8"));
|
||||||
|
|
||||||
|
const doIt = (subjects: GuaribasSubject[], parentSubjectId: number) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
asyncPromise.eachSeries(subjects, (item, callback) => {
|
||||||
|
let mediaFilename = item.id + ".png";
|
||||||
|
GuaribasSubject.create({
|
||||||
|
internalId: item.id,
|
||||||
|
parentSubjectId: parentSubjectId,
|
||||||
|
instanceId: instance.instanceId,
|
||||||
|
from: item.from,
|
||||||
|
to: item.to,
|
||||||
|
title: item.title,
|
||||||
|
description: item.description,
|
||||||
|
packageId: packageId
|
||||||
|
}).then((value: any) => {
|
||||||
|
if (item.children) {
|
||||||
|
doIt(item.children, value.subjectId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
doIt(subjects.children, null);
|
||||||
|
resolve()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
undeployKbFromStorage(
|
||||||
|
instance: IGBInstance,
|
||||||
|
packageId: number
|
||||||
|
) {
|
||||||
|
// TODO: call reject.
|
||||||
|
return new Promise(
|
||||||
|
(resolve, reject) => {
|
||||||
|
GuaribasQuestion.destroy({
|
||||||
|
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||||
|
}).then(value => {
|
||||||
|
GuaribasAnswer.destroy({
|
||||||
|
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||||
|
}).then(value => {
|
||||||
|
GuaribasSubject.destroy({
|
||||||
|
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||||
|
}).then(value => {
|
||||||
|
GuaribasPackage.destroy({
|
||||||
|
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||||
|
}).then(value => {
|
||||||
|
resolve(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deploys a knowledge base to the storage using the .gbkb format.
|
* Deploys a knowledge base to the storage using the .gbkb format.
|
||||||
*
|
*
|
||||||
* @param localPath Path to the .gbkb folder.
|
* @param localPath Path to the .gbkb folder.
|
||||||
* @param cb Package instance or error info.
|
*/
|
||||||
*/
|
async deployKb(core: IGBCoreService, deployer: GBDeployer, localPath: string) {
|
||||||
deployKb(core: IGBCoreService, deployer: GBDeployer, localPath: string, cb: GBServiceCallback<any>) {
|
|
||||||
let packageType = Path.extname(localPath);
|
let packageType = Path.extname(localPath);
|
||||||
let packageName = Path.basename(localPath);
|
let packageName = Path.basename(localPath);
|
||||||
logger.info("[GBDeployer] Opening package: ", packageName);
|
logger.info("[GBDeployer] Opening package: ", packageName);
|
||||||
|
@ -607,18 +614,10 @@ export class KBService {
|
||||||
Fs.readFileSync(UrlJoin(localPath, "package.json"), "utf8")
|
Fs.readFileSync(UrlJoin(localPath, "package.json"), "utf8")
|
||||||
);
|
);
|
||||||
|
|
||||||
core.loadInstance(packageObject.botId, (instance, err) => {
|
let instance = await core.loadInstance(packageObject.botId);
|
||||||
deployer.deployPackageToStorage(
|
let p = await deployer.deployPackageToStorage(
|
||||||
instance.instanceId,
|
instance.instanceId,
|
||||||
packageName,
|
packageName);
|
||||||
(p, err) => {
|
await this.importKbPackage(localPath, p, instance);
|
||||||
this.importKbPackage(localPath, p, instance);
|
|
||||||
setTimeout(() => {
|
|
||||||
cb(null, null);
|
|
||||||
}, 8000);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,13 +39,13 @@ const UrlJoin = require("url-join");
|
||||||
const Walk = require("fs-walk");
|
const Walk = require("fs-walk");
|
||||||
const logger = require("../../../src/logger");
|
const logger = require("../../../src/logger");
|
||||||
|
|
||||||
import { GBServiceCallback, GBService, IGBInstance } from "botlib";
|
import { GBServiceCallback, GBService, IGBInstance } from "botlib";
|
||||||
import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from "../models";
|
import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from "../models";
|
||||||
|
|
||||||
export class SecService extends GBService {
|
export class SecService extends GBService {
|
||||||
|
|
||||||
importSecurityFile(localPath: string, instance: IGBInstance) {
|
async importSecurityFile(localPath: string, instance: IGBInstance) {
|
||||||
var security = JSON.parse(
|
let security = JSON.parse(
|
||||||
Fs.readFileSync(UrlJoin(localPath, "security.json"), "utf8")
|
Fs.readFileSync(UrlJoin(localPath, "security.json"), "utf8")
|
||||||
);
|
);
|
||||||
security.groups.forEach(group => {
|
security.groups.forEach(group => {
|
||||||
|
@ -61,43 +61,46 @@ export class SecService extends GBService {
|
||||||
userName: user.userName
|
userName: user.userName
|
||||||
});
|
});
|
||||||
userDb.save().then(userDb => {
|
userDb.save().then(userDb => {
|
||||||
let userGroup = GuaribasUserGroup.build();
|
let userGroup = GuaribasUserGroup.build();
|
||||||
userGroup.groupId = groupDb.groupId;
|
userGroup.groupId = groupDb.groupId;
|
||||||
userGroup.userId = userDb.userId;
|
userGroup.userId = userDb.userId;
|
||||||
userGroup.save();
|
userGroup.save();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ensureUser(
|
async ensureUser(
|
||||||
instanceId: number,
|
instanceId: number,
|
||||||
userSystemId: string,
|
userSystemId: string,
|
||||||
userName: string,
|
userName: string,
|
||||||
address: string,
|
address: string,
|
||||||
channelName: string,
|
channelName: string,
|
||||||
displayName: string,
|
displayName: string
|
||||||
cb: GBServiceCallback<GuaribasUser>
|
): Promise<GuaribasUser> {
|
||||||
) {
|
return new Promise<GuaribasUser>(
|
||||||
GuaribasUser.findOne({
|
(resolve, reject) => {
|
||||||
attributes: ["instanceId", "internalAddress"],
|
|
||||||
where: {
|
GuaribasUser.findOne({
|
||||||
instanceId: instanceId,
|
attributes: ["instanceId", "internalAddress"],
|
||||||
userSystemId: userSystemId
|
where: {
|
||||||
}
|
instanceId: instanceId,
|
||||||
}).then(user => {
|
userSystemId: userSystemId
|
||||||
if (!user) {
|
}
|
||||||
user = GuaribasUser.build();
|
}).then(user => {
|
||||||
}
|
if (!user) {
|
||||||
user.userSystemId = userSystemId;
|
user = GuaribasUser.build();
|
||||||
user.userName = userName;
|
}
|
||||||
user.displayName = displayName;
|
user.userSystemId = userSystemId;
|
||||||
user.internalAddress = address;
|
user.userName = userName;
|
||||||
user.email = userName;
|
user.displayName = displayName;
|
||||||
user.defaultChannel = channelName;
|
user.internalAddress = address;
|
||||||
user.save();
|
user.email = userName;
|
||||||
cb(user, null);
|
user.defaultChannel = channelName;
|
||||||
});
|
user.save();
|
||||||
|
resolve(user);
|
||||||
|
}).error(reason => reject(reason));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,7 +138,6 @@ export class WhatsappDirectLine extends GBService {
|
||||||
.then((conversationId) => {
|
.then((conversationId) => {
|
||||||
|
|
||||||
this.conversationIds[from] = conversationId;
|
this.conversationIds[from] = conversationId;
|
||||||
|
|
||||||
this.inputMessage(client, conversationId, text,
|
this.inputMessage(client, conversationId, text,
|
||||||
from, fromName);
|
from, fromName);
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
"tedious": "^2.6.4",
|
"tedious": "^2.6.4",
|
||||||
"url-join": "^4.0.0",
|
"url-join": "^4.0.0",
|
||||||
"wait-until": "^0.0.2",
|
"wait-until": "^0.0.2",
|
||||||
|
"walk-promise": "^0.2.0",
|
||||||
"winston": "^3.0.0"
|
"winston": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
39
src/app.ts
39
src/app.ts
|
@ -77,16 +77,18 @@ export class GBServer {
|
||||||
extended: true
|
extended: true
|
||||||
}));
|
}));
|
||||||
|
|
||||||
server.listen(port, () => {
|
server.listen(port, async () => {
|
||||||
|
|
||||||
logger.info(`Accepting connections on ${port}...`);
|
try {
|
||||||
logger.info(`Starting instances...`);
|
|
||||||
|
|
||||||
// Reads basic configuration, initialize minimal services.
|
logger.info(`Accepting connections on ${port}...`);
|
||||||
|
logger.info(`Starting instances...`);
|
||||||
|
|
||||||
GBConfigService.init();
|
// Reads basic configuration, initialize minimal services.
|
||||||
let core = new GBCoreService();
|
|
||||||
core.initDatabase(() => {
|
GBConfigService.init();
|
||||||
|
let core = new GBCoreService();
|
||||||
|
await core.initDatabase();
|
||||||
|
|
||||||
// Boot a bot package if any.
|
// Boot a bot package if any.
|
||||||
|
|
||||||
|
@ -104,23 +106,16 @@ export class GBServer {
|
||||||
p.loadPackage(core, core.sequelize);
|
p.loadPackage(core, core.sequelize);
|
||||||
});
|
});
|
||||||
|
|
||||||
(async () => {
|
await minService.deployPackages(core, server, appPackages);
|
||||||
try {
|
logger.info(`The Bot Server is in RUNNING mode...`);
|
||||||
await minService.deployPackages(core, server, appPackages);
|
|
||||||
logger.info(`The Bot Server is in RUNNING mode...`);
|
|
||||||
|
|
||||||
minService.buildMin(instance => {
|
let instance = await minService.buildMin(server, appPackages);
|
||||||
logger.info(`Instance loaded: ${instance.botId}...`);
|
logger.info(`Instance loaded: ${instance.botId}...`);
|
||||||
}, server, appPackages);
|
return core;
|
||||||
|
} catch (err) {
|
||||||
|
logger.info(err);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
logger.info(err);
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
return core;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue