fix(config): TSLint parsed on all files.
new(config): Several CI integrations.
This commit is contained in:
parent
6f868c5178
commit
ea978f7d65
47 changed files with 11509 additions and 1839 deletions
|
@ -6,4 +6,4 @@ tmp
|
|||
.env
|
||||
.coveralls.yml
|
||||
coverage
|
||||
{YOUR_LIB}-*.tgz
|
||||
BotServer-*.tgz
|
||||
|
|
12
.travis.yml
12
.travis.yml
|
@ -7,7 +7,7 @@ notifications:
|
|||
email: false
|
||||
|
||||
before_install:
|
||||
- npm install --global nyc mocha typescript rimraf shx
|
||||
- npm install --global nyc mocha typescript shx
|
||||
|
||||
install:
|
||||
- npm install
|
||||
|
@ -17,7 +17,6 @@ before_script:
|
|||
|
||||
script:
|
||||
#- npm run build-docs
|
||||
#- npm run tslint
|
||||
#- npm run coveralls
|
||||
|
||||
branches:
|
||||
|
@ -29,10 +28,17 @@ after_success:
|
|||
- npm pack
|
||||
|
||||
deploy:
|
||||
- provider: pages
|
||||
skip_cleanup: true
|
||||
local_dir: docs/reference
|
||||
github_token: $GITHUB_TOKEN
|
||||
on:
|
||||
tags: false
|
||||
|
||||
- provider: releases
|
||||
api_key: $GITHUB_TOKEN
|
||||
file_glob: true
|
||||
file: "{YOURLIB}-*.tgz"
|
||||
file: "BotServer-*.tgz"
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: false
|
||||
|
|
9654
package-lock.json
generated
9654
package-lock.json
generated
File diff suppressed because it is too large
Load diff
50
package.json
50
package.json
|
@ -18,15 +18,29 @@
|
|||
"url": "https://github.com/pragmatismo-io/BotServer.git"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"tslint": "tslint ./src ./packages/**/*.ts -t verbose",
|
||||
"clean": "shx rm -rf node_modules/ dist/ docs/reference",
|
||||
"tslint": "tslint --fix ./src/*.ts ./packages/**/*.ts -t verbose",
|
||||
"build": "tsc",
|
||||
"build-docs": "typedoc --options typedoc.json src/",
|
||||
"test": "nyc --reporter=html --reporter=text mocha -r ts-node/register packages/**/*.test.ts ",
|
||||
"pretest": "npm run build",
|
||||
"coveralls": "npm run test && nyc report --reporter=text-lcov | coveralls",
|
||||
"start": "node ./dist/src/app.js",
|
||||
"watch:build": "tsc --watch",
|
||||
"watch:server": "nodemon './dist/index.js' --watch './dist'"
|
||||
"watch:server": "nodemon './dist/index.js' --watch './dist'",
|
||||
"posttypedoc": "shx cp .nojekyll docs/reference/.nojekyll",
|
||||
"ban": "ban",
|
||||
"issues": "git-issues",
|
||||
"license": "license-checker --production --onlyunknown --csv",
|
||||
"lint": "standard --verbose --fix 'src/*.js' 'cypress/**/*.js'",
|
||||
"prelint": "npm run pretty",
|
||||
"pretty": "prettier-standard 'src/*.ts' 'packages/**/*.ts'",
|
||||
"secure": "nsp check",
|
||||
"size": "t=\"$(npm pack .)\"; wc -c \"${t}\"; tar tvf \"${t}\"; rm \"${t}\";",
|
||||
"unused-deps": "dependency-check --unused --no-dev ./package.json",
|
||||
"travis-deploy-once": "travis-deploy-once",
|
||||
"semantic-release": "semantic-release",
|
||||
"commit": "commit-wizard"
|
||||
},
|
||||
"engines": {
|
||||
"node": "=10.13.0"
|
||||
|
@ -81,7 +95,7 @@
|
|||
"reflect-metadata": "0.1.12",
|
||||
"request-promise-native": "1.0.5",
|
||||
"scanf": "^1.0.2",
|
||||
"sequelize": "4.41.1",
|
||||
"sequelize": "4.41.2",
|
||||
"sequelize-typescript": "0.6.6",
|
||||
"simple-git": "^1.107.0",
|
||||
"sqlite3": "4.0.4",
|
||||
|
@ -99,14 +113,25 @@
|
|||
"winston": "3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^2.2.47",
|
||||
"@types/mocha": "^5.2.5",
|
||||
"chai": "^4.2.0",
|
||||
"coveralls": "^3.0.2",
|
||||
"mocha": "^5.2.0",
|
||||
"shx": "^0.3.2",
|
||||
"ts-loader": "^5.3.0",
|
||||
"tslint": "^5.11.0",
|
||||
"tslint-microsoft-contrib": "^5.2.1"
|
||||
"tslint-microsoft-contrib": "^5.2.1",
|
||||
"ban-sensitive-files": "1.9.2",
|
||||
"dependency-check": "3.2.1",
|
||||
"deps-ok": "1.4.1",
|
||||
"git-issues": "1.3.1",
|
||||
"license-checker": "24.0.1",
|
||||
"nsp": "3.2.1",
|
||||
"pre-git": "3.17.1",
|
||||
"prettier-standard": "8.0.1",
|
||||
"standard": "12.0.1",
|
||||
"travis-deploy-once": "5.0.9",
|
||||
"semantic-release": "15.10.8"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"env": {
|
||||
|
@ -152,5 +177,18 @@
|
|||
"warn"
|
||||
]
|
||||
}
|
||||
},
|
||||
"release": {
|
||||
"analyzeCommits": "simple-commit-message"
|
||||
},
|
||||
"config": {
|
||||
"pre-git": {
|
||||
"commit-msg": "simple",
|
||||
"pre-commit": [],
|
||||
"pre-push": [],
|
||||
"post-commit": [],
|
||||
"post-checkout": [],
|
||||
"post-merge": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,36 +36,36 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const UrlJoin = require("url-join");
|
||||
import { GBMinInstance } from "botlib";
|
||||
import { IGBDialog } from "botlib";
|
||||
import { GBDeployer } from "../../core.gbapp/services/GBDeployer";
|
||||
import { GBImporter } from "../../core.gbapp/services/GBImporter";
|
||||
import { GBConfigService } from "../../core.gbapp/services/GBConfigService";
|
||||
import { BotAdapter } from "botbuilder";
|
||||
import { GBAdminService } from "../services/GBAdminService";
|
||||
import { Messages } from "../strings";
|
||||
import { WaterfallDialog } from "botbuilder-dialogs";
|
||||
const UrlJoin = require('url-join');
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { GBMinInstance } from 'botlib';
|
||||
import { IGBDialog } from 'botlib';
|
||||
import { GBConfigService } from '../../core.gbapp/services/GBConfigService';
|
||||
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
|
||||
import { GBImporter } from '../../core.gbapp/services/GBImporter';
|
||||
import { GBAdminService } from '../services/GBAdminService';
|
||||
import { Messages } from '../strings';
|
||||
|
||||
/**
|
||||
* Dialogs for administration tasks.
|
||||
*/
|
||||
export class AdminDialog extends IGBDialog {
|
||||
static async createFarmCommand(text: any, min: GBMinInstance) {}
|
||||
public static async createFarmCommand(text: any, min: GBMinInstance) {}
|
||||
|
||||
static async undeployPackageCommand(text: any, min: GBMinInstance) {
|
||||
let packageName = text.split(" ")[1];
|
||||
let importer = new GBImporter(min.core);
|
||||
let deployer = new GBDeployer(min.core, importer);
|
||||
public static async undeployPackageCommand(text: any, min: GBMinInstance) {
|
||||
const packageName = text.split(' ')[1];
|
||||
const importer = new GBImporter(min.core);
|
||||
const deployer = new GBDeployer(min.core, importer);
|
||||
await deployer.undeployPackageFromLocalPath(
|
||||
min.instance,
|
||||
UrlJoin("packages", packageName)
|
||||
UrlJoin('packages', packageName)
|
||||
);
|
||||
}
|
||||
|
||||
static async deployPackageCommand(text: string, deployer: GBDeployer) {
|
||||
let packageName = text.split(" ")[1];
|
||||
let additionalPath = GBConfigService.get("ADDITIONAL_DEPLOY_PATH");
|
||||
public static async deployPackageCommand(text: string, deployer: GBDeployer) {
|
||||
const packageName = text.split(' ')[1];
|
||||
const additionalPath = GBConfigService.get('ADDITIONAL_DEPLOY_PATH');
|
||||
await deployer.deployPackageFromLocalPath(
|
||||
UrlJoin(additionalPath, packageName)
|
||||
);
|
||||
|
@ -76,59 +76,59 @@ export class AdminDialog extends IGBDialog {
|
|||
* @param bot The bot adapter.
|
||||
* @param min The minimal bot instance data.
|
||||
*/
|
||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
// Setup services.
|
||||
|
||||
let importer = new GBImporter(min.core);
|
||||
let deployer = new GBDeployer(min.core, importer);
|
||||
const importer = new GBImporter(min.core);
|
||||
const deployer = new GBDeployer(min.core, importer);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog("/admin", [
|
||||
new WaterfallDialog('/admin', [
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
const prompt = Messages[locale].authenticate;
|
||||
await step.prompt("textPrompt", prompt);
|
||||
await step.prompt('textPrompt', prompt);
|
||||
return await step.next();
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
let password = step.result;
|
||||
const password = step.result;
|
||||
if (
|
||||
password === GBConfigService.get("ADMIN_PASS") &&
|
||||
password === GBConfigService.get('ADMIN_PASS') &&
|
||||
GBAdminService.StrongRegex.test(password)
|
||||
) {
|
||||
await step.context.sendActivity(Messages[locale].welcome);
|
||||
await step.prompt("textPrompt", Messages[locale].which_task);
|
||||
await step.prompt('textPrompt', Messages[locale].which_task);
|
||||
} else {
|
||||
await step.prompt("textPrompt", Messages[locale].wrong_password);
|
||||
await step.prompt('textPrompt', Messages[locale].wrong_password);
|
||||
await step.endDialog();
|
||||
}
|
||||
return await step.next();
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
var text = step.result;
|
||||
let cmdName = text.split(" ")[0];
|
||||
const text = step.result;
|
||||
const cmdName = text.split(' ')[0];
|
||||
|
||||
step.context.sendActivity(Messages[locale].working(cmdName));
|
||||
let unknownCommand = false;
|
||||
|
||||
if (text === "quit") {
|
||||
await step.replaceDialog("/");
|
||||
} else if (cmdName === "createFarm") {
|
||||
if (text === 'quit') {
|
||||
await step.replaceDialog('/');
|
||||
} else if (cmdName === 'createFarm') {
|
||||
await AdminDialog.createFarmCommand(text, deployer);
|
||||
await step.replaceDialog("/admin", { firstRun: false });
|
||||
} else if (cmdName === "deployPackage") {
|
||||
await step.replaceDialog('/admin', { firstRun: false });
|
||||
} else if (cmdName === 'deployPackage') {
|
||||
await AdminDialog.deployPackageCommand(text, deployer);
|
||||
await step.replaceDialog("/admin", { firstRun: false });
|
||||
} else if (cmdName === "redeployPackage") {
|
||||
await step.replaceDialog('/admin', { firstRun: false });
|
||||
} else if (cmdName === 'redeployPackage') {
|
||||
await AdminDialog.undeployPackageCommand(text, min);
|
||||
await AdminDialog.deployPackageCommand(text, deployer);
|
||||
await step.replaceDialog("/admin", { firstRun: false });
|
||||
} else if (cmdName === "undeployPackage") {
|
||||
await step.replaceDialog('/admin', { firstRun: false });
|
||||
} else if (cmdName === 'undeployPackage') {
|
||||
await AdminDialog.undeployPackageCommand(text, min);
|
||||
await step.replaceDialog("/admin", { firstRun: false });
|
||||
} else if (cmdName === "setupSecurity") {
|
||||
await step.replaceDialog('/admin', { firstRun: false });
|
||||
} else if (cmdName === 'setupSecurity') {
|
||||
await AdminDialog.setupSecurity(min, step);
|
||||
} else {
|
||||
unknownCommand = true;
|
||||
|
@ -142,7 +142,7 @@ export class AdminDialog extends IGBDialog {
|
|||
);
|
||||
}
|
||||
await step.endDialog();
|
||||
await step.replaceDialog("/answer", { query: text });
|
||||
await step.replaceDialog('/answer', { query: text });
|
||||
return await step.next();
|
||||
}
|
||||
])
|
||||
|
@ -151,15 +151,15 @@ export class AdminDialog extends IGBDialog {
|
|||
|
||||
private static async setupSecurity(min: any, step: any) {
|
||||
const locale = step.activity.locale;
|
||||
let state = `${min.instance.instanceId}${Math.floor(
|
||||
const state = `${min.instance.instanceId}${Math.floor(
|
||||
Math.random() * 1000000000
|
||||
)}`;
|
||||
await min.adminService.setValue(
|
||||
min.instance.instanceId,
|
||||
"AntiCSRFAttackState",
|
||||
'AntiCSRFAttackState',
|
||||
state
|
||||
);
|
||||
let url = `https://login.microsoftonline.com/${
|
||||
const url = `https://login.microsoftonline.com/${
|
||||
min.instance.authenticatorTenant
|
||||
}/oauth2/authorize?client_id=${
|
||||
min.instance.authenticatorClientId
|
||||
|
|
|
@ -37,32 +37,30 @@
|
|||
'use strict';
|
||||
|
||||
import {
|
||||
Table,
|
||||
Column,
|
||||
Model,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
} from "sequelize-typescript";
|
||||
|
||||
Model,
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript';
|
||||
|
||||
@Table
|
||||
export class GuaribasAdmin extends Model<GuaribasAdmin>
|
||||
{
|
||||
export class GuaribasAdmin extends Model<GuaribasAdmin> {
|
||||
|
||||
@Column
|
||||
instanceId: number;
|
||||
public instanceId: number;
|
||||
|
||||
@Column
|
||||
key: string;
|
||||
public key: string;
|
||||
|
||||
@Column
|
||||
value: string;
|
||||
public value: string;
|
||||
|
||||
@Column
|
||||
@CreatedAt
|
||||
createdAt: Date;
|
||||
public createdAt: Date;
|
||||
|
||||
@Column
|
||||
@UpdatedAt
|
||||
updatedAt: Date;
|
||||
public updatedAt: Date;
|
||||
}
|
||||
|
|
|
@ -36,116 +36,41 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import { GuaribasAdmin } from "../models/AdminModel";
|
||||
import { IGBCoreService } from "botlib";
|
||||
import { AuthenticationContext, TokenResponse } from "adal-node";
|
||||
const UrlJoin = require("url-join");
|
||||
const msRestAzure = require("ms-rest-azure");
|
||||
const PasswordGenerator = require("strict-password-generator").default;
|
||||
import { AuthenticationContext, TokenResponse } from 'adal-node';
|
||||
import { IGBCoreService } from 'botlib';
|
||||
import { GuaribasAdmin } from '../models/AdminModel';
|
||||
const UrlJoin = require('url-join');
|
||||
const msRestAzure = require('ms-rest-azure');
|
||||
const PasswordGenerator = require('strict-password-generator').default;
|
||||
|
||||
export class GBAdminService {
|
||||
|
||||
static GB_PROMPT: string = "GeneralBots: "
|
||||
|
||||
static generateUuid(): string {
|
||||
return msRestAzure.generateUuid();
|
||||
}
|
||||
static masterBotInstanceId = 0;
|
||||
public static GB_PROMPT: string = 'GeneralBots: ';
|
||||
public static masterBotInstanceId = 0;
|
||||
|
||||
public static StrongRegex = new RegExp(
|
||||
"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*+_-])(?=.{8,})"
|
||||
'^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*+_-])(?=.{8,})'
|
||||
);
|
||||
|
||||
core: IGBCoreService;
|
||||
public core: IGBCoreService;
|
||||
|
||||
constructor(core: IGBCoreService) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public async setValue(
|
||||
instanceId: number,
|
||||
key: string,
|
||||
value: string
|
||||
): Promise<GuaribasAdmin> {
|
||||
let options = { where: {} };
|
||||
options.where = { key: key };
|
||||
let admin = await GuaribasAdmin.findOne(options);
|
||||
if (admin == null) {
|
||||
admin = new GuaribasAdmin();
|
||||
admin.key = key;
|
||||
}
|
||||
admin.value = value;
|
||||
admin.instanceId = instanceId;
|
||||
return admin.save();
|
||||
}
|
||||
|
||||
public async getValue(instanceId: number, key: string) {
|
||||
let options = { where: {} };
|
||||
options.where = { key: key, instanceId: instanceId };
|
||||
let obj = await GuaribasAdmin.findOne(options);
|
||||
return Promise.resolve(obj.value);
|
||||
}
|
||||
|
||||
public async acquireElevatedToken(instanceId): Promise<string> {
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
let instance = await this.core.loadInstanceById(instanceId);
|
||||
|
||||
let expiresOn = new Date(await this.getValue(instanceId, "expiresOn"));
|
||||
if (expiresOn.getTime() > new Date().getTime()) {
|
||||
let accessToken = await this.getValue(instanceId, "accessToken");
|
||||
resolve(accessToken);
|
||||
} else {
|
||||
let authorizationUrl = UrlJoin(
|
||||
instance.authenticatorAuthorityHostUrl,
|
||||
instance.authenticatorTenant,
|
||||
"/oauth2/authorize"
|
||||
);
|
||||
|
||||
let refreshToken = await this.getValue(instanceId, "refreshToken");
|
||||
let resource = "https://graph.microsoft.com";
|
||||
var authenticationContext = new AuthenticationContext(authorizationUrl);
|
||||
authenticationContext.acquireTokenWithRefreshToken(
|
||||
refreshToken,
|
||||
instance.authenticatorClientId,
|
||||
instance.authenticatorClientSecret,
|
||||
resource,
|
||||
async (err, res) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
let token = res as TokenResponse;
|
||||
await this.setValue(
|
||||
instanceId,
|
||||
"accessToken",
|
||||
token.accessToken
|
||||
);
|
||||
await this.setValue(
|
||||
instanceId,
|
||||
"refreshToken",
|
||||
token.refreshToken
|
||||
);
|
||||
await this.setValue(
|
||||
instanceId,
|
||||
"expiresOn",
|
||||
token.expiresOn.toString()
|
||||
);
|
||||
resolve(token.accessToken);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
public static generateUuid(): string {
|
||||
return msRestAzure.generateUuid();
|
||||
}
|
||||
|
||||
public static async getADALTokenFromUsername(
|
||||
username: string,
|
||||
password: string
|
||||
) {
|
||||
let credentials = await GBAdminService.getADALCredentialsFromUsername(
|
||||
const credentials = await GBAdminService.getADALCredentialsFromUsername(
|
||||
username,
|
||||
password
|
||||
);
|
||||
let accessToken = credentials.tokenCache._entries[0].accessToken;
|
||||
const accessToken = credentials.tokenCache._entries[0].accessToken;
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
|
@ -153,7 +78,7 @@ export class GBAdminService {
|
|||
username: string,
|
||||
password: string
|
||||
) {
|
||||
let credentials = await msRestAzure.loginWithUsernamePassword(
|
||||
const credentials = await msRestAzure.loginWithUsernamePassword(
|
||||
username,
|
||||
password
|
||||
);
|
||||
|
@ -171,7 +96,7 @@ export class GBAdminService {
|
|||
maximumLength: 14
|
||||
};
|
||||
let password = passwordGenerator.generatePassword(options);
|
||||
password = password.replace(/@[=:;\?]/g, "#");
|
||||
password = password.replace(/@[=:;\?]/g, '#');
|
||||
return password;
|
||||
}
|
||||
|
||||
|
@ -185,8 +110,83 @@ export class GBAdminService {
|
|||
minimumLength: 12,
|
||||
maximumLength: 14
|
||||
};
|
||||
let name = passwordGenerator.generatePassword(options);
|
||||
const name = passwordGenerator.generatePassword(options);
|
||||
return name;
|
||||
}
|
||||
|
||||
public async setValue(
|
||||
instanceId: number,
|
||||
key: string,
|
||||
value: string
|
||||
): Promise<GuaribasAdmin> {
|
||||
const options = { where: {} };
|
||||
options.where = { key: key };
|
||||
let admin = await GuaribasAdmin.findOne(options);
|
||||
if (admin == null) {
|
||||
admin = new GuaribasAdmin();
|
||||
admin.key = key;
|
||||
}
|
||||
admin.value = value;
|
||||
admin.instanceId = instanceId;
|
||||
return admin.save();
|
||||
}
|
||||
|
||||
public async getValue(instanceId: number, key: string) {
|
||||
const options = { where: {} };
|
||||
options.where = { key: key, instanceId: instanceId };
|
||||
const obj = await GuaribasAdmin.findOne(options);
|
||||
return Promise.resolve(obj.value);
|
||||
}
|
||||
|
||||
public async acquireElevatedToken(instanceId): Promise<string> {
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
const instance = await this.core.loadInstanceById(instanceId);
|
||||
|
||||
const expiresOn = new Date(await this.getValue(instanceId, 'expiresOn'));
|
||||
if (expiresOn.getTime() > new Date().getTime()) {
|
||||
const accessToken = await this.getValue(instanceId, 'accessToken');
|
||||
resolve(accessToken);
|
||||
} else {
|
||||
const authorizationUrl = UrlJoin(
|
||||
instance.authenticatorAuthorityHostUrl,
|
||||
instance.authenticatorTenant,
|
||||
'/oauth2/authorize'
|
||||
);
|
||||
|
||||
const refreshToken = await this.getValue(instanceId, 'refreshToken');
|
||||
const resource = 'https://graph.microsoft.com';
|
||||
const authenticationContext = new AuthenticationContext(authorizationUrl);
|
||||
authenticationContext.acquireTokenWithRefreshToken(
|
||||
refreshToken,
|
||||
instance.authenticatorClientId,
|
||||
instance.authenticatorClientSecret,
|
||||
resource,
|
||||
async (err, res) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
const token = res as TokenResponse;
|
||||
await this.setValue(
|
||||
instanceId,
|
||||
'accessToken',
|
||||
token.accessToken
|
||||
);
|
||||
await this.setValue(
|
||||
instanceId,
|
||||
'refreshToken',
|
||||
token.refreshToken
|
||||
);
|
||||
await this.setValue(
|
||||
instanceId,
|
||||
'expiresOn',
|
||||
token.expiresOn.toString()
|
||||
);
|
||||
resolve(token.accessToken);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
export const Messages = {
|
||||
"en-US": {
|
||||
authenticate: "Please, authenticate:",
|
||||
welcome: "Welcome to Pragmatismo.io GeneralBots Administration.",
|
||||
which_task: "Which task do you wanna run now?",
|
||||
working:(command)=> `I'm working on ${command}...`,
|
||||
finshed_working:"Done.",
|
||||
'en-US': {
|
||||
authenticate: 'Please, authenticate:',
|
||||
welcome: 'Welcome to Pragmatismo.io GeneralBots Administration.',
|
||||
which_task: 'Which task do you wanna run now?',
|
||||
working: (command) => `I'm working on ${command}...`,
|
||||
finshed_working: 'Done.',
|
||||
unknown_command: text =>
|
||||
`Well, but ${text} is not a administrative General Bots command, I will try to search for it.`,
|
||||
hi: text => `Hello, ${text}.`,
|
||||
|
@ -12,11 +12,11 @@ export const Messages = {
|
|||
deployPackage: text => `Deploying package ${text}...`,
|
||||
redeployPackage: text => `Redeploying package ${text}...`,
|
||||
packageUndeployed: text => `Package ${text} undeployed...`,
|
||||
consent: (url)=>`Please, consent access to this app at: [Microsoft Online](${url}).`,
|
||||
wrong_password: "Sorry, wrong password. Please, try again."
|
||||
consent: (url) => `Please, consent access to this app at: [Microsoft Online](${url}).`,
|
||||
wrong_password: 'Sorry, wrong password. Please, try again.'
|
||||
},
|
||||
"pt-BR": {
|
||||
show_video: "Vou te mostrar um vídeo. Por favor, aguarde...",
|
||||
'pt-BR': {
|
||||
show_video: 'Vou te mostrar um vídeo. Por favor, aguarde...',
|
||||
hi: msg => `Oi, ${msg}.`
|
||||
}
|
||||
};
|
||||
|
|
|
@ -34,33 +34,31 @@
|
|||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
const UrlJoin = require("url-join")
|
||||
const UrlJoin = require('url-join');
|
||||
|
||||
import { GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
|
||||
|
||||
|
||||
import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"
|
||||
|
||||
import { Sequelize } from "sequelize-typescript"
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
|
||||
export class GBAnalyticsPackage implements IGBPackage {
|
||||
|
||||
sysPackages: IGBPackage[] = null
|
||||
|
||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
|
||||
|
||||
public sysPackages: IGBPackage[] = null;
|
||||
|
||||
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
|
||||
}
|
||||
unloadPackage(core: IGBCoreService): void {
|
||||
|
||||
public unloadPackage(core: IGBCoreService): void {
|
||||
|
||||
}
|
||||
loadBot(min: GBMinInstance): void {
|
||||
|
||||
public loadBot(min: GBMinInstance): void {
|
||||
|
||||
}
|
||||
unloadBot(min: GBMinInstance): void {
|
||||
|
||||
public unloadBot(min: GBMinInstance): void {
|
||||
|
||||
}
|
||||
onNewSession(min: GBMinInstance, step: any): void {
|
||||
|
||||
public onNewSession(min: GBMinInstance, step: any): void {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,36 +34,36 @@
|
|||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
DataTypes,
|
||||
DataTypeUUIDv4,
|
||||
DataTypeDate,
|
||||
DataTypeDecimal
|
||||
} from "sequelize"
|
||||
DataTypeDecimal,
|
||||
DataTypes,
|
||||
DataTypeUUIDv4
|
||||
} from 'sequelize';
|
||||
|
||||
import {
|
||||
Sequelize,
|
||||
Table,
|
||||
Column,
|
||||
Model,
|
||||
HasMany,
|
||||
AutoIncrement,
|
||||
BelongsTo,
|
||||
BelongsToMany,
|
||||
Length,
|
||||
ForeignKey,
|
||||
Column,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
DataType,
|
||||
ForeignKey,
|
||||
HasMany,
|
||||
IsUUID,
|
||||
Length,
|
||||
Model,
|
||||
PrimaryKey,
|
||||
AutoIncrement
|
||||
} from "sequelize-typescript"
|
||||
Sequelize,
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript';
|
||||
|
||||
import { GuaribasSubject } from "../../kb.gbapp/models"
|
||||
import { GuaribasUser } from "../../security.gblib/models"
|
||||
import { GuaribasChannel, GuaribasInstance } from "../../core.gbapp/models/GBModel"
|
||||
import { GuaribasChannel, GuaribasInstance } from '../../core.gbapp/models/GBModel';
|
||||
import { GuaribasSubject } from '../../kb.gbapp/models';
|
||||
import { GuaribasUser } from '../../security.gblib/models';
|
||||
|
||||
@Table
|
||||
export class GuaribasConversation extends Model<GuaribasConversation> {
|
||||
|
@ -71,40 +71,40 @@ export class GuaribasConversation extends Model<GuaribasConversation> {
|
|||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
conversationId: number
|
||||
public conversationId: number;
|
||||
|
||||
@ForeignKey(() => GuaribasSubject)
|
||||
@Column
|
||||
startSubjectId: number
|
||||
public startSubjectId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasSubject)
|
||||
startSubject: GuaribasSubject
|
||||
public startSubject: GuaribasSubject;
|
||||
|
||||
@ForeignKey(() => GuaribasChannel)
|
||||
@Column
|
||||
channelId: string
|
||||
public channelId: string;
|
||||
|
||||
@Column rateDate: Date
|
||||
@Column public rateDate: Date;
|
||||
|
||||
@Column(DataType.FLOAT)
|
||||
@Column
|
||||
rate: number
|
||||
public rate: number;
|
||||
|
||||
@Column
|
||||
@CreatedAt
|
||||
createdAt: Date
|
||||
public createdAt: Date;
|
||||
|
||||
@Column text: string
|
||||
@Column public text: string;
|
||||
|
||||
@HasMany(() => GuaribasConversationMessage)
|
||||
conversationMessage: GuaribasConversationMessage[]
|
||||
public conversationMessage: GuaribasConversationMessage[];
|
||||
|
||||
@ForeignKey(() => GuaribasUser)
|
||||
@Column
|
||||
startedByUserId: number
|
||||
public startedByUserId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasUser)
|
||||
startedBy: GuaribasUser
|
||||
public startedBy: GuaribasUser;
|
||||
}
|
||||
|
||||
@Table
|
||||
|
@ -113,38 +113,38 @@ export class GuaribasConversationMessage extends Model<GuaribasConversationMessa
|
|||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
conversationMessageId: number
|
||||
public conversationMessageId: number;
|
||||
|
||||
@ForeignKey(() => GuaribasSubject)
|
||||
@Column
|
||||
subjectId: number
|
||||
public subjectId: number;
|
||||
|
||||
@Column(DataType.TEXT)
|
||||
content: string
|
||||
public content: string;
|
||||
|
||||
@Column
|
||||
@CreatedAt
|
||||
createdAt: Date
|
||||
public createdAt: Date;
|
||||
|
||||
@Column
|
||||
@UpdatedAt
|
||||
updatedAt: Date
|
||||
public updatedAt: Date;
|
||||
|
||||
@ForeignKey(() => GuaribasConversation)
|
||||
@Column
|
||||
conversationId: number
|
||||
public conversationId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasConversation)
|
||||
conversation: GuaribasConversation
|
||||
public conversation: GuaribasConversation;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column
|
||||
instanceId: number
|
||||
public instanceId: number;
|
||||
|
||||
@ForeignKey(() => GuaribasUser)
|
||||
@Column
|
||||
userId: number
|
||||
public userId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasUser)
|
||||
user: GuaribasUser
|
||||
public user: GuaribasUser;
|
||||
}
|
||||
|
|
|
@ -34,38 +34,38 @@
|
|||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
import { GuaribasUser } from "../../security.gblib/models"
|
||||
import { GuaribasConversation, GuaribasConversationMessage } from "../models"
|
||||
import { GuaribasUser } from '../../security.gblib/models';
|
||||
import { GuaribasConversation, GuaribasConversationMessage } from '../models';
|
||||
|
||||
export class AnalyticsService {
|
||||
async createConversation(
|
||||
public async createConversation(
|
||||
user: GuaribasUser
|
||||
): Promise<GuaribasConversation> {
|
||||
return new Promise<GuaribasConversation>(
|
||||
(resolve, reject) => {
|
||||
let conversation = new GuaribasConversation()
|
||||
conversation.startedBy = user
|
||||
conversation.startedByUserId = user.userId
|
||||
const conversation = new GuaribasConversation();
|
||||
conversation.startedBy = user;
|
||||
conversation.startedByUserId = user.userId;
|
||||
conversation.save().then((value: GuaribasConversation) => {
|
||||
resolve(value)
|
||||
})
|
||||
})
|
||||
resolve(value);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
createMessage(
|
||||
public createMessage(
|
||||
conversation: GuaribasConversation,
|
||||
user: GuaribasUser,
|
||||
content: string
|
||||
): Promise<GuaribasConversationMessage> {
|
||||
return new Promise<GuaribasConversationMessage>(
|
||||
(resolve, reject) => {
|
||||
let message = GuaribasConversationMessage.build()
|
||||
message.conversation = conversation
|
||||
message.user = user
|
||||
message.content = content
|
||||
const message = GuaribasConversationMessage.build();
|
||||
message.conversation = conversation;
|
||||
message.user = user;
|
||||
message.content = content;
|
||||
message.save().then((value: GuaribasConversationMessage) => {
|
||||
resolve(value)
|
||||
})
|
||||
})
|
||||
resolve(value);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,13 +57,13 @@ export class BotFarmDialog extends IGBDialog {
|
|||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'5'
|
||||
]);
|
||||
},
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
await step.context.sendActivity(Messages[locale].thanks);
|
||||
},
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,8 @@
|
|||
export const Messages = {
|
||||
"en-US": {
|
||||
about_suggestions: "Suggestions are welcomed and improve my quality...",
|
||||
'en-US': {
|
||||
about_suggestions: 'Suggestions are welcomed and improve my quality...'
|
||||
},
|
||||
"pt-BR": {
|
||||
about_suggestions: "Sugestões melhoram muito minha qualidade...",
|
||||
'pt-BR': {
|
||||
about_suggestions: 'Sugestões melhoram muito minha qualidade...'
|
||||
}
|
||||
};
|
||||
|
|
|
@ -34,32 +34,32 @@
|
|||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
const UrlJoin = require("url-join")
|
||||
const UrlJoin = require('url-join');
|
||||
|
||||
import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"
|
||||
import { GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
|
||||
|
||||
import { Sequelize } from 'sequelize-typescript'
|
||||
import { ConsoleDirectLine } from "./services/ConsoleDirectLine"
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
import { ConsoleDirectLine } from './services/ConsoleDirectLine';
|
||||
|
||||
export class GBConsolePackage implements IGBPackage {
|
||||
sysPackages: IGBPackage[] = null
|
||||
channel: ConsoleDirectLine
|
||||
public sysPackages: IGBPackage[] = null;
|
||||
public channel: ConsoleDirectLine;
|
||||
|
||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
}
|
||||
|
||||
unloadPackage(core: IGBCoreService): void {
|
||||
public unloadPackage(core: IGBCoreService): void {
|
||||
}
|
||||
|
||||
loadBot(min: GBMinInstance): void {
|
||||
this.channel = new ConsoleDirectLine(min.instance.webchatKey)
|
||||
public loadBot(min: GBMinInstance): void {
|
||||
this.channel = new ConsoleDirectLine(min.instance.webchatKey);
|
||||
}
|
||||
|
||||
unloadBot(min: GBMinInstance): void {
|
||||
public unloadBot(min: GBMinInstance): void {
|
||||
}
|
||||
|
||||
onNewSession(min: GBMinInstance, step: any): void {
|
||||
public onNewSession(min: GBMinInstance, step: any): void {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,76 +30,75 @@
|
|||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
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 Swagger = require('swagger-client')
|
||||
const rp = require('request-promise')
|
||||
import { GBService } from "botlib"
|
||||
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 Swagger = require('swagger-client');
|
||||
const rp = require('request-promise');
|
||||
import { GBService } from 'botlib';
|
||||
|
||||
export class ConsoleDirectLine extends GBService {
|
||||
|
||||
pollInterval = 1000
|
||||
directLineSecret = ''
|
||||
directLineClientName = 'DirectLineClient'
|
||||
directLineSpecUrl = 'https://docs.botframework.com/en-us/restapi/directline3/swagger.json'
|
||||
public pollInterval = 1000;
|
||||
public directLineSecret = '';
|
||||
public directLineClientName = 'DirectLineClient';
|
||||
public directLineSpecUrl = 'https://docs.botframework.com/en-us/restapi/directline3/swagger.json';
|
||||
|
||||
constructor(directLineSecret) {
|
||||
super()
|
||||
|
||||
this.directLineSecret = directLineSecret
|
||||
super();
|
||||
|
||||
this.directLineSecret = directLineSecret;
|
||||
|
||||
// TODO: Migrate to Swagger 3.
|
||||
let directLineClient = rp(this.directLineSpecUrl)
|
||||
const directLineClient = rp(this.directLineSpecUrl)
|
||||
.then(function (spec) {
|
||||
return new Swagger({
|
||||
spec: JSON.parse(spec.trim()),
|
||||
usePromise: true
|
||||
})
|
||||
});
|
||||
})
|
||||
.then(function (client) {
|
||||
client.clientAuthorizations.add('AuthorizationBotConnector',
|
||||
new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' + directLineSecret, 'header'))
|
||||
return client
|
||||
new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' + directLineSecret, 'header'));
|
||||
return client;
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error('Error initializing DirectLine client', err)
|
||||
})
|
||||
console.error('Error initializing DirectLine client', err);
|
||||
});
|
||||
|
||||
// TODO: Remove *this* issue.
|
||||
let _this_ = this
|
||||
directLineClient.then((client)=> {
|
||||
const _this_ = this;
|
||||
directLineClient.then((client) => {
|
||||
client.Conversations.Conversations_StartConversation()
|
||||
.then(function (response) {
|
||||
return response.obj.conversationId
|
||||
return response.obj.conversationId;
|
||||
})
|
||||
.then(function (conversationId) {
|
||||
_this_.sendMessagesFromConsole(client, conversationId)
|
||||
_this_.pollMessages(client, conversationId)
|
||||
_this_.sendMessagesFromConsole(client, conversationId);
|
||||
_this_.pollMessages(client, conversationId);
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error('Error starting conversation', err)
|
||||
})
|
||||
})
|
||||
console.error('Error starting conversation', err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
sendMessagesFromConsole(client, conversationId) {
|
||||
let _this_ = this
|
||||
process.stdin.resume()
|
||||
var stdin = process.stdin
|
||||
process.stdout.write('Command> ')
|
||||
public sendMessagesFromConsole(client, conversationId) {
|
||||
const _this_ = this;
|
||||
process.stdin.resume();
|
||||
const stdin = process.stdin;
|
||||
process.stdout.write('Command> ');
|
||||
stdin.addListener('data', function (e) {
|
||||
var input = e.toString().trim()
|
||||
const input = e.toString().trim();
|
||||
if (input) {
|
||||
// exit
|
||||
if (input.toLowerCase() === 'exit') {
|
||||
return process.exit()
|
||||
return process.exit();
|
||||
}
|
||||
|
||||
client.Conversations.Conversations_PostActivity(
|
||||
|
@ -115,80 +114,80 @@ export class ConsoleDirectLine extends GBService {
|
|||
}
|
||||
}
|
||||
}).catch(function (err) {
|
||||
console.error('Error sending message:', err)
|
||||
})
|
||||
console.error('Error sending message:', err);
|
||||
});
|
||||
|
||||
process.stdout.write('Command> ')
|
||||
process.stdout.write('Command> ');
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/** TBD: Poll Messages from conversation using DirectLine client */
|
||||
pollMessages(client, conversationId) {
|
||||
let _this_ = this
|
||||
console.log('Starting polling message for conversationId: ' + conversationId)
|
||||
var watermark = null
|
||||
public pollMessages(client, conversationId) {
|
||||
const _this_ = this;
|
||||
console.log('Starting polling message for conversationId: ' + conversationId);
|
||||
let watermark = null;
|
||||
setInterval(function () {
|
||||
client.Conversations.Conversations_GetActivities({ conversationId: conversationId, watermark: watermark })
|
||||
.then(function (response) {
|
||||
watermark = response.obj.watermark // use watermark so subsequent requests skip old messages
|
||||
return response.obj.activities
|
||||
watermark = response.obj.watermark; // use watermark so subsequent requests skip old messages
|
||||
return response.obj.activities;
|
||||
})
|
||||
.then(_this_.printMessages, _this_.directLineClientName)
|
||||
}, this.pollInterval)
|
||||
.then(_this_.printMessages, _this_.directLineClientName);
|
||||
}, this.pollInterval);
|
||||
}
|
||||
|
||||
printMessages(activities, directLineClientName) {
|
||||
public printMessages(activities, directLineClientName) {
|
||||
|
||||
if (activities && activities.length) {
|
||||
// ignore own messages
|
||||
activities = activities.filter(function (m) { return m.from.id !== directLineClientName })
|
||||
activities = activities.filter(function (m) { return m.from.id !== directLineClientName; });
|
||||
|
||||
if (activities.length) {
|
||||
|
||||
// print other messages
|
||||
activities.forEach(activity => {
|
||||
console.log(activity.text)
|
||||
}, this)
|
||||
console.log(activity.text);
|
||||
}, this);
|
||||
|
||||
process.stdout.write('Command> ')
|
||||
process.stdout.write('Command> ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printMessage(activity) {
|
||||
public printMessage(activity) {
|
||||
if (activity.text) {
|
||||
console.log(activity.text)
|
||||
console.log(activity.text);
|
||||
}
|
||||
|
||||
if (activity.attachments) {
|
||||
activity.attachments.forEach(function (attachment) {
|
||||
switch (attachment.contentType) {
|
||||
case "application/vnd.microsoft.card.hero":
|
||||
this.renderHeroCard(attachment)
|
||||
break
|
||||
case 'application/vnd.microsoft.card.hero':
|
||||
this.renderHeroCard(attachment);
|
||||
break;
|
||||
|
||||
case "image/png":
|
||||
console.log('Opening the requested image ' + attachment.contentUrl)
|
||||
open(attachment.contentUrl)
|
||||
break
|
||||
case 'image/png':
|
||||
console.log('Opening the requested image ' + attachment.contentUrl);
|
||||
open(attachment.contentUrl);
|
||||
break;
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
renderHeroCard(attachment) {
|
||||
var width = 70
|
||||
var contentLine = function (content) {
|
||||
public renderHeroCard(attachment) {
|
||||
const width = 70;
|
||||
const contentLine = function (content) {
|
||||
return ' '.repeat((width - content.length) / 2) +
|
||||
content +
|
||||
' '.repeat((width - content.length) / 2)
|
||||
}
|
||||
' '.repeat((width - content.length) / 2);
|
||||
};
|
||||
|
||||
console.log('/' + '*'.repeat(width + 1))
|
||||
console.log('*' + contentLine(attachment.content.title) + '*')
|
||||
console.log('*' + ' '.repeat(width) + '*')
|
||||
console.log('*' + contentLine(attachment.content.text) + '*')
|
||||
console.log('*'.repeat(width + 1) + '/')
|
||||
console.log('/' + '*'.repeat(width + 1));
|
||||
console.log('*' + contentLine(attachment.content.title) + '*');
|
||||
console.log('*' + ' '.repeat(width) + '*');
|
||||
console.log('*' + contentLine(attachment.content.text) + '*');
|
||||
console.log('*'.repeat(width + 1) + '/');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,11 +36,11 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import { IGBDialog } from "botlib";
|
||||
import { GBMinInstance } from "botlib";
|
||||
import { BotAdapter } from "botbuilder";
|
||||
import {WaterfallDialog } from "botbuilder-dialogs";
|
||||
import { Messages } from "../strings";
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import {WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { IGBDialog } from 'botlib';
|
||||
import { GBMinInstance } from 'botlib';
|
||||
import { Messages } from '../strings';
|
||||
|
||||
export class WelcomeDialog extends IGBDialog {
|
||||
/**
|
||||
|
@ -49,20 +49,20 @@ export class WelcomeDialog extends IGBDialog {
|
|||
* @param bot The bot adapter.
|
||||
* @param min The minimal bot instance data.
|
||||
*/
|
||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
|
||||
min.dialogs.add(new WaterfallDialog('/', [
|
||||
async step => {
|
||||
|
||||
min.dialogs.add(new WaterfallDialog("/", [
|
||||
async step => {
|
||||
|
||||
const user = await min.userProfile.get(context, {});
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
if (!user.once) {
|
||||
user.once = true;
|
||||
await min.userProfile.set(step.context, user);
|
||||
var a = new Date();
|
||||
const a = new Date();
|
||||
const date = a.getHours();
|
||||
var msg =
|
||||
const msg =
|
||||
date < 12
|
||||
? Messages[locale].good_morning
|
||||
: date < 18
|
||||
|
@ -70,18 +70,18 @@ export class WelcomeDialog extends IGBDialog {
|
|||
: Messages[locale].good_night;
|
||||
|
||||
await step.context.sendActivity(Messages[locale].hi(msg));
|
||||
await step.replaceDialog("/ask", { firstTime: true });
|
||||
await step.replaceDialog('/ask', { firstTime: true });
|
||||
|
||||
if (
|
||||
step.context.activity &&
|
||||
step.context.activity.type == "message" &&
|
||||
step.context.activity.text != ""
|
||||
step.context.activity.type == 'message' &&
|
||||
step.context.activity.text != ''
|
||||
) {
|
||||
await step.replaceDialog("/answer", { query: step.context.activity.text });
|
||||
await step.replaceDialog('/answer', { query: step.context.activity.text });
|
||||
}
|
||||
}
|
||||
return await step.next();
|
||||
}
|
||||
]))
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,11 +36,11 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import { IGBDialog } from "botlib";
|
||||
import { GBMinInstance } from "botlib";
|
||||
import { BotAdapter } from "botbuilder";
|
||||
import { Messages } from "../strings";
|
||||
import { WaterfallDialog } from "botbuilder-dialogs";
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { IGBDialog } from 'botlib';
|
||||
import { GBMinInstance } from 'botlib';
|
||||
import { Messages } from '../strings';
|
||||
|
||||
export class WhoAmIDialog extends IGBDialog {
|
||||
/**
|
||||
|
@ -49,21 +49,21 @@ export class WhoAmIDialog extends IGBDialog {
|
|||
* @param bot The bot adapter.
|
||||
* @param min The minimal bot instance data.
|
||||
*/
|
||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
min.dialogs.add(new WaterfallDialog("/whoAmI", [
|
||||
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
min.dialogs.add(new WaterfallDialog('/whoAmI', [
|
||||
async step => {
|
||||
let locale = step.context.activity.locale;
|
||||
const locale = step.context.activity.locale;
|
||||
await step.context.sendActivity(`${min.instance.description}`);
|
||||
|
||||
if (min.instance.whoAmIVideo) {
|
||||
await step.context.sendActivity(Messages[locale].show_video);
|
||||
await min.conversationalService.sendEvent(step, "play", {
|
||||
playerType: "video",
|
||||
await min.conversationalService.sendEvent(step, 'play', {
|
||||
playerType: 'video',
|
||||
data: min.instance.whoAmIVideo.trim()
|
||||
});
|
||||
}
|
||||
|
||||
await step.replaceDialog("/ask", { isReturning: true });
|
||||
await step.replaceDialog('/ask', { isReturning: true });
|
||||
return await step.next();
|
||||
}
|
||||
]));
|
||||
|
|
|
@ -34,44 +34,44 @@
|
|||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
const UrlJoin = require("url-join")
|
||||
const UrlJoin = require('url-join');
|
||||
|
||||
import { GBMinInstance, IGBPackage } from "botlib"
|
||||
import { GBMinInstance, IGBPackage } from 'botlib';
|
||||
|
||||
import { WelcomeDialog } from "./dialogs/WelcomeDialog"
|
||||
import { WhoAmIDialog } from "./dialogs/WhoAmIDialog"
|
||||
import { IGBCoreService} from "botlib"
|
||||
import { Sequelize } from "sequelize-typescript"
|
||||
import { GuaribasInstance, GuaribasException, GuaribasPackage, GuaribasChannel } from "./models/GBModel"
|
||||
import { IGBCoreService} from 'botlib';
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
import { WelcomeDialog } from './dialogs/WelcomeDialog';
|
||||
import { WhoAmIDialog } from './dialogs/WhoAmIDialog';
|
||||
import { GuaribasChannel, GuaribasException, GuaribasInstance, GuaribasPackage } from './models/GBModel';
|
||||
|
||||
export class GBCorePackage implements IGBPackage {
|
||||
sysPackages: IGBPackage[] = null
|
||||
public static CurrentEngineName = "guaribas-1.0.0";
|
||||
|
||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
public static CurrentEngineName = 'guaribas-1.0.0';
|
||||
public sysPackages: IGBPackage[] = null;
|
||||
|
||||
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
core.sequelize.addModels([
|
||||
GuaribasInstance,
|
||||
GuaribasPackage,
|
||||
GuaribasChannel,
|
||||
GuaribasException,
|
||||
])
|
||||
GuaribasException
|
||||
]);
|
||||
}
|
||||
|
||||
unloadPackage(core: IGBCoreService): void {
|
||||
|
||||
public unloadPackage(core: IGBCoreService): void {
|
||||
|
||||
}
|
||||
|
||||
loadBot(min: GBMinInstance): void {
|
||||
WelcomeDialog.setup(min.bot, min)
|
||||
WhoAmIDialog.setup(min.bot, min)
|
||||
public loadBot(min: GBMinInstance): void {
|
||||
WelcomeDialog.setup(min.bot, min);
|
||||
WhoAmIDialog.setup(min.bot, min);
|
||||
}
|
||||
|
||||
unloadBot(min: GBMinInstance): void {
|
||||
|
||||
public unloadBot(min: GBMinInstance): void {
|
||||
|
||||
}
|
||||
onNewSession(min: GBMinInstance, step: any): void {
|
||||
|
||||
public onNewSession(min: GBMinInstance, step: any): void {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,21 +36,20 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
|
||||
import {
|
||||
Table,
|
||||
Column,
|
||||
Model,
|
||||
AutoIncrement,
|
||||
BelongsTo,
|
||||
ForeignKey,
|
||||
Column,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
DataType,
|
||||
ForeignKey,
|
||||
Model,
|
||||
PrimaryKey,
|
||||
AutoIncrement
|
||||
} from "sequelize-typescript";
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript';
|
||||
|
||||
import { IGBInstance } from "botlib";
|
||||
import { IGBInstance } from 'botlib';
|
||||
|
||||
@Table
|
||||
export class GuaribasInstance extends Model<GuaribasInstance>
|
||||
|
@ -58,185 +57,185 @@ export class GuaribasInstance extends Model<GuaribasInstance>
|
|||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
instanceId: number;
|
||||
public instanceId: number;
|
||||
|
||||
@Column
|
||||
botEndpoint: string;
|
||||
public botEndpoint: string;
|
||||
|
||||
@Column
|
||||
whoAmIVideo: string;
|
||||
public whoAmIVideo: string;
|
||||
|
||||
@Column
|
||||
botId: string;
|
||||
public botId: string;
|
||||
|
||||
@Column
|
||||
title: string;
|
||||
public title: string;
|
||||
|
||||
@Column
|
||||
description: string;
|
||||
public description: string;
|
||||
|
||||
@Column
|
||||
version: string;
|
||||
public version: string;
|
||||
|
||||
@Column
|
||||
enabledAdmin: boolean;
|
||||
public enabledAdmin: boolean;
|
||||
|
||||
/* Services section on bot.json */
|
||||
|
||||
@Column
|
||||
engineName: string;
|
||||
public engineName: string;
|
||||
|
||||
@Column
|
||||
marketplaceId: string;
|
||||
public marketplaceId: string;
|
||||
|
||||
@Column
|
||||
textAnalyticsKey: string;
|
||||
public textAnalyticsKey: string;
|
||||
|
||||
@Column
|
||||
textAnalyticsEndpoint: string;
|
||||
public textAnalyticsEndpoint: string;
|
||||
|
||||
@Column
|
||||
marketplacePassword: string;
|
||||
public marketplacePassword: string;
|
||||
|
||||
@Column
|
||||
webchatKey: string;
|
||||
public webchatKey: string;
|
||||
|
||||
@Column
|
||||
authenticatorTenant: string;
|
||||
public authenticatorTenant: string;
|
||||
|
||||
@Column
|
||||
authenticatorAuthorityHostUrl: string;
|
||||
public authenticatorAuthorityHostUrl: string;
|
||||
|
||||
@Column
|
||||
authenticatorClientId: string;
|
||||
public authenticatorClientId: string;
|
||||
|
||||
@Column
|
||||
authenticatorClientSecret: string;
|
||||
public authenticatorClientSecret: string;
|
||||
|
||||
@Column
|
||||
cloudSubscriptionId: string;
|
||||
|
||||
@Column
|
||||
cloudUsername: string;
|
||||
public cloudSubscriptionId: string;
|
||||
|
||||
@Column
|
||||
cloudPassword: string;
|
||||
public cloudUsername: string;
|
||||
|
||||
@Column
|
||||
cloudLocation: string;
|
||||
public cloudPassword: string;
|
||||
|
||||
@Column
|
||||
whatsappBotKey: string;
|
||||
public cloudLocation: string;
|
||||
|
||||
@Column
|
||||
whatsappServiceKey: string;
|
||||
public whatsappBotKey: string;
|
||||
|
||||
@Column
|
||||
whatsappServiceNumber: string;
|
||||
public whatsappServiceKey: string;
|
||||
|
||||
@Column
|
||||
whatsappServiceUrl: string;
|
||||
public whatsappServiceNumber: string;
|
||||
|
||||
@Column
|
||||
whatsappServiceWebhookUrl: string;
|
||||
public whatsappServiceUrl: string;
|
||||
|
||||
@Column
|
||||
smsKey: string;
|
||||
public whatsappServiceWebhookUrl: string;
|
||||
|
||||
@Column
|
||||
smsSecret: string;
|
||||
public smsKey: string;
|
||||
|
||||
@Column
|
||||
smsServiceNumber: string;
|
||||
public smsSecret: string;
|
||||
|
||||
@Column
|
||||
speechKey: string;
|
||||
public smsServiceNumber: string;
|
||||
|
||||
@Column
|
||||
speechKeyEndpoint: string;
|
||||
public speechKey: string;
|
||||
|
||||
@Column
|
||||
spellcheckerKey: string;
|
||||
public speechKeyEndpoint: string;
|
||||
|
||||
@Column
|
||||
spellcheckerEndpoint: string;
|
||||
public spellcheckerKey: string;
|
||||
|
||||
@Column
|
||||
theme: string;
|
||||
public spellcheckerEndpoint: string;
|
||||
|
||||
@Column
|
||||
ui: string;
|
||||
public theme: string;
|
||||
|
||||
@Column
|
||||
kb: string;
|
||||
public ui: string;
|
||||
|
||||
@Column
|
||||
nlpAppId: string;
|
||||
public kb: string;
|
||||
|
||||
@Column
|
||||
nlpKey: string;
|
||||
public nlpAppId: string;
|
||||
|
||||
@Column
|
||||
public nlpKey: string;
|
||||
|
||||
@Column
|
||||
@Column({ type: DataType.STRING(512) })
|
||||
nlpEndpoint: string;
|
||||
public nlpEndpoint: string;
|
||||
|
||||
@Column
|
||||
nlpAuthoringKey: string;
|
||||
|
||||
@Column
|
||||
deploymentPaths: string;
|
||||
public nlpAuthoringKey: string;
|
||||
|
||||
@Column
|
||||
searchHost: string;
|
||||
public deploymentPaths: string;
|
||||
|
||||
@Column
|
||||
searchKey: string;
|
||||
public searchHost: string;
|
||||
|
||||
@Column
|
||||
searchIndex: string;
|
||||
public searchKey: string;
|
||||
|
||||
@Column
|
||||
searchIndexer: string;
|
||||
public searchIndex: string;
|
||||
|
||||
@Column
|
||||
storageUsername: string;
|
||||
public searchIndexer: string;
|
||||
|
||||
@Column
|
||||
storagePassword: string;
|
||||
public storageUsername: string;
|
||||
|
||||
@Column
|
||||
storageName: string;
|
||||
public storagePassword: string;
|
||||
|
||||
@Column
|
||||
storageServer: string;
|
||||
public storageName: string;
|
||||
|
||||
@Column
|
||||
storageDialect: string;
|
||||
public storageServer: string;
|
||||
|
||||
@Column
|
||||
storagePath: string;
|
||||
public storageDialect: string;
|
||||
|
||||
@Column
|
||||
adminPass: string;
|
||||
public storagePath: string;
|
||||
|
||||
@Column
|
||||
public adminPass: string;
|
||||
|
||||
/* Settings section of bot.json */
|
||||
|
||||
@Column(DataType.FLOAT)
|
||||
nlpVsSearch: number;
|
||||
public nlpVsSearch: number;
|
||||
|
||||
@Column(DataType.FLOAT)
|
||||
searchScore: number;
|
||||
public searchScore: number;
|
||||
|
||||
@Column(DataType.FLOAT)
|
||||
nlpScore: number;
|
||||
public nlpScore: number;
|
||||
|
||||
@Column
|
||||
@CreatedAt
|
||||
createdAt: Date;
|
||||
public createdAt: Date;
|
||||
|
||||
@Column
|
||||
@UpdatedAt
|
||||
updatedAt: Date;
|
||||
public updatedAt: Date;
|
||||
}
|
||||
|
||||
@Table
|
||||
|
@ -244,25 +243,25 @@ export class GuaribasPackage extends Model<GuaribasPackage> {
|
|||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
packageId: number;
|
||||
public packageId: number;
|
||||
|
||||
@Column
|
||||
packageName: string;
|
||||
public packageName: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column
|
||||
instanceId: number;
|
||||
public instanceId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasInstance)
|
||||
instance: GuaribasInstance;
|
||||
public instance: GuaribasInstance;
|
||||
|
||||
@Column
|
||||
@CreatedAt
|
||||
createdAt: Date;
|
||||
public createdAt: Date;
|
||||
|
||||
@Column
|
||||
@UpdatedAt
|
||||
updatedAt: Date;
|
||||
public updatedAt: Date;
|
||||
}
|
||||
|
||||
@Table
|
||||
|
@ -270,18 +269,18 @@ export class GuaribasChannel extends Model<GuaribasChannel> {
|
|||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
channelId: number;
|
||||
public channelId: number;
|
||||
|
||||
@Column
|
||||
title: string;
|
||||
public title: string;
|
||||
|
||||
@Column
|
||||
@CreatedAt
|
||||
createdAt: Date;
|
||||
public createdAt: Date;
|
||||
|
||||
@Column
|
||||
@UpdatedAt
|
||||
updatedAt: Date;
|
||||
public updatedAt: Date;
|
||||
}
|
||||
|
||||
@Table
|
||||
|
@ -289,23 +288,23 @@ export class GuaribasException extends Model<GuaribasException> {
|
|||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
exceptionId: number;
|
||||
public exceptionId: number;
|
||||
|
||||
@Column
|
||||
message: string;
|
||||
public message: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column
|
||||
instanceId: number;
|
||||
public instanceId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasInstance)
|
||||
instance: GuaribasInstance;
|
||||
public instance: GuaribasInstance;
|
||||
|
||||
@Column
|
||||
@CreatedAt
|
||||
createdAt: Date;
|
||||
public createdAt: Date;
|
||||
|
||||
@Column
|
||||
@UpdatedAt
|
||||
updatedAt: Date;
|
||||
public updatedAt: Date;
|
||||
}
|
||||
|
|
|
@ -30,20 +30,20 @@
|
|||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
const logger = require("../../../src/logger");
|
||||
import * as fs from "fs";
|
||||
const logger = require('../../../src/logger');
|
||||
import * as fs from 'fs';
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
export class GBConfigService {
|
||||
static init(): any {
|
||||
public static init(): any {
|
||||
try {
|
||||
require("dotenv-extended").load({
|
||||
path: ".env",
|
||||
require('dotenv-extended').load({
|
||||
path: '.env',
|
||||
errorOnMissing: true,
|
||||
errorOnExtra: false,
|
||||
overrideProcessEnv: true
|
||||
|
@ -54,52 +54,52 @@ export class GBConfigService {
|
|||
}
|
||||
}
|
||||
|
||||
static get(key: string): string | undefined {
|
||||
public static get(key: string): string | undefined {
|
||||
let value = GBConfigService.tryGet(key);
|
||||
|
||||
if (!value) {
|
||||
switch (key) {
|
||||
case "CLOUD_USERNAME":
|
||||
case 'CLOUD_USERNAME':
|
||||
value = undefined;
|
||||
break;
|
||||
case "BOT_ID":
|
||||
case 'BOT_ID':
|
||||
value = undefined;
|
||||
break;
|
||||
case "CLOUD_PASSWORD":
|
||||
case 'CLOUD_PASSWORD':
|
||||
value = undefined;
|
||||
break;
|
||||
case "CLOUD_SUBSCRIPTIONID":
|
||||
case 'CLOUD_SUBSCRIPTIONID':
|
||||
value = undefined;
|
||||
break;
|
||||
case "CLOUD_LOCATION":
|
||||
case 'CLOUD_LOCATION':
|
||||
value = undefined;
|
||||
break;
|
||||
case "NLP_AUTHORING_KEY":
|
||||
case 'NLP_AUTHORING_KEY':
|
||||
value = undefined;
|
||||
break;
|
||||
case "STORAGE_DIALECT":
|
||||
case 'STORAGE_DIALECT':
|
||||
value = undefined;
|
||||
break;
|
||||
case "STORAGE_STORAGE":
|
||||
value = "./guaribas.sqlite";
|
||||
case 'STORAGE_STORAGE':
|
||||
value = './guaribas.sqlite';
|
||||
break;
|
||||
case "ADDITIONAL_DEPLOY_PATH":
|
||||
case 'ADDITIONAL_DEPLOY_PATH':
|
||||
value = undefined;
|
||||
break;
|
||||
case "STORAGE_SYNC":
|
||||
value = "false";
|
||||
case 'STORAGE_SYNC':
|
||||
value = 'false';
|
||||
break;
|
||||
case "STORAGE_SYNC_ALTER":
|
||||
value = "false";
|
||||
case 'STORAGE_SYNC_ALTER':
|
||||
value = 'false';
|
||||
break;
|
||||
case "STORAGE_SYNC_FORCE":
|
||||
value = "false";
|
||||
case 'STORAGE_SYNC_FORCE':
|
||||
value = 'false';
|
||||
break;
|
||||
case "STORAGE_LOGGING":
|
||||
value = "false";
|
||||
case 'STORAGE_LOGGING':
|
||||
value = 'false';
|
||||
break;
|
||||
case "STORAGE_ENCRYPT":
|
||||
value = "true";
|
||||
case 'STORAGE_ENCRYPT':
|
||||
value = 'true';
|
||||
break;
|
||||
default:
|
||||
logger.warn(`Invalid key on .env file: '${key}'`);
|
||||
|
@ -110,7 +110,7 @@ export class GBConfigService {
|
|||
}
|
||||
|
||||
public static tryGet(key: string) {
|
||||
let value = process.env["container:" + key];
|
||||
let value = process.env['container:' + key];
|
||||
if (!value) {
|
||||
value = process.env[key];
|
||||
}
|
||||
|
|
|
@ -36,17 +36,17 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const logger = require("../../../src/logger");
|
||||
const logger = require('../../../src/logger');
|
||||
|
||||
import { GBCoreService } from "./GBCoreService";
|
||||
import { IGBConversationalService } from "botlib";
|
||||
import { GBMinInstance } from "botlib";
|
||||
import { LuisRecognizer } from "botbuilder-ai";
|
||||
import { MessageFactory } from "botbuilder";
|
||||
import { Messages } from "../strings";
|
||||
import { AzureText } from "pragmatismo-io-framework";
|
||||
import { any } from "bluebird";
|
||||
const Nexmo = require("nexmo");
|
||||
import { any } from 'bluebird';
|
||||
import { MessageFactory } from 'botbuilder';
|
||||
import { LuisRecognizer } from 'botbuilder-ai';
|
||||
import { IGBConversationalService } from 'botlib';
|
||||
import { GBMinInstance } from 'botlib';
|
||||
import { AzureText } from 'pragmatismo-io-framework';
|
||||
import { Messages } from '../strings';
|
||||
import { GBCoreService } from './GBCoreService';
|
||||
const Nexmo = require('nexmo');
|
||||
|
||||
export interface LanguagePickerSettings {
|
||||
defaultLocale?: string;
|
||||
|
@ -54,27 +54,27 @@ export interface LanguagePickerSettings {
|
|||
}
|
||||
|
||||
export class GBConversationalService implements IGBConversationalService {
|
||||
coreService: GBCoreService;
|
||||
public coreService: GBCoreService;
|
||||
|
||||
constructor(coreService: GBCoreService) {
|
||||
this.coreService = coreService;
|
||||
}
|
||||
|
||||
getCurrentLanguage(step: any) {
|
||||
public getCurrentLanguage(step: any) {
|
||||
return step.context.activity.locale;
|
||||
}
|
||||
|
||||
async sendEvent(step: any, name: string, value: any): Promise<any> {
|
||||
if (step.context.activity.channelId === "webchat") {
|
||||
const msg = MessageFactory.text("");
|
||||
public async sendEvent(step: any, name: string, value: any): Promise<any> {
|
||||
if (step.context.activity.channelId === 'webchat') {
|
||||
const msg = MessageFactory.text('');
|
||||
msg.value = value;
|
||||
msg.type = "event";
|
||||
msg.type = 'event';
|
||||
msg.name = name;
|
||||
return step.context.sendActivity(msg);
|
||||
}
|
||||
}
|
||||
|
||||
async sendSms(
|
||||
public async sendSms(
|
||||
min: GBMinInstance,
|
||||
mobile: string,
|
||||
text: string
|
||||
|
@ -99,7 +99,7 @@ export class GBConversationalService implements IGBConversationalService {
|
|||
});
|
||||
}
|
||||
|
||||
async routeNLP(step: any, min: GBMinInstance, text: string): Promise<boolean> {
|
||||
public async routeNLP(step: any, min: GBMinInstance, text: string): Promise<boolean> {
|
||||
// Invokes LUIS.
|
||||
|
||||
const model = new LuisRecognizer({
|
||||
|
@ -112,39 +112,38 @@ export class GBConversationalService implements IGBConversationalService {
|
|||
try {
|
||||
nlp = await model.recognize(step.context);
|
||||
} catch (error) {
|
||||
if (error.statusCode == 404){
|
||||
logger.warn ('NLP application still not publish and there are no other options for answering.')
|
||||
if (error.statusCode == 404) {
|
||||
logger.warn ('NLP application still not publish and there are no other options for answering.');
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
else{
|
||||
let msg = `Error calling NLP server, check if you have a published model and assigned keys on the service. Error: ${
|
||||
error.statusCode ? error.statusCode : ""
|
||||
} else {
|
||||
const msg = `Error calling NLP server, check if you have a published model and assigned keys on the service. Error: ${
|
||||
error.statusCode ? error.statusCode : ''
|
||||
} ${error.message}`;
|
||||
return Promise.reject(new Error(msg));}
|
||||
return Promise.reject(new Error(msg)); }
|
||||
|
||||
}
|
||||
|
||||
// Resolves intents returned from LUIS.
|
||||
|
||||
let topIntent = LuisRecognizer.topIntent(nlp);
|
||||
const topIntent = LuisRecognizer.topIntent(nlp);
|
||||
if (topIntent) {
|
||||
var intent = topIntent;
|
||||
var entity =
|
||||
const intent = topIntent;
|
||||
const entity =
|
||||
nlp.entities && nlp.entities.length > 0
|
||||
? nlp.entities[0].entity.toUpperCase()
|
||||
: null;
|
||||
|
||||
if (intent === "None") {
|
||||
if (intent === 'None') {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
logger.info("NLP called:" + intent + ", " + entity);
|
||||
logger.info('NLP called:' + intent + ', ' + entity);
|
||||
|
||||
try {
|
||||
await step.replace("/" + intent, nlp.entities);
|
||||
await step.replace('/' + intent, nlp.entities);
|
||||
return Promise.resolve(true);
|
||||
} catch (error) {
|
||||
let msg = `Error finding dialog associated to NLP event: ${intent}: ${
|
||||
const msg = `Error finding dialog associated to NLP event: ${intent}: ${
|
||||
error.message
|
||||
}`;
|
||||
return Promise.reject(new Error(msg));
|
||||
|
@ -153,20 +152,20 @@ export class GBConversationalService implements IGBConversationalService {
|
|||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
async checkLanguage(step, min, text) {
|
||||
let locale = await AzureText.getLocale(
|
||||
public async checkLanguage(step, min, text) {
|
||||
const locale = await AzureText.getLocale(
|
||||
min.instance.textAnalyticsKey,
|
||||
min.instance.textAnalyticsEndpoint,
|
||||
text
|
||||
);
|
||||
if (locale != step.context.activity.locale.split("-")[0]) {
|
||||
if (locale != step.context.activity.locale.split('-')[0]) {
|
||||
switch (locale) {
|
||||
case "pt":
|
||||
step.context.activity.locale = "pt-BR";
|
||||
case 'pt':
|
||||
step.context.activity.locale = 'pt-BR';
|
||||
await step.context.sendActivity(Messages[locale].changing_language);
|
||||
break;
|
||||
case "en":
|
||||
step.context.activity.locale = "en-US";
|
||||
case 'en':
|
||||
step.context.activity.locale = 'en-US';
|
||||
await step.context.sendActivity(Messages[locale].changing_language);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -70,7 +70,7 @@ export class GBCoreService implements IGBCoreService {
|
|||
private createTableQuery: (
|
||||
tableName: string,
|
||||
attributes: any,
|
||||
options: any,
|
||||
options: any
|
||||
) => string;
|
||||
|
||||
/**
|
||||
|
@ -136,15 +136,15 @@ export class GBCoreService implements IGBCoreService {
|
|||
dialect: this.dialect,
|
||||
storage: storage,
|
||||
dialectOptions: {
|
||||
encrypt: encrypt,
|
||||
encrypt: encrypt
|
||||
},
|
||||
pool: {
|
||||
max: 32,
|
||||
min: 8,
|
||||
idle: 40000,
|
||||
evict: 40000,
|
||||
acquire: 40000,
|
||||
},
|
||||
acquire: 40000
|
||||
}
|
||||
});
|
||||
|
||||
if (this.dialect === 'mssql') {
|
||||
|
@ -153,7 +153,7 @@ export class GBCoreService implements IGBCoreService {
|
|||
this.queryGenerator.createTableQuery = (
|
||||
tableName,
|
||||
attributes,
|
||||
options,
|
||||
options
|
||||
) => this.createTableQueryOverride(tableName, attributes, options);
|
||||
this.changeColumnQuery = this.queryGenerator.changeColumnQuery;
|
||||
this.queryGenerator.changeColumnQuery = (tableName, attributes) =>
|
||||
|
@ -163,7 +163,7 @@ export class GBCoreService implements IGBCoreService {
|
|||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,7 @@ export class GBCoreService implements IGBCoreService {
|
|||
logger.info('Syncing database...');
|
||||
return this.sequelize.sync({
|
||||
alter: alter,
|
||||
force: force,
|
||||
force: force
|
||||
});
|
||||
} else {
|
||||
const msg = 'Database synchronization is disabled.';
|
||||
|
@ -257,7 +257,7 @@ export class GBCoreService implements IGBCoreService {
|
|||
let sql: string = this.createTableQuery.apply(this.queryGenerator, [
|
||||
tableName,
|
||||
attributes,
|
||||
options,
|
||||
options
|
||||
]);
|
||||
const re1 = /CREATE\s+TABLE\s+\[([^\]]*)\]/;
|
||||
const matches = re1.exec(sql);
|
||||
|
@ -268,7 +268,7 @@ export class GBCoreService implements IGBCoreService {
|
|||
re2,
|
||||
(match: string, ...args: any[]): string => {
|
||||
return 'CONSTRAINT [' + table + '_pk] ' + match;
|
||||
},
|
||||
}
|
||||
);
|
||||
const re3 = /FOREIGN\s+KEY\s+\((\[[^\]]*\](?:,\s*\[[^\]]*\])*)\)/g;
|
||||
const re4 = /\[([^\]]*)\]/g;
|
||||
|
@ -283,7 +283,7 @@ export class GBCoreService implements IGBCoreService {
|
|||
matches = re4.exec(fkcols);
|
||||
}
|
||||
return 'CONSTRAINT [' + fkname + '_fk] FOREIGN KEY (' + fkcols + ')';
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
return sql;
|
||||
|
@ -300,7 +300,7 @@ export class GBCoreService implements IGBCoreService {
|
|||
private changeColumnQueryOverride(tableName, attributes): string {
|
||||
let sql: string = this.changeColumnQuery.apply(this.queryGenerator, [
|
||||
tableName,
|
||||
attributes,
|
||||
attributes
|
||||
]);
|
||||
const re1 = /ALTER\s+TABLE\s+\[([^\]]*)\]/;
|
||||
const matches = re1.exec(sql);
|
||||
|
@ -326,7 +326,7 @@ export class GBCoreService implements IGBCoreService {
|
|||
fkcols +
|
||||
')'
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
return sql;
|
||||
|
|
|
@ -36,35 +36,45 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const logger = require("../../../src/logger");
|
||||
const Path = require("path");
|
||||
const UrlJoin = require("url-join");
|
||||
const Fs = require("fs");
|
||||
const WaitUntil = require("wait-until");
|
||||
const express = require("express");
|
||||
const logger = require('../../../src/logger');
|
||||
const Path = require('path');
|
||||
const UrlJoin = require('url-join');
|
||||
const Fs = require('fs');
|
||||
const WaitUntil = require('wait-until');
|
||||
const express = require('express');
|
||||
|
||||
import { KBService } from "./../../kb.gbapp/services/KBService";
|
||||
import { GBImporter } from "./GBImporter";
|
||||
import { IGBCoreService, IGBInstance } from "botlib";
|
||||
import { GBConfigService } from "./GBConfigService";
|
||||
import { GBError } from "botlib";
|
||||
import { GuaribasPackage, GuaribasInstance } from "../models/GBModel";
|
||||
import { IGBPackage } from "botlib";
|
||||
import { AzureSearch } from "pragmatismo-io-framework";
|
||||
import { AzureDeployerService } from "../../azuredeployer.gbapp/services/AzureDeployerService";
|
||||
import { IGBCoreService, IGBInstance } from 'botlib';
|
||||
import { GBError } from 'botlib';
|
||||
import { IGBPackage } from 'botlib';
|
||||
import { AzureSearch } from 'pragmatismo-io-framework';
|
||||
import { AzureDeployerService } from '../../azuredeployer.gbapp/services/AzureDeployerService';
|
||||
import { GuaribasInstance, GuaribasPackage } from '../models/GBModel';
|
||||
import { KBService } from './../../kb.gbapp/services/KBService';
|
||||
import { GBConfigService } from './GBConfigService';
|
||||
import { GBImporter } from './GBImporter';
|
||||
|
||||
/** Deployer service for bots, themes, ai and more. */
|
||||
export class GBDeployer {
|
||||
core: IGBCoreService;
|
||||
importer: GBImporter;
|
||||
workDir: string = "./work";
|
||||
static deployFolder = "packages";
|
||||
public static deployFolder = 'packages';
|
||||
public core: IGBCoreService;
|
||||
public importer: GBImporter;
|
||||
public workDir: string = './work';
|
||||
|
||||
constructor(core: IGBCoreService, importer: GBImporter) {
|
||||
this.core = core;
|
||||
this.importer = importer;
|
||||
}
|
||||
|
||||
public static getConnectionStringFromInstance(instance: GuaribasInstance) {
|
||||
return `Server=tcp:${
|
||||
instance.storageServer
|
||||
}.database.windows.net,1433;Database=${instance.storageName};User ID=${
|
||||
instance.storageUsername
|
||||
};Password=${
|
||||
instance.storagePassword
|
||||
};Trusted_Connection=False;Encrypt=True;Connection Timeout=30;`;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Performs package deployment in all .gbai or default.
|
||||
|
@ -73,18 +83,18 @@ export class GBDeployer {
|
|||
public deployPackages(
|
||||
core: IGBCoreService,
|
||||
server: any,
|
||||
appPackages: Array<IGBPackage>
|
||||
appPackages: IGBPackage[]
|
||||
) {
|
||||
let _this = this;
|
||||
const _this = this;
|
||||
return new Promise((resolve: any, reject: any): any => {
|
||||
let totalPackages = 0;
|
||||
let additionalPath = GBConfigService.get("ADDITIONAL_DEPLOY_PATH");
|
||||
const additionalPath = GBConfigService.get('ADDITIONAL_DEPLOY_PATH');
|
||||
let paths = [GBDeployer.deployFolder];
|
||||
if (additionalPath) {
|
||||
paths = paths.concat(additionalPath.toLowerCase().split(";"));
|
||||
paths = paths.concat(additionalPath.toLowerCase().split(';'));
|
||||
}
|
||||
let botPackages = new Array<string>();
|
||||
let gbappPackages = new Array<string>();
|
||||
const botPackages = new Array<string>();
|
||||
const gbappPackages = new Array<string>();
|
||||
let generalPackages = new Array<string>();
|
||||
|
||||
function doIt(path) {
|
||||
|
@ -94,14 +104,14 @@ export class GBDeployer {
|
|||
.map(name => Path.join(source, name))
|
||||
.filter(isDirectory);
|
||||
|
||||
let dirs = getDirectories(path);
|
||||
const dirs = getDirectories(path);
|
||||
dirs.forEach(element => {
|
||||
if (element.startsWith(".")) {
|
||||
if (element.startsWith('.')) {
|
||||
logger.info(`Ignoring ${element}...`);
|
||||
} else {
|
||||
if (element.endsWith(".gbot")) {
|
||||
if (element.endsWith('.gbot')) {
|
||||
botPackages.push(element);
|
||||
} else if (element.endsWith(".gbapp")) {
|
||||
} else if (element.endsWith('.gbapp')) {
|
||||
gbappPackages.push(element);
|
||||
} else {
|
||||
generalPackages.push(element);
|
||||
|
@ -124,11 +134,11 @@ export class GBDeployer {
|
|||
|
||||
gbappPackages.forEach(e => {
|
||||
// Skips .gbapp inside deploy folder.
|
||||
if (!e.startsWith("packages")) {
|
||||
if (!e.startsWith('packages')) {
|
||||
logger.info(`Deploying app: ${e}...`);
|
||||
import(e)
|
||||
.then(m => {
|
||||
let p = new m.Package();
|
||||
const p = new m.Package();
|
||||
p.loadPackage(core, core.sequelize);
|
||||
appPackages.push(p);
|
||||
logger.info(`App (.gbapp) deployed: ${e}.`);
|
||||
|
@ -169,40 +179,40 @@ export class GBDeployer {
|
|||
|
||||
/** Then all remaining generalPackages are loaded. */
|
||||
|
||||
generalPackages = generalPackages.filter(p => !p.endsWith(".git"));
|
||||
generalPackages = generalPackages.filter(p => !p.endsWith('.git'));
|
||||
|
||||
generalPackages.forEach(filename => {
|
||||
let filenameOnly = Path.basename(filename);
|
||||
const filenameOnly = Path.basename(filename);
|
||||
logger.info(`Deploying package: ${filename}...`);
|
||||
|
||||
/** Handles apps for general bots - .gbapp must stay out of deploy folder. */
|
||||
|
||||
if (
|
||||
Path.extname(filename) === ".gbapp" ||
|
||||
Path.extname(filename) === ".gblib"
|
||||
Path.extname(filename) === '.gbapp' ||
|
||||
Path.extname(filename) === '.gblib'
|
||||
) {
|
||||
/** Themes for bots. */
|
||||
} else if (Path.extname(filename) === ".gbtheme") {
|
||||
server.use("/themes/" + filenameOnly, express.static(filename));
|
||||
} else if (Path.extname(filename) === '.gbtheme') {
|
||||
server.use('/themes/' + filenameOnly, express.static(filename));
|
||||
logger.info(
|
||||
`Theme (.gbtheme) assets accessible at: ${"/themes/" +
|
||||
`Theme (.gbtheme) assets accessible at: ${'/themes/' +
|
||||
filenameOnly}.`
|
||||
);
|
||||
|
||||
/** Knowledge base for bots. */
|
||||
} else if (Path.extname(filename) === ".gbkb") {
|
||||
} else if (Path.extname(filename) === '.gbkb') {
|
||||
server.use(
|
||||
"/kb/" + filenameOnly + "/subjects",
|
||||
express.static(UrlJoin(filename, "subjects"))
|
||||
'/kb/' + filenameOnly + '/subjects',
|
||||
express.static(UrlJoin(filename, 'subjects'))
|
||||
);
|
||||
logger.info(
|
||||
`KB (.gbkb) assets accessible at: ${"/kb/" + filenameOnly}.`
|
||||
`KB (.gbkb) assets accessible at: ${'/kb/' + filenameOnly}.`
|
||||
);
|
||||
} else if (Path.extname(filename) === ".gbui") {
|
||||
} else if (Path.extname(filename) === '.gbui') {
|
||||
// Already Handled
|
||||
} else {
|
||||
/** Unknown package format. */
|
||||
let err = new Error(`Package type not handled: ${filename}.`);
|
||||
const err = new Error(`Package type not handled: ${filename}.`);
|
||||
reject(err);
|
||||
}
|
||||
totalPackages++;
|
||||
|
@ -218,7 +228,7 @@ export class GBDeployer {
|
|||
.done(function(result) {
|
||||
if (botPackages.length === 0) {
|
||||
logger.warn(
|
||||
"No external packages to load, please use ADDITIONAL_DEPLOY_PATH to point to a .gbai package folder."
|
||||
'No external packages to load, please use ADDITIONAL_DEPLOY_PATH to point to a .gbai package folder.'
|
||||
);
|
||||
} else {
|
||||
logger.info(`Package deployment done.`);
|
||||
|
@ -233,17 +243,17 @@ export class GBDeployer {
|
|||
* Deploys a bot to the storage.
|
||||
*/
|
||||
|
||||
async deployBot(localPath: string): Promise<IGBInstance> {
|
||||
let packageType = Path.extname(localPath);
|
||||
let packageName = Path.basename(localPath);
|
||||
let instance = await this.importer.importIfNotExistsBotPackage(
|
||||
public async deployBot(localPath: string): Promise<IGBInstance> {
|
||||
const packageType = Path.extname(localPath);
|
||||
const packageName = Path.basename(localPath);
|
||||
const instance = await this.importer.importIfNotExistsBotPackage(
|
||||
packageName,
|
||||
localPath
|
||||
);
|
||||
return instance;
|
||||
}
|
||||
|
||||
async deployPackageToStorage(
|
||||
public async deployPackageToStorage(
|
||||
instanceId: number,
|
||||
packageName: string
|
||||
): Promise<GuaribasPackage> {
|
||||
|
@ -253,7 +263,7 @@ export class GBDeployer {
|
|||
});
|
||||
}
|
||||
|
||||
deployTheme(localPath: string) {
|
||||
public deployTheme(localPath: string) {
|
||||
// DISABLED: Until completed, "/ui/public".
|
||||
// FsExtra.copy(localPath, this.workDir + packageName)
|
||||
// .then(() => {
|
||||
|
@ -265,26 +275,26 @@ export class GBDeployer {
|
|||
// })
|
||||
}
|
||||
|
||||
async deployPackageFromLocalPath(localPath: string) {
|
||||
let packageType = Path.extname(localPath);
|
||||
public async deployPackageFromLocalPath(localPath: string) {
|
||||
const packageType = Path.extname(localPath);
|
||||
|
||||
switch (packageType) {
|
||||
case ".gbot":
|
||||
case '.gbot':
|
||||
return this.deployBot(localPath);
|
||||
|
||||
case ".gbtheme":
|
||||
case '.gbtheme':
|
||||
return this.deployTheme(localPath);
|
||||
|
||||
// PACKAGE: Put in package logic.
|
||||
case ".gbkb":
|
||||
let service = new KBService(this.core.sequelize);
|
||||
case '.gbkb':
|
||||
const service = new KBService(this.core.sequelize);
|
||||
return service.deployKb(this.core, this, localPath);
|
||||
|
||||
case ".gbui":
|
||||
case '.gbui':
|
||||
break;
|
||||
|
||||
default:
|
||||
var err = GBError.create(
|
||||
const err = GBError.create(
|
||||
`GuaribasBusinessError: Unknow package type: ${packageType}.`
|
||||
);
|
||||
Promise.reject(err);
|
||||
|
@ -292,30 +302,30 @@ export class GBDeployer {
|
|||
}
|
||||
}
|
||||
|
||||
async undeployPackageFromLocalPath(instance: IGBInstance, localPath: string) {
|
||||
let packageType = Path.extname(localPath);
|
||||
let packageName = Path.basename(localPath);
|
||||
public async undeployPackageFromLocalPath(instance: IGBInstance, localPath: string) {
|
||||
const packageType = Path.extname(localPath);
|
||||
const packageName = Path.basename(localPath);
|
||||
|
||||
let p = await this.getPackageByName(instance.instanceId, packageName);
|
||||
const p = await this.getPackageByName(instance.instanceId, packageName);
|
||||
|
||||
switch (packageType) {
|
||||
case ".gbot":
|
||||
case '.gbot':
|
||||
// TODO: this.undeployBot(packageName, localPath)
|
||||
break;
|
||||
|
||||
case ".gbtheme":
|
||||
case '.gbtheme':
|
||||
// TODO: this.undeployTheme(packageName, localPath)
|
||||
break;
|
||||
|
||||
case ".gbkb":
|
||||
let service = new KBService(this.core.sequelize);
|
||||
case '.gbkb':
|
||||
const service = new KBService(this.core.sequelize);
|
||||
return service.undeployKbFromStorage(instance, this, p.packageId);
|
||||
|
||||
case ".gbui":
|
||||
case '.gbui':
|
||||
break;
|
||||
|
||||
default:
|
||||
var err = GBError.create(
|
||||
const err = GBError.create(
|
||||
`GuaribasBusinessError: Unknown package type: ${packageType}.`
|
||||
);
|
||||
Promise.reject(err);
|
||||
|
@ -323,27 +333,17 @@ export class GBDeployer {
|
|||
}
|
||||
}
|
||||
|
||||
public static getConnectionStringFromInstance(instance: GuaribasInstance) {
|
||||
return `Server=tcp:${
|
||||
instance.storageServer
|
||||
}.database.windows.net,1433;Database=${instance.storageName};User ID=${
|
||||
instance.storageUsername
|
||||
};Password=${
|
||||
instance.storagePassword
|
||||
};Trusted_Connection=False;Encrypt=True;Connection Timeout=30;`;
|
||||
}
|
||||
|
||||
public async rebuildIndex(instance: GuaribasInstance) {
|
||||
let search = new AzureSearch(
|
||||
const search = new AzureSearch(
|
||||
instance.searchKey,
|
||||
instance.searchHost,
|
||||
instance.searchIndex,
|
||||
instance.searchIndexer
|
||||
);
|
||||
|
||||
let connectionString = GBDeployer.getConnectionStringFromInstance(instance);
|
||||
const connectionString = GBDeployer.getConnectionStringFromInstance(instance);
|
||||
|
||||
const dsName = "gb";
|
||||
const dsName = 'gb';
|
||||
try {
|
||||
await search.deleteDataSource(dsName);
|
||||
} catch (err) {
|
||||
|
@ -356,8 +356,8 @@ export class GBDeployer {
|
|||
await search.createDataSource(
|
||||
dsName,
|
||||
dsName,
|
||||
"GuaribasQuestion",
|
||||
"azuresql",
|
||||
'GuaribasQuestion',
|
||||
'azuresql',
|
||||
connectionString
|
||||
);
|
||||
|
||||
|
@ -375,11 +375,11 @@ export class GBDeployer {
|
|||
);
|
||||
}
|
||||
|
||||
async getPackageByName(
|
||||
public async getPackageByName(
|
||||
instanceId: number,
|
||||
packageName: string
|
||||
): Promise<GuaribasPackage> {
|
||||
var where = { packageName: packageName, instanceId: instanceId };
|
||||
const where = { packageName: packageName, instanceId: instanceId };
|
||||
return GuaribasPackage.findOne({
|
||||
where: where
|
||||
});
|
||||
|
@ -390,11 +390,11 @@ export class GBDeployer {
|
|||
* Hot deploy processing.
|
||||
*
|
||||
*/
|
||||
async scanBootPackage() {
|
||||
const deployFolder = "packages";
|
||||
let bootPackage = GBConfigService.get("BOOT_PACKAGE");
|
||||
public async scanBootPackage() {
|
||||
const deployFolder = 'packages';
|
||||
const bootPackage = GBConfigService.get('BOOT_PACKAGE');
|
||||
|
||||
if (bootPackage === "none") {
|
||||
if (bootPackage === 'none') {
|
||||
return Promise.resolve(true);
|
||||
} else {
|
||||
return this.deployPackageFromLocalPath(
|
||||
|
|
|
@ -30,42 +30,41 @@
|
|||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
const UrlJoin = require("url-join")
|
||||
import Fs = require("fs")
|
||||
import Path = require("path")
|
||||
import { IGBCoreService, IGBInstance } from "botlib"
|
||||
import { SecService } from "../../security.gblib/services/SecService"
|
||||
import { GuaribasInstance } from "../models/GBModel"
|
||||
const UrlJoin = require('url-join');
|
||||
import { IGBCoreService, IGBInstance } from 'botlib';
|
||||
import fs = require('fs');
|
||||
import path = require('path');
|
||||
import { SecService } from '../../security.gblib/services/SecService';
|
||||
import { GuaribasInstance } from '../models/GBModel';
|
||||
|
||||
export class GBImporter {
|
||||
core: IGBCoreService
|
||||
public core: IGBCoreService;
|
||||
|
||||
constructor(core: IGBCoreService) {
|
||||
this.core = core
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
async importIfNotExistsBotPackage(
|
||||
public async importIfNotExistsBotPackage(
|
||||
packageName: string,
|
||||
localPath: string) {
|
||||
|
||||
let packageJson = JSON.parse(
|
||||
Fs.readFileSync(UrlJoin(localPath, "package.json"), "utf8")
|
||||
)
|
||||
const packageJson = JSON.parse(
|
||||
Fs.readFileSync(UrlJoin(localPath, 'package.json'), 'utf8')
|
||||
);
|
||||
|
||||
let botId = packageJson.botId
|
||||
const botId = packageJson.botId;
|
||||
|
||||
let instance = await this.core.loadInstance(botId)
|
||||
const instance = await this.core.loadInstance(botId);
|
||||
if (instance) {
|
||||
return Promise.resolve(instance)
|
||||
return Promise.resolve(instance);
|
||||
} else {
|
||||
return this.createInstanceInternal(packageName, localPath, packageJson)
|
||||
return this.createInstanceInternal(packageName, localPath, packageJson);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,20 +74,20 @@ export class GBImporter {
|
|||
packageJson: any
|
||||
) {
|
||||
const settings = JSON.parse(
|
||||
Fs.readFileSync(UrlJoin(localPath, "settings.json"), "utf8")
|
||||
)
|
||||
Fs.readFileSync(UrlJoin(localPath, 'settings.json'), 'utf8')
|
||||
);
|
||||
const servicesJson = JSON.parse(
|
||||
Fs.readFileSync(UrlJoin(localPath, "services.json"), "utf8")
|
||||
)
|
||||
Fs.readFileSync(UrlJoin(localPath, 'services.json'), 'utf8')
|
||||
);
|
||||
|
||||
packageJson = Object.assign(packageJson, settings, servicesJson)
|
||||
packageJson = {...packageJson, ...settings, ...servicesJson};
|
||||
|
||||
GuaribasInstance.create(packageJson).then((instance: IGBInstance) => {
|
||||
|
||||
let service = new SecService()
|
||||
const service = new SecService();
|
||||
// TODO: service.importSecurityFile(localPath, instance)
|
||||
|
||||
Promise.resolve(instance)
|
||||
})
|
||||
Promise.resolve(instance);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,48 +36,48 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const { DialogSet, TextPrompt } = require("botbuilder-dialogs");
|
||||
const UrlJoin = require("url-join");
|
||||
const express = require("express");
|
||||
const logger = require("../../../src/logger");
|
||||
const request = require("request-promise-native");
|
||||
var AuthenticationContext = require("adal-node").AuthenticationContext;
|
||||
const { DialogSet, TextPrompt } = require('botbuilder-dialogs');
|
||||
const UrlJoin = require('url-join');
|
||||
const express = require('express');
|
||||
const logger = require('../../../src/logger');
|
||||
const request = require('request-promise-native');
|
||||
const AuthenticationContext = require('adal-node').AuthenticationContext;
|
||||
|
||||
import {
|
||||
AutoSaveStateMiddleware,
|
||||
BotFrameworkAdapter,
|
||||
BotStateSet,
|
||||
ConversationState,
|
||||
MemoryStorage,
|
||||
UserState,
|
||||
AutoSaveStateMiddleware
|
||||
} from "botbuilder";
|
||||
UserState
|
||||
} from 'botbuilder';
|
||||
|
||||
import { GBMinInstance, IGBPackage } from "botlib";
|
||||
import { GBAnalyticsPackage } from "../../analytics.gblib";
|
||||
import { GBCorePackage } from "../../core.gbapp";
|
||||
import { GBKBPackage } from "../../kb.gbapp";
|
||||
import { GBDeployer } from "./GBDeployer";
|
||||
import { GBSecurityPackage } from "../../security.gblib";
|
||||
import { GBAdminPackage } from "./../../admin.gbapp/index";
|
||||
import { GBCustomerSatisfactionPackage } from "../../customer-satisfaction.gbapp";
|
||||
import { GBWhatsappPackage } from "../../whatsapp.gblib";
|
||||
import { GBMinInstance, IGBPackage } from 'botlib';
|
||||
import {
|
||||
IGBAdminService,
|
||||
IGBCoreService,
|
||||
IGBConversationalService
|
||||
} from "botlib";
|
||||
import { GuaribasInstance } from "../models/GBModel";
|
||||
import { Messages } from "../strings";
|
||||
IGBConversationalService,
|
||||
IGBCoreService
|
||||
} from 'botlib';
|
||||
import { GBAnalyticsPackage } from '../../analytics.gblib';
|
||||
import { GBCorePackage } from '../../core.gbapp';
|
||||
import { GBCustomerSatisfactionPackage } from '../../customer-satisfaction.gbapp';
|
||||
import { GBKBPackage } from '../../kb.gbapp';
|
||||
import { GBSecurityPackage } from '../../security.gblib';
|
||||
import { GBWhatsappPackage } from '../../whatsapp.gblib';
|
||||
import { GuaribasInstance } from '../models/GBModel';
|
||||
import { Messages } from '../strings';
|
||||
import { GBAdminPackage } from './../../admin.gbapp/index';
|
||||
import { GBDeployer } from './GBDeployer';
|
||||
|
||||
/** Minimal service layer for a bot. */
|
||||
|
||||
export class GBMinService {
|
||||
core: IGBCoreService;
|
||||
conversationalService: IGBConversationalService;
|
||||
adminService: IGBAdminService;
|
||||
deployer: GBDeployer;
|
||||
public core: IGBCoreService;
|
||||
public conversationalService: IGBConversationalService;
|
||||
public adminService: IGBAdminService;
|
||||
public deployer: GBDeployer;
|
||||
|
||||
corePackage = "core.gbai";
|
||||
public corePackage = 'core.gbai';
|
||||
|
||||
/**
|
||||
* Static initialization of minimal instance.
|
||||
|
@ -107,40 +107,40 @@ export class GBMinService {
|
|||
*
|
||||
* */
|
||||
|
||||
async buildMin(
|
||||
public async buildMin(
|
||||
server: any,
|
||||
appPackages: Array<IGBPackage>,
|
||||
appPackages: IGBPackage[],
|
||||
instances: GuaribasInstance[]
|
||||
): Promise<GBMinInstance> {
|
||||
// Serves default UI on root address '/'.
|
||||
|
||||
let uiPackage = "default.gbui";
|
||||
const uiPackage = 'default.gbui';
|
||||
server.use(
|
||||
"/",
|
||||
express.static(UrlJoin(GBDeployer.deployFolder, uiPackage, "build"))
|
||||
'/',
|
||||
express.static(UrlJoin(GBDeployer.deployFolder, uiPackage, 'build'))
|
||||
);
|
||||
|
||||
Promise.all(
|
||||
instances.map(async instance => {
|
||||
// Gets the authorization key for each instance from Bot Service.
|
||||
|
||||
let webchatToken = await this.getWebchatToken(instance);
|
||||
const webchatToken = await this.getWebchatToken(instance);
|
||||
|
||||
// Serves the bot information object via HTTP so clients can get
|
||||
// instance information stored on server.
|
||||
|
||||
server.get("/instances/:botId", (req, res) => {
|
||||
server.get('/instances/:botId', (req, res) => {
|
||||
(async () => {
|
||||
// Returns the instance object to clients requesting bot info.
|
||||
|
||||
let botId = req.params.botId;
|
||||
let instance = await this.core.loadInstance(botId);
|
||||
const botId = req.params.botId;
|
||||
const instance = await this.core.loadInstance(botId);
|
||||
|
||||
if (instance) {
|
||||
let speechToken = await this.getSTSToken(instance);
|
||||
const speechToken = await this.getSTSToken(instance);
|
||||
let theme = instance.theme;
|
||||
if (!theme) {
|
||||
theme = "default.gbtheme";
|
||||
theme = 'default.gbtheme';
|
||||
}
|
||||
|
||||
res.send(
|
||||
|
@ -156,7 +156,7 @@ export class GBMinService {
|
|||
})
|
||||
);
|
||||
} else {
|
||||
let error = `Instance not found: ${botId}.`;
|
||||
const error = `Instance not found: ${botId}.`;
|
||||
res.sendStatus(error);
|
||||
logger.error(error);
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ export class GBMinService {
|
|||
|
||||
// Build bot adapter.
|
||||
|
||||
var { min, adapter, conversationState } = await this.buildBotAdapter(
|
||||
const { min, adapter, conversationState } = await this.buildBotAdapter(
|
||||
instance
|
||||
);
|
||||
|
||||
|
@ -175,7 +175,7 @@ export class GBMinService {
|
|||
|
||||
// Serves individual URL for each bot conversational interface...
|
||||
|
||||
let url = `/api/messages/${instance.botId}`;
|
||||
const url = `/api/messages/${instance.botId}`;
|
||||
server.post(url, async (req, res) => {
|
||||
return this.receiver(
|
||||
adapter,
|
||||
|
@ -193,14 +193,14 @@ export class GBMinService {
|
|||
|
||||
// Serves individual URL for each bot user interface.
|
||||
|
||||
let uiUrl = `/${instance.botId}`;
|
||||
const uiUrl = `/${instance.botId}`;
|
||||
server.use(
|
||||
uiUrl,
|
||||
express.static(UrlJoin(GBDeployer.deployFolder, uiPackage, "build"))
|
||||
express.static(UrlJoin(GBDeployer.deployFolder, uiPackage, 'build'))
|
||||
);
|
||||
|
||||
logger.info(`Bot UI ${uiPackage} accessible at: ${uiUrl}.`);
|
||||
let state = `${instance.instanceId}${Math.floor(
|
||||
const state = `${instance.instanceId}${Math.floor(
|
||||
Math.random() * 1000000000
|
||||
)}`;
|
||||
|
||||
|
@ -211,7 +211,7 @@ export class GBMinService {
|
|||
let authorizationUrl = UrlJoin(
|
||||
min.instance.authenticatorAuthorityHostUrl,
|
||||
min.instance.authenticatorTenant,
|
||||
"/oauth2/authorize"
|
||||
'/oauth2/authorize'
|
||||
);
|
||||
authorizationUrl = `${authorizationUrl}?response_type=code&client_id=${
|
||||
min.instance.authenticatorClientId
|
||||
|
@ -227,57 +227,57 @@ export class GBMinService {
|
|||
// access token that can be used to access the user owned resource.
|
||||
|
||||
server.get(`/${min.instance.botId}/token`, async (req, res) => {
|
||||
let state = await min.adminService.getValue(
|
||||
const state = await min.adminService.getValue(
|
||||
min.instance.instanceId,
|
||||
"AntiCSRFAttackState"
|
||||
'AntiCSRFAttackState'
|
||||
);
|
||||
|
||||
if (req.query.state != state) {
|
||||
let msg =
|
||||
"WARNING: state field was not provided as anti-CSRF token";
|
||||
const msg =
|
||||
'WARNING: state field was not provided as anti-CSRF token';
|
||||
logger.error(msg);
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
var authenticationContext = new AuthenticationContext(
|
||||
const authenticationContext = new AuthenticationContext(
|
||||
UrlJoin(
|
||||
min.instance.authenticatorAuthorityHostUrl,
|
||||
min.instance.authenticatorTenant
|
||||
)
|
||||
);
|
||||
|
||||
let resource = "https://graph.microsoft.com";
|
||||
const resource = 'https://graph.microsoft.com';
|
||||
|
||||
authenticationContext.acquireTokenWithAuthorizationCode(
|
||||
req.query.code,
|
||||
UrlJoin(instance.botEndpoint, min.instance.botId, "/token"),
|
||||
UrlJoin(instance.botEndpoint, min.instance.botId, '/token'),
|
||||
resource,
|
||||
instance.authenticatorClientId,
|
||||
instance.authenticatorClientSecret,
|
||||
async (err, token) => {
|
||||
if (err) {
|
||||
let msg = `Error acquiring token: ${err}`;
|
||||
const msg = `Error acquiring token: ${err}`;
|
||||
logger.error(msg);
|
||||
res.send(msg);
|
||||
} else {
|
||||
await this.adminService.setValue(
|
||||
instance.instanceId,
|
||||
"refreshToken",
|
||||
'refreshToken',
|
||||
token.refreshToken
|
||||
);
|
||||
await this.adminService.setValue(
|
||||
instance.instanceId,
|
||||
"accessToken",
|
||||
'accessToken',
|
||||
token.accessToken
|
||||
);
|
||||
await this.adminService.setValue(
|
||||
instance.instanceId,
|
||||
"expiresOn",
|
||||
'expiresOn',
|
||||
token.expiresOn.toString()
|
||||
);
|
||||
await this.adminService.setValue(
|
||||
instance.instanceId,
|
||||
"AntiCSRFAttackState",
|
||||
'AntiCSRFAttackState',
|
||||
null
|
||||
);
|
||||
|
||||
|
@ -305,8 +305,57 @@ export class GBMinService {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Webchat key from Bot Service.
|
||||
*
|
||||
* @param instance The Bot instance.
|
||||
*
|
||||
*/
|
||||
public async getWebchatToken(instance: any) {
|
||||
const options = {
|
||||
url: 'https://directline.botframework.com/v3/directline/tokens/generate',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${instance.webchatKey}`
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const json = await request(options);
|
||||
return Promise.resolve(JSON.parse(json));
|
||||
} catch (error) {
|
||||
const msg = `[botId:${instance.botId}] Error calling Direct Line client, verify Bot endpoint on the cloud. Error is: ${error}.`;
|
||||
return Promise.reject(new Error(msg));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Speech to Text / Text to Speech token from the provider.
|
||||
*
|
||||
* @param instance The general bot instance.
|
||||
*
|
||||
*/
|
||||
public async getSTSToken(instance: any) {
|
||||
// TODO: Make dynamic: https://CHANGE.api.cognitive.microsoft.com/sts/v1.0
|
||||
|
||||
const options = {
|
||||
url: 'https://westus.api.cognitive.microsoft.com/sts/v1.0/issueToken',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Ocp-Apim-Subscription-Key': instance.speechKey
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
return await request(options);
|
||||
} catch (error) {
|
||||
const msg = `Error calling Speech to Text client. Error is: ${error}.`;
|
||||
return Promise.reject(new Error(msg));
|
||||
}
|
||||
}
|
||||
|
||||
private async buildBotAdapter(instance: any) {
|
||||
let adapter = new BotFrameworkAdapter({
|
||||
const adapter = new BotFrameworkAdapter({
|
||||
appId: instance.marketplaceId,
|
||||
appPassword: instance.marketplacePassword
|
||||
});
|
||||
|
@ -318,7 +367,7 @@ export class GBMinService {
|
|||
|
||||
// The minimal bot is built here.
|
||||
|
||||
let min = new GBMinInstance();
|
||||
const min = new GBMinInstance();
|
||||
min.botId = instance.botId;
|
||||
min.bot = adapter;
|
||||
min.userState = userState;
|
||||
|
@ -326,16 +375,16 @@ export class GBMinService {
|
|||
min.conversationalService = this.conversationalService;
|
||||
min.adminService = this.adminService;
|
||||
min.instance = await this.core.loadInstance(min.botId);
|
||||
min.userProfile = conversationState.createProperty("userProfile");
|
||||
const dialogState = conversationState.createProperty("dialogState");
|
||||
min.userProfile = conversationState.createProperty('userProfile');
|
||||
const dialogState = conversationState.createProperty('dialogState');
|
||||
min.dialogs = new DialogSet(dialogState);
|
||||
min.dialogs.add(new TextPrompt("textPrompt"));
|
||||
min.dialogs.add(new TextPrompt('textPrompt'));
|
||||
|
||||
return { min, adapter, conversationState };
|
||||
}
|
||||
|
||||
private invokeLoadBot(appPackages: any[], min: any, server: any) {
|
||||
let sysPackages = new Array<IGBPackage>();
|
||||
const sysPackages = new Array<IGBPackage>();
|
||||
// NOTE: A semicolon is necessary before this line.
|
||||
[
|
||||
GBCorePackage,
|
||||
|
@ -346,21 +395,21 @@ export class GBMinService {
|
|||
GBCustomerSatisfactionPackage,
|
||||
GBWhatsappPackage
|
||||
].forEach(sysPackage => {
|
||||
let p = Object.create(sysPackage.prototype) as IGBPackage;
|
||||
const p = Object.create(sysPackage.prototype) as IGBPackage;
|
||||
p.loadBot(min);
|
||||
sysPackages.push(p);
|
||||
if (sysPackage.name === "GBWhatsappPackage") {
|
||||
let url = "/instances/:botId/whatsapp";
|
||||
if (sysPackage.name === 'GBWhatsappPackage') {
|
||||
const url = '/instances/:botId/whatsapp';
|
||||
server.post(url, (req, res) => {
|
||||
p["channel"].received(req, res);
|
||||
p.channel.received(req, res);
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
}, this);
|
||||
|
||||
appPackages.forEach(e => {
|
||||
e.sysPackages = sysPackages;
|
||||
e.loadBot(min);
|
||||
}, this);
|
||||
}, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -378,16 +427,16 @@ export class GBMinService {
|
|||
return adapter.processActivity(req, res, async context => {
|
||||
const state = conversationState.get(context);
|
||||
const step = await min.dialogs.createContext(context, state);
|
||||
step.context.activity.locale = "en-US"; // TODO: Make dynamic.
|
||||
step.context.activity.locale = 'en-US'; // TODO: Make dynamic.
|
||||
|
||||
try {
|
||||
const user = await min.userProfile.get(context, {});
|
||||
|
||||
if (!user.loaded) {
|
||||
await min.conversationalService.sendEvent(step, "loadInstance", {
|
||||
await min.conversationalService.sendEvent(step, 'loadInstance', {
|
||||
instanceId: instance.instanceId,
|
||||
botId: instance.botId,
|
||||
theme: instance.theme?instance.theme:"default.gbtheme" ,
|
||||
theme: instance.theme ? instance.theme : 'default.gbtheme' ,
|
||||
secret: instance.webchatKey
|
||||
});
|
||||
user.loaded = true;
|
||||
|
@ -401,32 +450,32 @@ export class GBMinService {
|
|||
}, ${context.activity.channelId}, {context.activity.value})`
|
||||
);
|
||||
if (
|
||||
context.activity.type === "conversationUpdate" &&
|
||||
context.activity.type === 'conversationUpdate' &&
|
||||
context.activity.membersAdded.length > 0
|
||||
) {
|
||||
let member = context.activity.membersAdded[0];
|
||||
if (member.name === "GeneralBots") {
|
||||
const member = context.activity.membersAdded[0];
|
||||
if (member.name === 'GeneralBots') {
|
||||
logger.info(`Bot added to conversation, starting chat...`);
|
||||
appPackages.forEach(e => {
|
||||
e.onNewSession(min, step);
|
||||
});
|
||||
// Processes the root dialog.
|
||||
|
||||
await step.beginDialog("/");
|
||||
await step.beginDialog('/');
|
||||
} else {
|
||||
logger.info(`Member added to conversation: ${member.name}`);
|
||||
}
|
||||
|
||||
// Processes messages.
|
||||
} else if (context.activity.type === "message") {
|
||||
} else if (context.activity.type === 'message') {
|
||||
// Checks for /admin request.
|
||||
|
||||
if (context.activity.text === "admin") {
|
||||
await step.beginDialog("/admin");
|
||||
if (context.activity.text === 'admin') {
|
||||
await step.beginDialog('/admin');
|
||||
|
||||
// Checks for /menu JSON signature.
|
||||
} else if (context.activity.text.startsWith('{"title"')) {
|
||||
await step.beginDialog("/menu", {
|
||||
await step.beginDialog('/menu', {
|
||||
data: JSON.parse(context.activity.text)
|
||||
});
|
||||
|
||||
|
@ -435,102 +484,53 @@ export class GBMinService {
|
|||
if (step.activeDialog) {
|
||||
await step.continueDialog();
|
||||
} else {
|
||||
await step.beginDialog("/answer", {
|
||||
await step.beginDialog('/answer', {
|
||||
query: context.activity.text
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Processes events.
|
||||
} else if (context.activity.type === "event") {
|
||||
} else if (context.activity.type === 'event') {
|
||||
// Empties dialog stack before going to the target.
|
||||
|
||||
await step.endAll();
|
||||
|
||||
if (context.activity.name === "whoAmI") {
|
||||
await step.beginDialog("/whoAmI");
|
||||
} else if (context.activity.name === "showSubjects") {
|
||||
await step.beginDialog("/menu");
|
||||
} else if (context.activity.name === "giveFeedback") {
|
||||
await step.beginDialog("/feedback", {
|
||||
if (context.activity.name === 'whoAmI') {
|
||||
await step.beginDialog('/whoAmI');
|
||||
} else if (context.activity.name === 'showSubjects') {
|
||||
await step.beginDialog('/menu');
|
||||
} else if (context.activity.name === 'giveFeedback') {
|
||||
await step.beginDialog('/feedback', {
|
||||
fromMenu: true
|
||||
});
|
||||
} else if (context.activity.name === "showFAQ") {
|
||||
await step.beginDialog("/faq");
|
||||
} else if (context.activity.name === "answerEvent") {
|
||||
await step.beginDialog("/answerEvent", {
|
||||
} else if (context.activity.name === 'showFAQ') {
|
||||
await step.beginDialog('/faq');
|
||||
} else if (context.activity.name === 'answerEvent') {
|
||||
await step.beginDialog('/answerEvent', {
|
||||
questionId: (context.activity as any).data,
|
||||
fromFaq: true
|
||||
});
|
||||
} else if (context.activity.name === "quality") {
|
||||
await step.beginDialog("/quality", {
|
||||
} else if (context.activity.name === 'quality') {
|
||||
await step.beginDialog('/quality', {
|
||||
score: (context.activity as any).data
|
||||
});
|
||||
} else if (context.activity.name === "updateToken") {
|
||||
let token = (context.activity as any).data;
|
||||
await step.beginDialog("/adminUpdateToken", { token: token });
|
||||
} else if (context.activity.name === 'updateToken') {
|
||||
const token = (context.activity as any).data;
|
||||
await step.beginDialog('/adminUpdateToken', { token: token });
|
||||
} else {
|
||||
await step.continueDialog();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
let msg = `ERROR: ${error.message} ${error.stack ? error.stack : ""}`;
|
||||
const msg = `ERROR: ${error.message} ${error.stack ? error.stack : ''}`;
|
||||
logger.error(msg);
|
||||
|
||||
await step.context.sendActivity(
|
||||
Messages[step.context.activity.locale].very_sorry_about_error
|
||||
);
|
||||
await step.beginDialog("/ask", { isReturning: true });
|
||||
await step.beginDialog('/ask', { isReturning: true });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Webchat key from Bot Service.
|
||||
*
|
||||
* @param instance The Bot instance.
|
||||
*
|
||||
*/
|
||||
async getWebchatToken(instance: any) {
|
||||
let options = {
|
||||
url: "https://directline.botframework.com/v3/directline/tokens/generate",
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${instance.webchatKey}`
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
let json = await request(options);
|
||||
return Promise.resolve(JSON.parse(json));
|
||||
} catch (error) {
|
||||
let msg = `[botId:${instance.botId}] Error calling Direct Line client, verify Bot endpoint on the cloud. Error is: ${error}.`;
|
||||
return Promise.reject(new Error(msg));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Speech to Text / Text to Speech token from the provider.
|
||||
*
|
||||
* @param instance The general bot instance.
|
||||
*
|
||||
*/
|
||||
async getSTSToken(instance: any) {
|
||||
// TODO: Make dynamic: https://CHANGE.api.cognitive.microsoft.com/sts/v1.0
|
||||
|
||||
let options = {
|
||||
url: "https://westus.api.cognitive.microsoft.com/sts/v1.0/issueToken",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Ocp-Apim-Subscription-Key": instance.speechKey
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
return await request(options);
|
||||
} catch (error) {
|
||||
let msg = `Error calling Speech to Text client. Error is: ${error}.`;
|
||||
return Promise.reject(new Error(msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
|
||||
export const Messages = {
|
||||
"en-US": {
|
||||
show_video: "I will show you a video, please wait...",
|
||||
good_morning: "good morning",
|
||||
good_evening: "good evening",
|
||||
good_night: "good night",
|
||||
hi: (msg ) => `Hello, ${msg}.`,
|
||||
'en-US': {
|
||||
show_video: 'I will show you a video, please wait...',
|
||||
good_morning: 'good morning',
|
||||
good_evening: 'good evening',
|
||||
good_night: 'good night',
|
||||
hi: (msg) => `Hello, ${msg}.`,
|
||||
very_sorry_about_error: `I'm sorry to inform that there was an error which was recorded to be solved.`
|
||||
|
||||
},
|
||||
"pt-BR": {
|
||||
show_video: "Vou te mostrar um vídeo. Por favor, aguarde...",
|
||||
good_morning: "bom dia",
|
||||
good_evening: "boa tarde",
|
||||
good_night: "boa noite",
|
||||
hi: (msg ) => `Oi, ${msg}.`,
|
||||
'pt-BR': {
|
||||
show_video: 'Vou te mostrar um vídeo. Por favor, aguarde...',
|
||||
good_morning: 'bom dia',
|
||||
good_evening: 'boa tarde',
|
||||
good_night: 'boa noite',
|
||||
hi: (msg) => `Oi, ${msg}.`,
|
||||
very_sorry_about_error: `Lamento, ocorreu um erro que já foi registrado para ser tratado.`
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
|
||||
import { expect } from 'chai'
|
||||
import 'mocha'
|
||||
import {GBImporter} from '../services/GBImporter'
|
||||
import { expect } from 'chai';
|
||||
import 'mocha';
|
||||
import {GBImporter} from '../services/GBImporter';
|
||||
|
||||
describe('Hello function', () => {
|
||||
|
||||
|
||||
it('should return empty test', () => {
|
||||
let service = new GBImporter(null);
|
||||
const service = new GBImporter(null);
|
||||
//service.importIfNotExistsBotPackage(null, null);
|
||||
const result = 0;
|
||||
expect(result).to.equal(0);
|
||||
|
|
|
@ -36,13 +36,13 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import { CSService } from "../services/CSService";
|
||||
import { AzureText } from "pragmatismo-io-framework";
|
||||
import { GBMinInstance } from "botlib";
|
||||
import { IGBDialog } from "botlib";
|
||||
import { BotAdapter } from "botbuilder";
|
||||
import { Messages } from "../strings";
|
||||
import { WaterfallDialog } from "botbuilder-dialogs";
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { GBMinInstance } from 'botlib';
|
||||
import { IGBDialog } from 'botlib';
|
||||
import { AzureText } from 'pragmatismo-io-framework';
|
||||
import { CSService } from '../services/CSService';
|
||||
import { Messages } from '../strings';
|
||||
|
||||
export class FeedbackDialog extends IGBDialog {
|
||||
/**
|
||||
|
@ -51,13 +51,13 @@ export class FeedbackDialog extends IGBDialog {
|
|||
* @param bot The bot adapter.
|
||||
* @param min The minimal bot instance data.
|
||||
*/
|
||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
const service = new CSService();
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog("/feedbackNumber", [
|
||||
new WaterfallDialog('/feedbackNumber', [
|
||||
async step => {
|
||||
let locale = step.context.activity.locale;
|
||||
const locale = step.context.activity.locale;
|
||||
// TODO: Migrate to 4.*+ await step.prompt("choicePrompt", Messages[locale].what_about_me, [
|
||||
// "1",
|
||||
// "2",
|
||||
|
@ -68,8 +68,8 @@ export class FeedbackDialog extends IGBDialog {
|
|||
return await step.next();
|
||||
},
|
||||
async step => {
|
||||
let locale = step.context.activity.locale;
|
||||
let rate = step.result.entity;
|
||||
const locale = step.context.activity.locale;
|
||||
const rate = step.result.entity;
|
||||
const user = await min.userProfile.get(context, {});
|
||||
await service.updateConversationRate(user.conversation, rate);
|
||||
await step.context.sendActivity(Messages[locale].thanks);
|
||||
|
@ -78,19 +78,19 @@ export class FeedbackDialog extends IGBDialog {
|
|||
])
|
||||
);
|
||||
|
||||
min.dialogs.add(new WaterfallDialog("/feedback", [
|
||||
min.dialogs.add(new WaterfallDialog('/feedback', [
|
||||
async step => {
|
||||
let locale = step.context.activity.locale;
|
||||
const locale = step.context.activity.locale;
|
||||
if (step.result.fromMenu) {
|
||||
await step.context.sendActivity(Messages[locale].about_suggestions);
|
||||
}
|
||||
|
||||
await step.prompt("textPrompt", Messages[locale].what_about_service);
|
||||
await step.prompt('textPrompt', Messages[locale].what_about_service);
|
||||
return await step.next();
|
||||
},
|
||||
async step => {
|
||||
let locale = step.context.activity.locale;
|
||||
let rate = await AzureText.getSentiment(
|
||||
const locale = step.context.activity.locale;
|
||||
const rate = await AzureText.getSentiment(
|
||||
min.instance.textAnalyticsKey,
|
||||
min.instance.textAnalyticsEndpoint,
|
||||
min.conversationalService.getCurrentLanguage(step),
|
||||
|
@ -104,7 +104,7 @@ export class FeedbackDialog extends IGBDialog {
|
|||
|
||||
// TODO: Record.
|
||||
}
|
||||
await step.replaceDialog("/ask", { isReturning: true });
|
||||
await step.replaceDialog('/ask', { isReturning: true });
|
||||
return await step.next();
|
||||
}
|
||||
]));
|
||||
|
|
|
@ -36,14 +36,14 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import { IGBDialog } from "botlib";
|
||||
import { IGBDialog } from 'botlib';
|
||||
|
||||
import { GBMinInstance } from "botlib";
|
||||
import { CSService } from "../services/CSService";
|
||||
import { BotAdapter } from "botbuilder";
|
||||
import { Messages } from "../strings";
|
||||
import { WaterfallDialog } from "botbuilder-dialogs";
|
||||
const logger = require("../../../src/logger");
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { GBMinInstance } from 'botlib';
|
||||
import { CSService } from '../services/CSService';
|
||||
import { Messages } from '../strings';
|
||||
const logger = require('../../../src/logger');
|
||||
|
||||
export class QualityDialog extends IGBDialog {
|
||||
/**
|
||||
|
@ -52,18 +52,18 @@ export class QualityDialog extends IGBDialog {
|
|||
* @param bot The bot adapter.
|
||||
* @param min The minimal bot instance data.
|
||||
*/
|
||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
const service = new CSService();
|
||||
|
||||
min.dialogs.add( new WaterfallDialog("/quality", [
|
||||
min.dialogs.add(new WaterfallDialog('/quality', [
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
const user = await min.userProfile.get(context, {});
|
||||
|
||||
var score = step.result;
|
||||
|
||||
const score = step.result;
|
||||
|
||||
setTimeout(
|
||||
() => min.conversationalService.sendEvent(step, "stop", null),
|
||||
() => min.conversationalService.sendEvent(step, 'stop', null),
|
||||
400
|
||||
);
|
||||
|
||||
|
@ -77,7 +77,7 @@ export class QualityDialog extends IGBDialog {
|
|||
user.lastQuestion,
|
||||
user.lastQuestionId
|
||||
);
|
||||
await step.replaceDialog("/ask", { isReturning: true });
|
||||
await step.replaceDialog('/ask', { isReturning: true });
|
||||
}
|
||||
return await step.next();
|
||||
}
|
||||
|
|
|
@ -34,34 +34,34 @@
|
|||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
const UrlJoin = require("url-join")
|
||||
import { GuaribasQuestionAlternate } from './models/index'
|
||||
import { QualityDialog } from './dialogs/QualityDialog'
|
||||
import { FeedbackDialog } from './dialogs/FeedbackDialog'
|
||||
import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"
|
||||
const UrlJoin = require('url-join');
|
||||
import { GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
|
||||
import { FeedbackDialog } from './dialogs/FeedbackDialog';
|
||||
import { QualityDialog } from './dialogs/QualityDialog';
|
||||
import { GuaribasQuestionAlternate } from './models/index';
|
||||
|
||||
import { Sequelize } from 'sequelize-typescript'
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
|
||||
export class GBCustomerSatisfactionPackage implements IGBPackage {
|
||||
sysPackages: IGBPackage[] = null
|
||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
public sysPackages: IGBPackage[] = null;
|
||||
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
core.sequelize.addModels([
|
||||
GuaribasQuestionAlternate
|
||||
])
|
||||
]);
|
||||
}
|
||||
unloadPackage(core: IGBCoreService): void {
|
||||
|
||||
public unloadPackage(core: IGBCoreService): void {
|
||||
|
||||
}
|
||||
loadBot(min: GBMinInstance): void {
|
||||
FeedbackDialog.setup(min.bot, min)
|
||||
QualityDialog.setup(min.bot, min)
|
||||
public loadBot(min: GBMinInstance): void {
|
||||
FeedbackDialog.setup(min.bot, min);
|
||||
QualityDialog.setup(min.bot, min);
|
||||
}
|
||||
unloadBot(min: GBMinInstance): void {
|
||||
|
||||
public unloadBot(min: GBMinInstance): void {
|
||||
|
||||
}
|
||||
onNewSession(min: GBMinInstance, step: any): void {
|
||||
|
||||
public onNewSession(min: GBMinInstance, step: any): void {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,34 +34,34 @@
|
|||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
DataTypes,
|
||||
DataTypeUUIDv4,
|
||||
DataTypeDate,
|
||||
DataTypeDecimal
|
||||
} from "sequelize"
|
||||
DataTypeDecimal,
|
||||
DataTypes,
|
||||
DataTypeUUIDv4
|
||||
} from 'sequelize';
|
||||
|
||||
import {
|
||||
Sequelize,
|
||||
Table,
|
||||
Column,
|
||||
Model,
|
||||
HasMany,
|
||||
AutoIncrement,
|
||||
BelongsTo,
|
||||
BelongsToMany,
|
||||
Length,
|
||||
ForeignKey,
|
||||
Column,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
DataType,
|
||||
ForeignKey,
|
||||
HasMany,
|
||||
IsUUID,
|
||||
Length,
|
||||
Model,
|
||||
PrimaryKey,
|
||||
AutoIncrement
|
||||
} from "sequelize-typescript"
|
||||
Sequelize,
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript';
|
||||
|
||||
import { GuaribasInstance } from "../../core.gbapp/models/GBModel"
|
||||
import { GuaribasInstance } from '../../core.gbapp/models/GBModel';
|
||||
|
||||
@Table
|
||||
export class GuaribasQuestionAlternate extends Model<GuaribasQuestionAlternate> {
|
||||
|
@ -69,16 +69,16 @@ export class GuaribasQuestionAlternate extends Model<GuaribasQuestionAlternate>
|
|||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
quickAnswerId: number
|
||||
public quickAnswerId: number;
|
||||
|
||||
@Column questionTyped: string
|
||||
@Column public questionTyped: string;
|
||||
|
||||
@Column questionText: string
|
||||
@Column public questionText: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column
|
||||
instanceId: number
|
||||
public instanceId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasInstance)
|
||||
instance: GuaribasInstance
|
||||
public instance: GuaribasInstance;
|
||||
}
|
||||
|
|
|
@ -30,12 +30,12 @@
|
|||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
import { GuaribasQuestionAlternate } from '../models'
|
||||
import { GuaribasConversation } from '../../analytics.gblib/models'
|
||||
import { GuaribasConversation } from '../../analytics.gblib/models';
|
||||
import { GuaribasQuestionAlternate } from '../models';
|
||||
|
||||
export class CSService {
|
||||
|
||||
async resolveQuestionAlternate(
|
||||
public async resolveQuestionAlternate(
|
||||
instanceId: number,
|
||||
questionTyped: string): Promise<GuaribasQuestionAlternate> {
|
||||
|
||||
|
@ -44,24 +44,24 @@ export class CSService {
|
|||
instanceId: instanceId,
|
||||
questionTyped: questionTyped
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async insertQuestionAlternate(
|
||||
public async insertQuestionAlternate(
|
||||
instanceId: number,
|
||||
questionTyped: string,
|
||||
questionText: string): Promise<GuaribasQuestionAlternate> {
|
||||
return GuaribasQuestionAlternate.create({
|
||||
questionTyped: questionTyped,
|
||||
questionText: questionText
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async updateConversationRate(
|
||||
public async updateConversationRate(
|
||||
conversation: GuaribasConversation,
|
||||
rate: number
|
||||
): Promise<GuaribasConversation> {
|
||||
conversation.rate = rate
|
||||
return conversation.save()
|
||||
conversation.rate = rate;
|
||||
return conversation.save();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
export const Messages = {
|
||||
"en-US": {
|
||||
about_suggestions: "Suggestions are welcomed and improve my quality...",
|
||||
what_about_service: "What about my service?",
|
||||
glad_you_liked: "I'm glad you liked. I'm here for you.",
|
||||
we_will_improve: "Let's take note of that, thanks for sharing.",
|
||||
what_about_me: "What about the service, please rate between 1 and 5.",
|
||||
thanks: "Thanks!",
|
||||
im_sorry_lets_try: "I'm sorry. Let's try again...",
|
||||
great_thanks: "Great, thanks for sharing your thoughts."
|
||||
'en-US': {
|
||||
about_suggestions: 'Suggestions are welcomed and improve my quality...',
|
||||
what_about_service: 'What about my service?',
|
||||
glad_you_liked: 'I\'m glad you liked. I\'m here for you.',
|
||||
we_will_improve: 'Let\'s take note of that, thanks for sharing.',
|
||||
what_about_me: 'What about the service, please rate between 1 and 5.',
|
||||
thanks: 'Thanks!',
|
||||
im_sorry_lets_try: 'I\'m sorry. Let\'s try again...',
|
||||
great_thanks: 'Great, thanks for sharing your thoughts.'
|
||||
},
|
||||
"pt-BR": {
|
||||
about_suggestions: "Sugestões melhoram muito minha qualidade...",
|
||||
what_about_service:"O que achou do meu atendimento?",
|
||||
glad_you_liked: "Bom saber que você gostou. Conte comigo.",
|
||||
we_will_improve: "Vamos registrar sua questão, obrigado pela sinceridade.",
|
||||
what_about_me: "O que achou do meu atendimento, de 1 a 5?",
|
||||
thanks: "Obrigado!",
|
||||
im_sorry_lets_try: "Desculpe-me, vamos tentar novamente.",
|
||||
great_thanks: "Ótimo, obrigado por contribuir com sua resposta."
|
||||
'pt-BR': {
|
||||
about_suggestions: 'Sugestões melhoram muito minha qualidade...',
|
||||
what_about_service: 'O que achou do meu atendimento?',
|
||||
glad_you_liked: 'Bom saber que você gostou. Conte comigo.',
|
||||
we_will_improve: 'Vamos registrar sua questão, obrigado pela sinceridade.',
|
||||
what_about_me: 'O que achou do meu atendimento, de 1 a 5?',
|
||||
thanks: 'Obrigado!',
|
||||
im_sorry_lets_try: 'Desculpe-me, vamos tentar novamente.',
|
||||
great_thanks: 'Ótimo, obrigado por contribuir com sua resposta.'
|
||||
}
|
||||
};
|
||||
|
|
|
@ -36,15 +36,15 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import { IGBDialog } from "botlib";
|
||||
import { AzureText } from "pragmatismo-io-framework";
|
||||
import { GBMinInstance } from "botlib";
|
||||
import { KBService } from "./../services/KBService";
|
||||
import { BotAdapter } from "botbuilder";
|
||||
import { Messages } from "../strings";
|
||||
import { WaterfallDialog } from "botbuilder-dialogs";
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { IGBDialog } from 'botlib';
|
||||
import { GBMinInstance } from 'botlib';
|
||||
import { AzureText } from 'pragmatismo-io-framework';
|
||||
import { Messages } from '../strings';
|
||||
import { KBService } from './../services/KBService';
|
||||
|
||||
const logger = require("../../../src/logger");
|
||||
const logger = require('../../../src/logger');
|
||||
|
||||
export class AskDialog extends IGBDialog {
|
||||
/**
|
||||
|
@ -53,18 +53,18 @@ export class AskDialog extends IGBDialog {
|
|||
* @param bot The bot adapter.
|
||||
* @param min The minimal bot instance data.
|
||||
*/
|
||||
static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
const service = new KBService(min.core.sequelize);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog("/answerEvent", [
|
||||
new WaterfallDialog('/answerEvent', [
|
||||
async step => {
|
||||
if (step.options && step.options["questionId"]) {
|
||||
let question = await service.getQuestionById(
|
||||
if (step.options && step.options.questionId) {
|
||||
const question = await service.getQuestionById(
|
||||
min.instance.instanceId,
|
||||
step.options["questionId"]
|
||||
step.options.questionId
|
||||
);
|
||||
let answer = await service.getAnswerById(
|
||||
const answer = await service.getAnswerById(
|
||||
min.instance.instanceId,
|
||||
question.answerId
|
||||
);
|
||||
|
@ -73,7 +73,7 @@ export class AskDialog extends IGBDialog {
|
|||
|
||||
await service.sendAnswer(min.conversationalService, step, answer);
|
||||
|
||||
await step.replaceDialog("/ask", { isReturning: true });
|
||||
await step.replaceDialog('/ask', { isReturning: true });
|
||||
}
|
||||
return await step.next();
|
||||
}
|
||||
|
@ -81,32 +81,32 @@ export class AskDialog extends IGBDialog {
|
|||
);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog("/answer", [
|
||||
new WaterfallDialog('/answer', [
|
||||
async step => {
|
||||
const user = await min.userProfile.get(step.context, {});
|
||||
let text = step.options["query"];
|
||||
let text = step.options.query;
|
||||
if (!text) {
|
||||
throw new Error(`/answer being called with no args.query text.`);
|
||||
}
|
||||
|
||||
let locale = step.context.activity.locale;
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
// Stops any content on projector.
|
||||
|
||||
await min.conversationalService.sendEvent(step, "stop", null);
|
||||
await min.conversationalService.sendEvent(step, 'stop', null);
|
||||
|
||||
// Handle extra text from FAQ.
|
||||
|
||||
if (step.options && step.options["query"]) {
|
||||
text = step.options["query"];
|
||||
} else if (step.options && step.options["fromFaq"]) {
|
||||
if (step.options && step.options.query) {
|
||||
text = step.options.query;
|
||||
} else if (step.options && step.options.fromFaq) {
|
||||
await step.context.sendActivity(Messages[locale].going_answer);
|
||||
}
|
||||
|
||||
// Spells check the input text before sending Search or NLP.
|
||||
|
||||
if (min.instance.spellcheckerKey) {
|
||||
let data = await AzureText.getSpelledText(
|
||||
const data = await AzureText.getSpelledText(
|
||||
min.instance.spellcheckerKey,
|
||||
text
|
||||
);
|
||||
|
@ -121,7 +121,7 @@ export class AskDialog extends IGBDialog {
|
|||
|
||||
user.lastQuestion = text;
|
||||
await min.userProfile.set(step.context, user);
|
||||
let resultsA = await service.ask(
|
||||
const resultsA = await service.ask(
|
||||
min.instance,
|
||||
text,
|
||||
min.instance.searchScore,
|
||||
|
@ -147,11 +147,11 @@ export class AskDialog extends IGBDialog {
|
|||
|
||||
// Goes to ask loop, again.
|
||||
|
||||
return await step.replaceDialog("/ask", { isReturning: true });
|
||||
return await step.replaceDialog('/ask', { isReturning: true });
|
||||
} else {
|
||||
// Second time running Search, now with no filter.
|
||||
|
||||
let resultsB = await service.ask(
|
||||
const resultsB = await service.ask(
|
||||
min.instance,
|
||||
text,
|
||||
min.instance.searchScore,
|
||||
|
@ -172,7 +172,7 @@ export class AskDialog extends IGBDialog {
|
|||
// Informs user that a broader search will be used.
|
||||
|
||||
if (user.subjects.length > 0) {
|
||||
let subjectText = `${KBService.getSubjectItemsSeparatedBySpaces(
|
||||
const subjectText = `${KBService.getSubjectItemsSeparatedBySpaces(
|
||||
user.subjects
|
||||
)}`;
|
||||
await step.context.sendActivity(Messages[locale].wider_answer);
|
||||
|
@ -185,13 +185,13 @@ export class AskDialog extends IGBDialog {
|
|||
step,
|
||||
resultsB.answer
|
||||
);
|
||||
return await step.replaceDialog("/ask", { isReturning: true });
|
||||
return await step.replaceDialog('/ask', { isReturning: true });
|
||||
} else {
|
||||
if (
|
||||
!(await min.conversationalService.routeNLP(step, min, text))
|
||||
) {
|
||||
await step.context.sendActivity(Messages[locale].did_not_find);
|
||||
return await step.replaceDialog("/ask", { isReturning: true });
|
||||
return await step.replaceDialog('/ask', { isReturning: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ export class AskDialog extends IGBDialog {
|
|||
);
|
||||
|
||||
min.dialogs.add(
|
||||
new WaterfallDialog("/ask", [
|
||||
new WaterfallDialog('/ask', [
|
||||
async step => {
|
||||
const locale = step.context.activity.locale;
|
||||
const user = await min.userProfile.get(step.context, {});
|
||||
|
@ -212,23 +212,23 @@ export class AskDialog extends IGBDialog {
|
|||
|
||||
// Three forms of asking.
|
||||
|
||||
if (step.options && step.options["firstTime"]) {
|
||||
if (step.options && step.options.firstTime) {
|
||||
text = Messages[locale].ask_first_time;
|
||||
} else if (step.options && step.options["isReturning"]) {
|
||||
} else if (step.options && step.options.isReturning) {
|
||||
text = Messages[locale].anything_else;
|
||||
} else if (user.subjects.length > 0) {
|
||||
text = Messages[locale].which_question;
|
||||
} else {
|
||||
throw new Error("Invalid use of /ask");
|
||||
throw new Error('Invalid use of /ask');
|
||||
}
|
||||
|
||||
if (text.length > 0) {
|
||||
return await step.prompt("textPrompt", text);
|
||||
return await step.prompt('textPrompt', text);
|
||||
}
|
||||
return await step.next();
|
||||
},
|
||||
async step => {
|
||||
return await step.replaceDialog("/answer", { query: step.result });
|
||||
return await step.replaceDialog('/answer', { query: step.result });
|
||||
}
|
||||
])
|
||||
);
|
||||
|
|
|
@ -34,41 +34,41 @@
|
|||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
import { KBService } from './../services/KBService'
|
||||
import { IGBDialog } from "botlib"
|
||||
import { BotAdapter } from "botbuilder"
|
||||
import { Messages } from "../strings";
|
||||
import { GBMinInstance } from "botlib"
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { IGBDialog } from 'botlib';
|
||||
import { GBMinInstance } from 'botlib';
|
||||
import { Messages } from '../strings';
|
||||
import { KBService } from './../services/KBService';
|
||||
|
||||
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) {
|
||||
public static setup(bot: BotAdapter, min: GBMinInstance) {
|
||||
|
||||
const service = new KBService(min.core.sequelize)
|
||||
const service = new KBService(min.core.sequelize);
|
||||
|
||||
min.dialogs.add(new WaterfallDialog("/faq", [
|
||||
min.dialogs.add(new WaterfallDialog('/faq', [
|
||||
async step => {
|
||||
let data = await service.getFaqBySubjectArray("faq", null)
|
||||
const data = await service.getFaqBySubjectArray('faq', null);
|
||||
const locale = step.context.activity.locale;
|
||||
if (data) {
|
||||
await min.conversationalService.sendEvent(step, "play", {
|
||||
playerType: "bullet",
|
||||
await min.conversationalService.sendEvent(step, 'play', {
|
||||
playerType: 'bullet',
|
||||
data: data.slice(0, 10)
|
||||
})
|
||||
|
||||
await step.context.sendActivity(Messages[locale].see_faq) // TODO: RND messages.
|
||||
await step.endDialog()
|
||||
});
|
||||
|
||||
await step.context.sendActivity(Messages[locale].see_faq); // TODO: RND messages.
|
||||
await step.endDialog();
|
||||
return await step.next();
|
||||
}
|
||||
}
|
||||
]))
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ export class MenuDialog extends IGBDialog {
|
|||
const locale = step.context.activity.locale;
|
||||
let rootSubjectId = null;
|
||||
|
||||
if (step.options && step.options['data']) {
|
||||
if (step.options && step.options.data) {
|
||||
const subject = step.result.data;
|
||||
|
||||
// If there is a shortcut specified as subject destination, go there.
|
||||
|
|
|
@ -34,45 +34,45 @@
|
|||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
const UrlJoin = require("url-join")
|
||||
const UrlJoin = require('url-join');
|
||||
|
||||
import { GuaribasAnswer, GuaribasQuestion, GuaribasSubject } from './models/index'
|
||||
import { GBMinInstance, IGBPackage } from "botlib"
|
||||
import { GBMinInstance, IGBPackage } from 'botlib';
|
||||
import { GuaribasAnswer, GuaribasQuestion, GuaribasSubject } from './models/index';
|
||||
|
||||
import { AskDialog } from "./dialogs/AskDialog"
|
||||
import { FaqDialog } from "./dialogs/FaqDialog"
|
||||
import { MenuDialog } from "./dialogs/MenuDialog"
|
||||
import { Sequelize } from 'sequelize-typescript'
|
||||
import { IGBCoreService } from 'botlib'
|
||||
import { IGBCoreService } from 'botlib';
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
import { AskDialog } from './dialogs/AskDialog';
|
||||
import { FaqDialog } from './dialogs/FaqDialog';
|
||||
import { MenuDialog } from './dialogs/MenuDialog';
|
||||
|
||||
export class GBKBPackage implements IGBPackage {
|
||||
|
||||
sysPackages: IGBPackage[] = null
|
||||
|
||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
public sysPackages: IGBPackage[] = null;
|
||||
|
||||
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
core.sequelize.addModels([
|
||||
GuaribasAnswer,
|
||||
GuaribasQuestion,
|
||||
GuaribasSubject
|
||||
])
|
||||
|
||||
}
|
||||
unloadPackage(core: IGBCoreService): void {
|
||||
|
||||
}
|
||||
loadBot(min: GBMinInstance): void {
|
||||
]);
|
||||
|
||||
AskDialog.setup(min.bot, min)
|
||||
FaqDialog.setup(min.bot, min)
|
||||
MenuDialog.setup(min.bot, min)
|
||||
|
||||
}
|
||||
unloadBot(min: GBMinInstance): void {
|
||||
|
||||
public unloadPackage(core: IGBCoreService): void {
|
||||
|
||||
}
|
||||
onNewSession(min: GBMinInstance, step: any): void {
|
||||
|
||||
public loadBot(min: GBMinInstance): void {
|
||||
|
||||
AskDialog.setup(min.bot, min);
|
||||
FaqDialog.setup(min.bot, min);
|
||||
MenuDialog.setup(min.bot, min);
|
||||
|
||||
}
|
||||
public unloadBot(min: GBMinInstance): void {
|
||||
|
||||
}
|
||||
public onNewSession(min: GBMinInstance, step: any): void {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,40 +30,57 @@
|
|||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
const logger = require("../../../src/logger")
|
||||
const Path = require("path")
|
||||
const Fs = require("fs")
|
||||
const promise = require('bluebird')
|
||||
const parse = promise.promisify(require('csv-parse'))
|
||||
const UrlJoin = require("url-join")
|
||||
const marked = require("marked")
|
||||
const path = require("path")
|
||||
const asyncPromise = require('async-promises')
|
||||
const walkPromise = require('walk-promise')
|
||||
import { Messages } from "../strings";
|
||||
const logger = require('../../../src/logger');
|
||||
const Path = require('path');
|
||||
const Fs = require('fs');
|
||||
const promise = require('bluebird');
|
||||
const parse = promise.promisify(require('csv-parse'));
|
||||
const UrlJoin = require('url-join');
|
||||
const marked = require('marked');
|
||||
const path = require('path');
|
||||
const asyncPromise = require('async-promises');
|
||||
const walkPromise = require('walk-promise');
|
||||
import { Messages } from '../strings';
|
||||
|
||||
import { Sequelize } from 'sequelize-typescript'
|
||||
import { GBConfigService } from './../../core.gbapp/services/GBConfigService'
|
||||
import { GuaribasQuestion, GuaribasAnswer, GuaribasSubject } from "../models"
|
||||
import { IGBCoreService, IGBConversationalService, IGBInstance } from "botlib"
|
||||
import { AzureSearch } from "pragmatismo-io-framework"
|
||||
import { GBDeployer } from "../../core.gbapp/services/GBDeployer"
|
||||
import { GuaribasPackage } from "../../core.gbapp/models/GBModel"
|
||||
import { IGBConversationalService, IGBCoreService, IGBInstance } from 'botlib';
|
||||
import { AzureSearch } from 'pragmatismo-io-framework';
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
import { GuaribasPackage } from '../../core.gbapp/models/GBModel';
|
||||
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
|
||||
import { GuaribasAnswer, GuaribasQuestion, GuaribasSubject } from '../models';
|
||||
import { GBConfigService } from './../../core.gbapp/services/GBConfigService';
|
||||
|
||||
export class KBServiceSearchResults {
|
||||
answer: GuaribasAnswer
|
||||
questionId: number
|
||||
public answer: GuaribasAnswer;
|
||||
public questionId: number;
|
||||
}
|
||||
|
||||
export class KBService {
|
||||
|
||||
sequelize: Sequelize
|
||||
public sequelize: Sequelize;
|
||||
|
||||
constructor(sequelize: Sequelize) {
|
||||
this.sequelize = sequelize
|
||||
this.sequelize = sequelize;
|
||||
}
|
||||
|
||||
async getQuestionById(
|
||||
public static getFormattedSubjectItems(subjects: GuaribasSubject[]) {
|
||||
if (!subjects) { return ''; }
|
||||
const out = [];
|
||||
subjects.forEach(subject => {
|
||||
out.push(subject.title);
|
||||
});
|
||||
return out.join(', ');
|
||||
}
|
||||
|
||||
public static getSubjectItemsSeparatedBySpaces(subjects: GuaribasSubject[]) {
|
||||
const out = [];
|
||||
subjects.forEach(subject => {
|
||||
out.push(subject.internalId);
|
||||
});
|
||||
return out.join(' ');
|
||||
}
|
||||
|
||||
public async getQuestionById(
|
||||
instanceId: number,
|
||||
questionId: number
|
||||
): Promise<GuaribasQuestion> {
|
||||
|
@ -72,10 +89,10 @@ export class KBService {
|
|||
instanceId: instanceId,
|
||||
questionId: questionId
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async getAnswerById(
|
||||
public async getAnswerById(
|
||||
instanceId: number,
|
||||
answerId: number
|
||||
): Promise<GuaribasAnswer> {
|
||||
|
@ -84,47 +101,47 @@ export class KBService {
|
|||
instanceId: instanceId,
|
||||
answerId: answerId
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async getAnswerByText(
|
||||
public async getAnswerByText(
|
||||
instanceId: number,
|
||||
text: string
|
||||
): Promise<any> {
|
||||
|
||||
const Op = Sequelize.Op
|
||||
const Op = Sequelize.Op;
|
||||
|
||||
let question = await GuaribasQuestion.findOne({
|
||||
const question = await GuaribasQuestion.findOne({
|
||||
where: {
|
||||
instanceId: instanceId,
|
||||
content: { [Op.like]: `%${text.trim()}%` }
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if (question) {
|
||||
let answer = await GuaribasAnswer.findOne({
|
||||
const answer = await GuaribasAnswer.findOne({
|
||||
where: {
|
||||
instanceId: instanceId,
|
||||
answerId: question.answerId
|
||||
}
|
||||
})
|
||||
return Promise.resolve({ question: question, answer: answer })
|
||||
});
|
||||
return Promise.resolve({ question: question, answer: answer });
|
||||
}
|
||||
return Promise.resolve(null)
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
async addAnswer(obj: GuaribasAnswer): Promise<GuaribasAnswer> {
|
||||
public async addAnswer(obj: GuaribasAnswer): Promise<GuaribasAnswer> {
|
||||
return new Promise<GuaribasAnswer>(
|
||||
(resolve, reject) => {
|
||||
GuaribasAnswer.create(obj).then(item => {
|
||||
resolve(item)
|
||||
resolve(item);
|
||||
}).error((reason) => {
|
||||
reject(reason)
|
||||
})
|
||||
})
|
||||
reject(reason);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async ask(
|
||||
public async ask(
|
||||
instance: IGBInstance,
|
||||
query: string,
|
||||
searchScore: number,
|
||||
|
@ -133,185 +150,165 @@ export class KBService {
|
|||
|
||||
// Builds search query.
|
||||
|
||||
query = query.toLowerCase()
|
||||
query = query.replace("?", " ")
|
||||
query = query.replace("!", " ")
|
||||
query = query.replace(".", " ")
|
||||
query = query.replace("/", " ")
|
||||
query = query.replace("\\", " ")
|
||||
query = query.toLowerCase();
|
||||
query = query.replace('?', ' ');
|
||||
query = query.replace('!', ' ');
|
||||
query = query.replace('.', ' ');
|
||||
query = query.replace('/', ' ');
|
||||
query = query.replace('\\', ' ');
|
||||
|
||||
if (subjects) {
|
||||
let text = KBService.getSubjectItemsSeparatedBySpaces(subjects)
|
||||
const text = KBService.getSubjectItemsSeparatedBySpaces(subjects);
|
||||
if (text) {
|
||||
query = `${query} ${text}`
|
||||
query = `${query} ${text}`;
|
||||
}
|
||||
}
|
||||
// TODO: Filter by instance. what = `${what}&$filter=instanceId eq ${instanceId}`
|
||||
try {
|
||||
if (instance.searchKey && GBConfigService.get("STORAGE_DIALECT") == "mssql") {
|
||||
let service = new AzureSearch(
|
||||
if (instance.searchKey && GBConfigService.get('STORAGE_DIALECT') == 'mssql') {
|
||||
const service = new AzureSearch(
|
||||
instance.searchKey,
|
||||
instance.searchHost,
|
||||
instance.searchIndex,
|
||||
instance.searchIndexer
|
||||
)
|
||||
let results = await service.search(query)
|
||||
);
|
||||
const results = await service.search(query);
|
||||
if (results && results.length > 0 &&
|
||||
results[0]["@search.score"] >= searchScore) {
|
||||
let value = await this.getAnswerById(
|
||||
results[0]['@search.score'] >= searchScore) {
|
||||
const value = await this.getAnswerById(
|
||||
instance.instanceId,
|
||||
results[0].answerId)
|
||||
results[0].answerId);
|
||||
if (value) {
|
||||
return Promise.resolve({ answer: value, questionId: results[0].questionId })
|
||||
}
|
||||
else {
|
||||
return Promise.resolve({ answer: null, questionId: 0 })
|
||||
return Promise.resolve({ answer: value, questionId: results[0].questionId });
|
||||
} else {
|
||||
return Promise.resolve({ answer: null, questionId: 0 });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let data = await this.getAnswerByText(instance.instanceId, query)
|
||||
const data = await this.getAnswerByText(instance.instanceId, query);
|
||||
if (data) {
|
||||
return Promise.resolve(
|
||||
{ answer: data.answer, questionId: data.question.questionId })
|
||||
{ answer: data.answer, questionId: data.question.questionId });
|
||||
} else {
|
||||
return Promise.resolve({ answer: null, questionId: 0 })
|
||||
return Promise.resolve({ answer: null, questionId: 0 });
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (reason) {
|
||||
} catch (reason) {
|
||||
return Promise.reject(new Error(reason));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static getFormattedSubjectItems(subjects: GuaribasSubject[]) {
|
||||
if (!subjects) return ""
|
||||
let out = []
|
||||
subjects.forEach(subject => {
|
||||
out.push(subject.title)
|
||||
})
|
||||
return out.join(", ")
|
||||
}
|
||||
|
||||
static getSubjectItemsSeparatedBySpaces(subjects: GuaribasSubject[]) {
|
||||
let out = []
|
||||
subjects.forEach(subject => {
|
||||
out.push(subject.internalId)
|
||||
})
|
||||
return out.join(" ")
|
||||
}
|
||||
|
||||
async getSubjectItems(
|
||||
public async getSubjectItems(
|
||||
instanceId: number,
|
||||
parentId: number
|
||||
): Promise<GuaribasSubject[]> {
|
||||
var where = { parentSubjectId: parentId, instanceId: instanceId }
|
||||
const where = { parentSubjectId: parentId, instanceId: instanceId };
|
||||
return GuaribasSubject.findAll({
|
||||
where: where
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async getFaqBySubjectArray(from: string, subjects: any): Promise<GuaribasQuestion[]> {
|
||||
let where = {
|
||||
public async getFaqBySubjectArray(from: string, subjects: any): Promise<GuaribasQuestion[]> {
|
||||
const where = {
|
||||
from: from
|
||||
}
|
||||
};
|
||||
|
||||
if (subjects) {
|
||||
if (subjects[0]) {
|
||||
where["subject1"] = subjects[0].internalId
|
||||
where.subject1 = subjects[0].internalId;
|
||||
}
|
||||
|
||||
if (subjects[1]) {
|
||||
where["subject2"] = subjects[1].internalId
|
||||
where.subject2 = subjects[1].internalId;
|
||||
}
|
||||
|
||||
if (subjects[2]) {
|
||||
where["subject3"] = subjects[2].internalId
|
||||
where.subject3 = subjects[2].internalId;
|
||||
}
|
||||
|
||||
if (subjects[3]) {
|
||||
where["subject4"] = subjects[3].internalId
|
||||
where.subject4 = subjects[3].internalId;
|
||||
}
|
||||
}
|
||||
return await GuaribasQuestion.findAll({
|
||||
where: where
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async importKbTabularFile(
|
||||
public async importKbTabularFile(
|
||||
filePath: string,
|
||||
instanceId: number,
|
||||
packageId: number
|
||||
): Promise<GuaribasQuestion[]> {
|
||||
|
||||
let file = Fs.readFileSync(filePath, "UCS-2")
|
||||
let opts = {
|
||||
delimiter: "\t"
|
||||
}
|
||||
const file = Fs.readFileSync(filePath, 'UCS-2');
|
||||
const opts = {
|
||||
delimiter: '\t'
|
||||
};
|
||||
|
||||
let lastQuestion: GuaribasQuestion;
|
||||
let lastAnswer: GuaribasAnswer;
|
||||
|
||||
let data = await parse(file, opts)
|
||||
const data = await parse(file, opts);
|
||||
return asyncPromise.eachSeries(data, async line => {
|
||||
|
||||
// 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]
|
||||
const subjectsText = line[0];
|
||||
const from = line[1];
|
||||
const to = line[2];
|
||||
const question = line[3];
|
||||
let answer = line[4];
|
||||
|
||||
// Skips the first line.
|
||||
|
||||
if (!(subjectsText === "subjects" && from == "from")) {
|
||||
let format = ".txt"
|
||||
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 (answer.indexOf('.md') > -1) {
|
||||
const mediaFilename = UrlJoin(path.dirname(filePath), '..', 'articles', answer);
|
||||
if (Fs.existsSync(mediaFilename)) {
|
||||
answer = Fs.readFileSync(mediaFilename, "utf8")
|
||||
format = ".md"
|
||||
answer = Fs.readFileSync(mediaFilename, 'utf8');
|
||||
format = '.md';
|
||||
} else {
|
||||
logger.info(`[GBImporter] File not found: ${mediaFilename}.`)
|
||||
answer = ""
|
||||
logger.info(`[GBImporter] File not found: ${mediaFilename}.`);
|
||||
answer = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Processes subjects hierarchy splitting by dots.
|
||||
|
||||
let subjectArray = subjectsText.split(".")
|
||||
const subjectArray = subjectsText.split('.');
|
||||
let subject1: string, subject2: string, subject3: string,
|
||||
subject4: string
|
||||
var indexer = 0
|
||||
subject4: string;
|
||||
let indexer = 0;
|
||||
|
||||
subjectArray.forEach(element => {
|
||||
if (indexer == 0) {
|
||||
subject1 = subjectArray[indexer].substring(0, 63)
|
||||
subject1 = subjectArray[indexer].substring(0, 63);
|
||||
} else if (indexer == 1) {
|
||||
subject2 = subjectArray[indexer].substring(0, 63)
|
||||
subject2 = subjectArray[indexer].substring(0, 63);
|
||||
} else if (indexer == 2) {
|
||||
subject3 = subjectArray[indexer].substring(0, 63)
|
||||
subject3 = subjectArray[indexer].substring(0, 63);
|
||||
} else if (indexer == 3) {
|
||||
subject4 = subjectArray[indexer].substring(0, 63)
|
||||
subject4 = subjectArray[indexer].substring(0, 63);
|
||||
}
|
||||
indexer++
|
||||
})
|
||||
indexer++;
|
||||
});
|
||||
|
||||
// Now with all the data ready, creates entities in the store.
|
||||
|
||||
let answer1 = await GuaribasAnswer.create({
|
||||
const answer1 = await GuaribasAnswer.create({
|
||||
instanceId: instanceId,
|
||||
content: answer,
|
||||
format: format,
|
||||
packageId: packageId,
|
||||
prevId: lastQuestion ? lastQuestion.questionId : 0,
|
||||
})
|
||||
prevId: lastQuestion ? lastQuestion.questionId : 0
|
||||
});
|
||||
|
||||
let question1 = await GuaribasQuestion.create({
|
||||
const question1 = await GuaribasQuestion.create({
|
||||
from: from,
|
||||
to: to,
|
||||
subject1: subject1,
|
||||
|
@ -322,41 +319,41 @@ export class KBService {
|
|||
instanceId: instanceId,
|
||||
answerId: answer1.answerId,
|
||||
packageId: packageId
|
||||
})
|
||||
});
|
||||
|
||||
if (lastAnswer && lastQuestion) {
|
||||
await lastAnswer.updateAttributes({ nextId: lastQuestion.questionId })
|
||||
await lastAnswer.updateAttributes({ nextId: lastQuestion.questionId });
|
||||
}
|
||||
lastAnswer = answer1
|
||||
lastQuestion = question1
|
||||
lastAnswer = answer1;
|
||||
lastQuestion = question1;
|
||||
|
||||
return Promise.resolve(lastQuestion)
|
||||
return Promise.resolve(lastQuestion);
|
||||
|
||||
} else {
|
||||
|
||||
// Skips the header.
|
||||
|
||||
return Promise.resolve(null)
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async sendAnswer(conversationalService: IGBConversationalService,
|
||||
step: any, answer: GuaribasAnswer) {
|
||||
public async sendAnswer(conversationalService: IGBConversationalService,
|
||||
step: any, answer: GuaribasAnswer) {
|
||||
|
||||
if (answer.content.endsWith('.mp4')) {
|
||||
await conversationalService.sendEvent(step, "play", {
|
||||
playerType: "video",
|
||||
await conversationalService.sendEvent(step, 'play', {
|
||||
playerType: 'video',
|
||||
data: answer.content
|
||||
})
|
||||
});
|
||||
} else if (answer.content.length > 140 &&
|
||||
step.context._activity.channelId === "webchat") {
|
||||
step.context._activity.channelId === 'webchat') {
|
||||
const locale = step.context.activity.locale;
|
||||
|
||||
await step.context.sendActivity(Messages[locale].will_answer_projector) // TODO: Handle rnd.
|
||||
var html = answer.content
|
||||
await step.context.sendActivity(Messages[locale].will_answer_projector); // TODO: Handle rnd.
|
||||
let html = answer.content;
|
||||
|
||||
if (answer.format === ".md") {
|
||||
if (answer.format === '.md') {
|
||||
marked.setOptions({
|
||||
renderer: new marked.Renderer(),
|
||||
gfm: true,
|
||||
|
@ -367,23 +364,23 @@ export class KBService {
|
|||
smartLists: true,
|
||||
smartypants: false,
|
||||
xhtml: false
|
||||
})
|
||||
html = marked(answer.content)
|
||||
});
|
||||
html = marked(answer.content);
|
||||
}
|
||||
await conversationalService.sendEvent(step, "play",
|
||||
{
|
||||
playerType: "markdown", data: {
|
||||
await conversationalService.sendEvent(step, 'play',
|
||||
{
|
||||
playerType: 'markdown', data: {
|
||||
content: html, answer: answer,
|
||||
prevId: answer.prevId, nextId: answer.nextId
|
||||
}
|
||||
})
|
||||
});
|
||||
} else {
|
||||
await step.context.sendActivity(answer.content)
|
||||
await conversationalService.sendEvent(step, "stop", null)
|
||||
await step.context.sendActivity(answer.content);
|
||||
await conversationalService.sendEvent(step, 'stop', null);
|
||||
}
|
||||
}
|
||||
|
||||
async importKbPackage(
|
||||
public async importKbPackage(
|
||||
localPath: string,
|
||||
packageStorage: GuaribasPackage,
|
||||
instance: IGBInstance
|
||||
|
@ -393,8 +390,8 @@ export class KBService {
|
|||
|
||||
await this.importSubjectFile(
|
||||
packageStorage.packageId,
|
||||
UrlJoin(localPath, "subjects.json"),
|
||||
instance)
|
||||
UrlJoin(localPath, 'subjects.json'),
|
||||
instance);
|
||||
|
||||
// Import all .tsv files in the tabular directory.
|
||||
|
||||
|
@ -402,41 +399,40 @@ export class KBService {
|
|||
localPath,
|
||||
instance,
|
||||
packageStorage.packageId
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
async importKbTabularDirectory(
|
||||
public async importKbTabularDirectory(
|
||||
localPath: string,
|
||||
instance: IGBInstance,
|
||||
packageId: number
|
||||
): Promise<any> {
|
||||
|
||||
let files = await walkPromise(UrlJoin(localPath, "tabular"))
|
||||
const files = await walkPromise(UrlJoin(localPath, 'tabular'));
|
||||
|
||||
return Promise.all(files.map(async file => {
|
||||
if (file.name.endsWith(".tsv")) {
|
||||
if (file.name.endsWith('.tsv')) {
|
||||
return this.importKbTabularFile(
|
||||
UrlJoin(file.root, file.name),
|
||||
instance.instanceId,
|
||||
packageId)
|
||||
packageId);
|
||||
}
|
||||
}))
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
async importSubjectFile(
|
||||
public async importSubjectFile(
|
||||
packageId: number,
|
||||
filename: string,
|
||||
instance: IGBInstance
|
||||
): Promise<any> {
|
||||
var subjects = JSON.parse(Fs.readFileSync(filename, "utf8"))
|
||||
const subjects = JSON.parse(Fs.readFileSync(filename, 'utf8'));
|
||||
|
||||
const doIt = async (subjects: GuaribasSubject[], parentSubjectId: number) => {
|
||||
return asyncPromise.eachSeries(subjects, async item => {
|
||||
let mediaFilename = item.id + ".png"
|
||||
const mediaFilename = item.id + '.png';
|
||||
|
||||
let value = await GuaribasSubject.create({
|
||||
const value = await GuaribasSubject.create({
|
||||
internalId: item.id,
|
||||
parentSubjectId: parentSubjectId,
|
||||
instanceId: instance.instanceId,
|
||||
|
@ -445,20 +441,19 @@ export class KBService {
|
|||
title: item.title,
|
||||
description: item.description,
|
||||
packageId: packageId
|
||||
})
|
||||
});
|
||||
|
||||
if (item.children) {
|
||||
return Promise.resolve(doIt(item.children, value.subjectId))
|
||||
return Promise.resolve(doIt(item.children, value.subjectId));
|
||||
} else {
|
||||
return Promise.resolve(item);
|
||||
}
|
||||
else {
|
||||
return Promise.resolve(item)
|
||||
}
|
||||
})
|
||||
}
|
||||
return doIt(subjects.children, null)
|
||||
});
|
||||
};
|
||||
return doIt(subjects.children, null);
|
||||
}
|
||||
|
||||
async undeployKbFromStorage(
|
||||
public async undeployKbFromStorage(
|
||||
instance: IGBInstance,
|
||||
deployer: GBDeployer,
|
||||
packageId: number
|
||||
|
@ -466,41 +461,41 @@ export class KBService {
|
|||
|
||||
await GuaribasQuestion.destroy({
|
||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||
})
|
||||
});
|
||||
await GuaribasAnswer.destroy({
|
||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||
})
|
||||
});
|
||||
await GuaribasSubject.destroy({
|
||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||
})
|
||||
});
|
||||
await GuaribasPackage.destroy({
|
||||
where: { instanceId: instance.instanceId, packageId: packageId }
|
||||
})
|
||||
});
|
||||
|
||||
await deployer.rebuildIndex(instance)
|
||||
await deployer.rebuildIndex(instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploys a knowledge base to the storage using the .gbkb format.
|
||||
*
|
||||
*
|
||||
* @param localPath Path to the .gbkb folder.
|
||||
*/
|
||||
async deployKb(core: IGBCoreService, deployer: GBDeployer, localPath: string) {
|
||||
let packageType = Path.extname(localPath)
|
||||
let packageName = Path.basename(localPath)
|
||||
logger.info(`[GBDeployer] Opening package: ${localPath}`)
|
||||
let packageObject = JSON.parse(
|
||||
Fs.readFileSync(UrlJoin(localPath, "package.json"), "utf8")
|
||||
)
|
||||
public async deployKb(core: IGBCoreService, deployer: GBDeployer, localPath: string) {
|
||||
const packageType = Path.extname(localPath);
|
||||
const packageName = Path.basename(localPath);
|
||||
logger.info(`[GBDeployer] Opening package: ${localPath}`);
|
||||
const packageObject = JSON.parse(
|
||||
Fs.readFileSync(UrlJoin(localPath, 'package.json'), 'utf8')
|
||||
);
|
||||
|
||||
let instance = await core.loadInstance(packageObject.botId)
|
||||
logger.info(`[GBDeployer] Importing: ${localPath}`)
|
||||
let p = await deployer.deployPackageToStorage(
|
||||
const instance = await core.loadInstance(packageObject.botId);
|
||||
logger.info(`[GBDeployer] Importing: ${localPath}`);
|
||||
const p = await deployer.deployPackageToStorage(
|
||||
instance.instanceId,
|
||||
packageName)
|
||||
await this.importKbPackage(localPath, p, instance)
|
||||
packageName);
|
||||
await this.importKbPackage(localPath, p, instance);
|
||||
|
||||
deployer.rebuildIndex(instance)
|
||||
logger.info(`[GBDeployer] Finished import of ${localPath}`)
|
||||
deployer.rebuildIndex(instance);
|
||||
logger.info(`[GBDeployer] Finished import of ${localPath}`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
export const Messages = {
|
||||
"en-US": {
|
||||
did_not_find: "I'm sorry I didn't find anything.",
|
||||
changing_language: "OK, changing language to English...",
|
||||
going_answer: "Great choice, now looking for your answer...",
|
||||
'en-US': {
|
||||
did_not_find: 'I\'m sorry I didn\'t find anything.',
|
||||
changing_language: 'OK, changing language to English...',
|
||||
going_answer: 'Great choice, now looking for your answer...',
|
||||
wider_answer: subjectText =>
|
||||
`Answering to you in a broader way... Not just about ${subjectText}.`,
|
||||
which_question: "What's your question?",
|
||||
anything_else: "So, may I help with anything else?",
|
||||
here_is_subjects: "Here are some subjects to choose from...",
|
||||
menu_select: "Select",
|
||||
which_question: 'What\'s your question?',
|
||||
anything_else: 'So, may I help with anything else?',
|
||||
here_is_subjects: 'Here are some subjects to choose from...',
|
||||
menu_select: 'Select',
|
||||
lets_search: query =>
|
||||
`Vamos pesquisar sobre ${query}... O que deseja saber?`,
|
||||
see_faq:
|
||||
"Please take a look at the FAQ I've prepared for you. You can click on them to get the answer.",
|
||||
'Please take a look at the FAQ I\'ve prepared for you. You can click on them to get the answer.',
|
||||
will_answer_projector:
|
||||
"I'll answer on the projector to a better experience...",
|
||||
ask_first_time: "What are you looking for?"
|
||||
'I\'ll answer on the projector to a better experience...',
|
||||
ask_first_time: 'What are you looking for?'
|
||||
},
|
||||
"pt-BR": {
|
||||
did_not_find: "Desculpe-me, não encontrei nada a respeito.",
|
||||
changing_language: "OK, mundando de idioma para o Português...",
|
||||
going_answer: "Ótima escolha, procurando resposta para sua questão...",
|
||||
'pt-BR': {
|
||||
did_not_find: 'Desculpe-me, não encontrei nada a respeito.',
|
||||
changing_language: 'OK, mundando de idioma para o Português...',
|
||||
going_answer: 'Ótima escolha, procurando resposta para sua questão...',
|
||||
wider_answer: subjectText =>
|
||||
`Vou te responder de modo mais abrangente... Não apenas sobre ${subjectText}`,
|
||||
which_question: "Qual a pergunta?",
|
||||
anything_else: "Então, posso ajudar em algo a mais?",
|
||||
here_is_subjects: "Aqui estão algumas categorias de assuntos...",
|
||||
menu_select: "Selecionar",
|
||||
which_question: 'Qual a pergunta?',
|
||||
anything_else: 'Então, posso ajudar em algo a mais?',
|
||||
here_is_subjects: 'Aqui estão algumas categorias de assuntos...',
|
||||
menu_select: 'Selecionar',
|
||||
lets_search: query =>
|
||||
`Let's search about ${query}... What do you want to know?`,
|
||||
see_faq:
|
||||
"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.',
|
||||
will_answer_projector:
|
||||
"Vou te responder na tela para melhor visualização...",
|
||||
ask_first_time: "Sobre como eu poderia ajudar?"
|
||||
'Vou te responder na tela para melhor visualização...',
|
||||
ask_first_time: 'Sobre como eu poderia ajudar?'
|
||||
}
|
||||
};
|
||||
|
|
|
@ -34,40 +34,39 @@
|
|||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
const UrlJoin = require("url-join")
|
||||
const UrlJoin = require('url-join');
|
||||
|
||||
import { GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
|
||||
|
||||
import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"
|
||||
|
||||
import { Sequelize } from "sequelize-typescript"
|
||||
import { GuaribasUser, GuaribasGroup, GuaribasUserGroup } from "./models"
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from './models';
|
||||
|
||||
export class GBSecurityPackage implements IGBPackage {
|
||||
sysPackages: IGBPackage[] = null
|
||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
public sysPackages: IGBPackage[] = null;
|
||||
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
core.sequelize.addModels([
|
||||
GuaribasGroup,
|
||||
GuaribasUser,
|
||||
GuaribasUserGroup
|
||||
])
|
||||
]);
|
||||
|
||||
core
|
||||
core;
|
||||
}
|
||||
|
||||
unloadPackage(core: IGBCoreService): void {
|
||||
public unloadPackage(core: IGBCoreService): void {
|
||||
|
||||
}
|
||||
|
||||
loadBot(min: GBMinInstance): void {
|
||||
public loadBot(min: GBMinInstance): void {
|
||||
|
||||
}
|
||||
|
||||
unloadBot(min: GBMinInstance): void {
|
||||
public unloadBot(min: GBMinInstance): void {
|
||||
|
||||
}
|
||||
onNewSession(min: GBMinInstance, step: any): void {
|
||||
public onNewSession(min: GBMinInstance, step: any): void {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,60 +34,60 @@
|
|||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
DataTypes,
|
||||
DataTypeUUIDv4,
|
||||
DataTypeDate,
|
||||
DataTypeDecimal
|
||||
} from "sequelize"
|
||||
DataTypeDecimal,
|
||||
DataTypes,
|
||||
DataTypeUUIDv4
|
||||
} from 'sequelize';
|
||||
|
||||
import {
|
||||
Sequelize,
|
||||
Table,
|
||||
Column,
|
||||
Model,
|
||||
HasMany,
|
||||
AutoIncrement,
|
||||
BelongsTo,
|
||||
BelongsToMany,
|
||||
Length,
|
||||
ForeignKey,
|
||||
Column,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
DataType,
|
||||
ForeignKey,
|
||||
HasMany,
|
||||
IsUUID,
|
||||
Length,
|
||||
Model,
|
||||
PrimaryKey,
|
||||
AutoIncrement
|
||||
} from "sequelize-typescript"
|
||||
Sequelize,
|
||||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript';
|
||||
|
||||
import { GuaribasInstance } from "../../core.gbapp/models/GBModel"
|
||||
import { GuaribasInstance } from '../../core.gbapp/models/GBModel';
|
||||
|
||||
@Table
|
||||
export class GuaribasUser extends Model<GuaribasUser> {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
userId: number
|
||||
public userId: number;
|
||||
|
||||
@Column displayName: string
|
||||
@Column public displayName: string;
|
||||
|
||||
@Column userSystemId: string
|
||||
@Column userName: string
|
||||
@Column public userSystemId: string;
|
||||
@Column public userName: string;
|
||||
|
||||
@Column defaultChannel: string
|
||||
@Column public defaultChannel: string;
|
||||
|
||||
@Column email: string
|
||||
@Column public email: string;
|
||||
|
||||
@Column(DataType.STRING(512))
|
||||
internalAddress: string
|
||||
public internalAddress: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column
|
||||
instanceId: number
|
||||
public instanceId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasInstance)
|
||||
instance: GuaribasInstance
|
||||
public instance: GuaribasInstance;
|
||||
}
|
||||
|
||||
@Table
|
||||
|
@ -95,40 +95,40 @@ export class GuaribasGroup extends Model<GuaribasGroup> {
|
|||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
groupId: number
|
||||
public groupId: number;
|
||||
|
||||
@Length({ min: 0, max: 512 })
|
||||
@Column
|
||||
displayName: string
|
||||
public displayName: string;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column
|
||||
instanceId: number
|
||||
public instanceId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasInstance)
|
||||
instance: GuaribasInstance
|
||||
public instance: GuaribasInstance;
|
||||
}
|
||||
|
||||
@Table
|
||||
export class GuaribasUserGroup extends Model<GuaribasUserGroup> {
|
||||
@ForeignKey(() => GuaribasUser)
|
||||
@Column
|
||||
userId: number
|
||||
public userId: number;
|
||||
|
||||
@ForeignKey(() => GuaribasGroup)
|
||||
@Column
|
||||
groupId: number
|
||||
public groupId: number;
|
||||
|
||||
@ForeignKey(() => GuaribasInstance)
|
||||
@Column
|
||||
instanceId: number
|
||||
public instanceId: number;
|
||||
|
||||
@BelongsTo(() => GuaribasInstance)
|
||||
instance: GuaribasInstance
|
||||
public instance: GuaribasInstance;
|
||||
|
||||
@BelongsTo(() => GuaribasGroup)
|
||||
group: GuaribasGroup
|
||||
public group: GuaribasGroup;
|
||||
|
||||
@BelongsTo(() => GuaribasUser)
|
||||
user: GuaribasUser
|
||||
public user: GuaribasUser;
|
||||
}
|
||||
|
|
|
@ -30,48 +30,48 @@
|
|||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
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 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');
|
||||
|
||||
import { GBServiceCallback, GBService, IGBInstance } from "botlib"
|
||||
import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from "../models"
|
||||
import { GBService, GBServiceCallback, IGBInstance } from 'botlib';
|
||||
import { GuaribasGroup, GuaribasUser, GuaribasUserGroup } from '../models';
|
||||
|
||||
export class SecService extends GBService {
|
||||
|
||||
async importSecurityFile(localPath: string, instance: IGBInstance) {
|
||||
let security = JSON.parse(
|
||||
Fs.readFileSync(UrlJoin(localPath, "security.json"), "utf8")
|
||||
)
|
||||
public async importSecurityFile(localPath: string, instance: IGBInstance) {
|
||||
const security = JSON.parse(
|
||||
Fs.readFileSync(UrlJoin(localPath, 'security.json'), 'utf8')
|
||||
);
|
||||
security.groups.forEach(group => {
|
||||
let groupDb = GuaribasGroup.build({
|
||||
const groupDb = GuaribasGroup.build({
|
||||
instanceId: instance.instanceId,
|
||||
displayName: group.displayName
|
||||
})
|
||||
});
|
||||
groupDb.save().then(groupDb => {
|
||||
group.users.forEach(user => {
|
||||
let userDb = GuaribasUser.build({
|
||||
const userDb = GuaribasUser.build({
|
||||
instanceId: instance.instanceId,
|
||||
groupId: groupDb.groupId,
|
||||
userName: user.userName
|
||||
})
|
||||
});
|
||||
userDb.save().then(userDb => {
|
||||
let userGroup = GuaribasUserGroup.build()
|
||||
userGroup.groupId = groupDb.groupId
|
||||
userGroup.userId = userDb.userId
|
||||
userGroup.save()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
const userGroup = GuaribasUserGroup.build();
|
||||
userGroup.groupId = groupDb.groupId;
|
||||
userGroup.userId = userDb.userId;
|
||||
userGroup.save();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async ensureUser(
|
||||
public async ensureUser(
|
||||
instanceId: number,
|
||||
userSystemId: string,
|
||||
userName: string,
|
||||
|
@ -83,24 +83,24 @@ export class SecService extends GBService {
|
|||
(resolve, reject) => {
|
||||
|
||||
GuaribasUser.findOne({
|
||||
attributes: ["instanceId", "internalAddress"],
|
||||
attributes: ['instanceId', 'internalAddress'],
|
||||
where: {
|
||||
instanceId: instanceId,
|
||||
userSystemId: userSystemId
|
||||
}
|
||||
}).then(user => {
|
||||
if (!user) {
|
||||
user = GuaribasUser.build()
|
||||
user = GuaribasUser.build();
|
||||
}
|
||||
user.userSystemId = userSystemId
|
||||
user.userName = userName
|
||||
user.displayName = displayName
|
||||
user.internalAddress = address
|
||||
user.email = userName
|
||||
user.defaultChannel = channelName
|
||||
user.save()
|
||||
resolve(user)
|
||||
}).error(reason => reject(reason))
|
||||
})
|
||||
user.userSystemId = userSystemId;
|
||||
user.userName = userName;
|
||||
user.displayName = displayName;
|
||||
user.internalAddress = address;
|
||||
user.email = userName;
|
||||
user.defaultChannel = channelName;
|
||||
user.save();
|
||||
resolve(user);
|
||||
}).error(reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,43 +34,41 @@
|
|||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
const UrlJoin = require("url-join")
|
||||
const UrlJoin = require('url-join');
|
||||
|
||||
import { GBMinInstance, IGBCoreService, IGBPackage } from 'botlib';
|
||||
|
||||
import { GBMinInstance, IGBPackage, IGBCoreService } from "botlib"
|
||||
|
||||
import { Sequelize } from "sequelize-typescript"
|
||||
import { WhatsappDirectLine } from "./services/WhatsappDirectLine"
|
||||
|
||||
import { Sequelize } from 'sequelize-typescript';
|
||||
import { WhatsappDirectLine } from './services/WhatsappDirectLine';
|
||||
|
||||
export class GBWhatsappPackage implements IGBPackage {
|
||||
|
||||
sysPackages: IGBPackage[] = null
|
||||
channel: WhatsappDirectLine
|
||||
public sysPackages: IGBPackage[] = null;
|
||||
public channel: WhatsappDirectLine;
|
||||
|
||||
loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
public loadPackage(core: IGBCoreService, sequelize: Sequelize): void {
|
||||
}
|
||||
|
||||
unloadPackage(core: IGBCoreService): void {
|
||||
public unloadPackage(core: IGBCoreService): void {
|
||||
|
||||
}
|
||||
|
||||
loadBot(min: GBMinInstance): void {
|
||||
|
||||
public loadBot(min: GBMinInstance): void {
|
||||
|
||||
// Only loads engine if it is defined on services.json.
|
||||
|
||||
if (min.instance.whatsappBotKey != "") {
|
||||
if (min.instance.whatsappBotKey != '') {
|
||||
this.channel = new WhatsappDirectLine(min.botId, min.instance.whatsappBotKey, min.instance.whatsappServiceKey,
|
||||
min.instance.whatsappServiceNumber, min.instance.whatsappServiceUrl, min.instance.whatsappServiceWebhookUrl)
|
||||
min.instance.whatsappServiceNumber, min.instance.whatsappServiceUrl, min.instance.whatsappServiceWebhookUrl);
|
||||
}
|
||||
}
|
||||
|
||||
unloadBot(min: GBMinInstance): void {
|
||||
public unloadBot(min: GBMinInstance): void {
|
||||
|
||||
}
|
||||
onNewSession(min: GBMinInstance, step: any): void {
|
||||
public onNewSession(min: GBMinInstance, step: any): void {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,45 +30,45 @@
|
|||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
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 Swagger = require('swagger-client')
|
||||
const rp = require('request-promise')
|
||||
import * as request from "request-promise-native"
|
||||
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 Swagger = require('swagger-client');
|
||||
const rp = require('request-promise');
|
||||
import * as request from 'request-promise-native';
|
||||
|
||||
import { GBServiceCallback, GBService, IGBInstance } from "botlib"
|
||||
import { GBService, GBServiceCallback, IGBInstance } from 'botlib';
|
||||
|
||||
export class WhatsappDirectLine extends GBService {
|
||||
|
||||
pollInterval = 1000
|
||||
directLineClientName = 'DirectLineClient'
|
||||
directLineSpecUrl = 'https://docs.botframework.com/en-us/restapi/directline3/swagger.json'
|
||||
public pollInterval = 1000;
|
||||
public directLineClientName = 'DirectLineClient';
|
||||
public directLineSpecUrl = 'https://docs.botframework.com/en-us/restapi/directline3/swagger.json';
|
||||
|
||||
directLineClient: any
|
||||
whatsappServiceKey: string
|
||||
whatsappServiceNumber: string
|
||||
whatsappServiceUrl: string
|
||||
whatsappServiceWebhookUrl: string
|
||||
botId: string
|
||||
watermark: string = null
|
||||
public directLineClient: any;
|
||||
public whatsappServiceKey: string;
|
||||
public whatsappServiceNumber: string;
|
||||
public whatsappServiceUrl: string;
|
||||
public whatsappServiceWebhookUrl: string;
|
||||
public botId: string;
|
||||
public watermark: string = null;
|
||||
|
||||
conversationIds = {}
|
||||
public conversationIds = {};
|
||||
|
||||
constructor(botId, directLineSecret, whatsappServiceKey, whatsappServiceNumber, whatsappServiceUrl, whatsappServiceWebhookUrl) {
|
||||
|
||||
super()
|
||||
super();
|
||||
|
||||
this.botId = botId
|
||||
this.whatsappServiceKey = whatsappServiceKey
|
||||
this.whatsappServiceNumber = whatsappServiceNumber
|
||||
this.whatsappServiceUrl = whatsappServiceUrl
|
||||
this.whatsappServiceWebhookUrl = whatsappServiceWebhookUrl
|
||||
this.botId = botId;
|
||||
this.whatsappServiceKey = whatsappServiceKey;
|
||||
this.whatsappServiceNumber = whatsappServiceNumber;
|
||||
this.whatsappServiceUrl = whatsappServiceUrl;
|
||||
this.whatsappServiceWebhookUrl = whatsappServiceWebhookUrl;
|
||||
|
||||
// TODO: Migrate to Swagger 3.
|
||||
this.directLineClient = rp(this.directLineSpecUrl)
|
||||
|
@ -76,16 +76,16 @@ export class WhatsappDirectLine extends GBService {
|
|||
return new Swagger({
|
||||
spec: JSON.parse(spec.trim()),
|
||||
usePromise: true
|
||||
})
|
||||
});
|
||||
})
|
||||
.then(async (client) => {
|
||||
client.clientAuthorizations.add('AuthorizationBotConnector',
|
||||
new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' +
|
||||
directLineSecret, 'header'))
|
||||
new Swagger.ApiKeyAuthorization('Authorization', 'Bearer ' +
|
||||
directLineSecret, 'header'));
|
||||
|
||||
var options = {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
url: UrlJoin(this.whatsappServiceUrl, "webhook"),
|
||||
url: UrlJoin(this.whatsappServiceUrl, 'webhook'),
|
||||
qs:
|
||||
{
|
||||
token: this.whatsappServiceKey,
|
||||
|
@ -96,67 +96,66 @@ export class WhatsappDirectLine extends GBService {
|
|||
{
|
||||
'cache-control': 'no-cache'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await request.post(options)
|
||||
logger.info(result)
|
||||
const result = await request.post(options);
|
||||
logger.info(result);
|
||||
} catch (error) {
|
||||
logger.error('Error initializing 3rd party Whatsapp provider.', error)
|
||||
logger.error('Error initializing 3rd party Whatsapp provider.', error);
|
||||
}
|
||||
|
||||
return client
|
||||
return client;
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error('Error initializing DirectLine client', err)
|
||||
})
|
||||
logger.error('Error initializing DirectLine client', err);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
received(req, res) {
|
||||
let text = req.body.messages[0].body
|
||||
let from = req.body.messages[0].author.split('@')[0]
|
||||
let fromName = req.body.messages[0].senderName
|
||||
public received(req, res) {
|
||||
const text = req.body.messages[0].body;
|
||||
const from = req.body.messages[0].author.split('@')[0];
|
||||
const fromName = req.body.messages[0].senderName;
|
||||
|
||||
if (req.body.messages[0].fromMe) {
|
||||
return // Exit here.
|
||||
return; // Exit here.
|
||||
}
|
||||
|
||||
logger.info(`GBWhatsapp: Hook called. from: ${from}(${fromName}), text: ${text})`)
|
||||
logger.info(`GBWhatsapp: Hook called. from: ${from}(${fromName}), text: ${text})`);
|
||||
|
||||
let conversationId = this.conversationIds[from]
|
||||
const conversationId = this.conversationIds[from];
|
||||
|
||||
this.directLineClient.then((client) => {
|
||||
|
||||
if (this.conversationIds[from] == null) {
|
||||
|
||||
logger.info(`GBWhatsapp: Starting new conversation on Bot.`)
|
||||
logger.info(`GBWhatsapp: Starting new conversation on Bot.`);
|
||||
client.Conversations.Conversations_StartConversation()
|
||||
.then((response) => {
|
||||
return response.obj.conversationId
|
||||
return response.obj.conversationId;
|
||||
})
|
||||
.then((conversationId) => {
|
||||
|
||||
this.conversationIds[from] = conversationId
|
||||
this.conversationIds[from] = conversationId;
|
||||
this.inputMessage(client, conversationId, text,
|
||||
from, fromName)
|
||||
from, fromName);
|
||||
|
||||
this.pollMessages(client, conversationId, from, fromName)
|
||||
this.pollMessages(client, conversationId, from, fromName);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Error starting conversation', err)
|
||||
})
|
||||
console.error('Error starting conversation', err);
|
||||
});
|
||||
|
||||
} else {
|
||||
this.inputMessage(client, conversationId, text,
|
||||
from, fromName)
|
||||
from, fromName);
|
||||
}
|
||||
res.end()
|
||||
})
|
||||
res.end();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
inputMessage(client, conversationId, text, from, fromName) {
|
||||
public inputMessage(client, conversationId, text, from, fromName) {
|
||||
|
||||
client.Conversations.Conversations_PostActivity(
|
||||
{
|
||||
|
@ -172,15 +171,15 @@ export class WhatsappDirectLine extends GBService {
|
|||
replyToId: from
|
||||
}
|
||||
}).catch((err) => {
|
||||
logger.error(`GBWhatsapp: Error receiving message: ${err}.`)
|
||||
})
|
||||
logger.error(`GBWhatsapp: Error receiving message: ${err}.`);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
pollMessages(client, conversationId, from, fromName) {
|
||||
public pollMessages(client, conversationId, from, fromName) {
|
||||
|
||||
logger.info(`GBWhatsapp: Starting polling message for conversationId:
|
||||
${conversationId}.`)
|
||||
logger.info(`GBWhatsapp: Starting polling message for conversationId:
|
||||
${conversationId}.`);
|
||||
|
||||
setInterval(() => {
|
||||
client.Conversations.Conversations_GetActivities({
|
||||
|
@ -188,67 +187,67 @@ export class WhatsappDirectLine extends GBService {
|
|||
conversationId, watermark: this.watermark
|
||||
})
|
||||
.then((response) => {
|
||||
this.watermark = response.obj.watermark
|
||||
return response.obj.activities
|
||||
this.watermark = response.obj.watermark;
|
||||
return response.obj.activities;
|
||||
})
|
||||
.then((activities) => {
|
||||
this.printMessages(activities, conversationId, from, fromName)
|
||||
})
|
||||
}, this.pollInterval)
|
||||
this.printMessages(activities, conversationId, from, fromName);
|
||||
});
|
||||
}, this.pollInterval);
|
||||
}
|
||||
|
||||
printMessages(activities, conversationId, from, fromName) {
|
||||
public printMessages(activities, conversationId, from, fromName) {
|
||||
|
||||
if (activities && activities.length) {
|
||||
|
||||
// Ignore own messages.
|
||||
|
||||
activities = activities.filter((m) => { return (m.from.id === "GeneralBots") && m.type === "message" })
|
||||
|
||||
if (activities.length) {
|
||||
activities = activities.filter((m) => (m.from.id === 'GeneralBots') && m.type === 'message');
|
||||
|
||||
if (activities.length) {
|
||||
|
||||
// Print other messages.
|
||||
|
||||
activities.forEach(activity => {
|
||||
this.printMessage(activity, conversationId, from, fromName)
|
||||
})
|
||||
this.printMessage(activity, conversationId, from, fromName);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printMessage(activity, conversationId, from, fromName) {
|
||||
public printMessage(activity, conversationId, from, fromName) {
|
||||
|
||||
let output = ""
|
||||
let output = '';
|
||||
|
||||
if (activity.text) {
|
||||
logger.info(`GBWhatsapp: MSG: ${activity.text}`)
|
||||
output = activity.text
|
||||
logger.info(`GBWhatsapp: MSG: ${activity.text}`);
|
||||
output = activity.text;
|
||||
}
|
||||
|
||||
if (activity.attachments) {
|
||||
activity.attachments.forEach((attachment) => {
|
||||
switch (attachment.contentType) {
|
||||
case "application/vnd.microsoft.card.hero":
|
||||
output += `\n${this.renderHeroCard(attachment)}`
|
||||
break
|
||||
case 'application/vnd.microsoft.card.hero':
|
||||
output += `\n${this.renderHeroCard(attachment)}`;
|
||||
break;
|
||||
|
||||
case "image/png":
|
||||
logger.info('Opening the requested image ' + attachment.contentUrl)
|
||||
output += `\n${attachment.contentUrl}`
|
||||
break
|
||||
case 'image/png':
|
||||
logger.info('Opening the requested image ' + attachment.contentUrl);
|
||||
output += `\n${attachment.contentUrl}`;
|
||||
break;
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
this.sendToDevice(conversationId, from, fromName, output)
|
||||
this.sendToDevice(conversationId, from, fromName, output);
|
||||
}
|
||||
|
||||
renderHeroCard(attachment) {
|
||||
return `${attachment.content.title} - ${attachment.content.text}`
|
||||
public renderHeroCard(attachment) {
|
||||
return `${attachment.content.title} - ${attachment.content.text}`;
|
||||
}
|
||||
|
||||
async sendToDevice(conversationId, to, toName, msg) {
|
||||
var options = {
|
||||
public async sendToDevice(conversationId, to, toName, msg) {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
url: UrlJoin(this.whatsappServiceUrl, 'message'),
|
||||
qs:
|
||||
|
@ -261,8 +260,8 @@ export class WhatsappDirectLine extends GBService {
|
|||
{
|
||||
'cache-control': 'no-cache'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = await request.get(options)
|
||||
const result = await request.get(options);
|
||||
}
|
||||
}
|
||||
|
|
100
src/app.ts
100
src/app.ts
|
@ -37,30 +37,30 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const logger = require("./logger");
|
||||
const express = require("express");
|
||||
const bodyParser = require("body-parser");
|
||||
const logger = require('./logger');
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const opn = require('opn');
|
||||
|
||||
import { GBConfigService } from "../packages/core.gbapp/services/GBConfigService";
|
||||
import { GBConversationalService } from "../packages/core.gbapp/services/GBConversationalService";
|
||||
import { GBMinService } from "../packages/core.gbapp/services/GBMinService";
|
||||
import { GBDeployer } from "../packages/core.gbapp/services/GBDeployer";
|
||||
import { GBWhatsappPackage } from "./../packages/whatsapp.gblib/index";
|
||||
import { GBCoreService } from "../packages/core.gbapp/services/GBCoreService";
|
||||
import { GBImporter } from "../packages/core.gbapp/services/GBImporter";
|
||||
import { GBAnalyticsPackage } from "../packages/analytics.gblib";
|
||||
import { GBCorePackage } from "../packages/core.gbapp";
|
||||
import { GBKBPackage } from "../packages/kb.gbapp";
|
||||
import { GBSecurityPackage } from "../packages/security.gblib";
|
||||
import { GBAdminPackage } from "../packages/admin.gbapp/index";
|
||||
import { GBCustomerSatisfactionPackage } from "../packages/customer-satisfaction.gbapp";
|
||||
import { GBAdminService } from "../packages/admin.gbapp/services/GBAdminService";
|
||||
import { GuaribasInstance } from "../packages/core.gbapp/models/GBModel";
|
||||
import { AzureDeployerService } from "../packages/azuredeployer.gbapp/services/AzureDeployerService";
|
||||
import { IGBPackage, IGBInstance } from "botlib";
|
||||
import { IGBInstance, IGBPackage } from 'botlib';
|
||||
import { GBAdminPackage } from '../packages/admin.gbapp/index';
|
||||
import { GBAdminService } from '../packages/admin.gbapp/services/GBAdminService';
|
||||
import { GBAnalyticsPackage } from '../packages/analytics.gblib';
|
||||
import { AzureDeployerService } from '../packages/azuredeployer.gbapp/services/AzureDeployerService';
|
||||
import { GBCorePackage } from '../packages/core.gbapp';
|
||||
import { GuaribasInstance } from '../packages/core.gbapp/models/GBModel';
|
||||
import { GBConfigService } from '../packages/core.gbapp/services/GBConfigService';
|
||||
import { GBConversationalService } from '../packages/core.gbapp/services/GBConversationalService';
|
||||
import { GBCoreService } from '../packages/core.gbapp/services/GBCoreService';
|
||||
import { GBDeployer } from '../packages/core.gbapp/services/GBDeployer';
|
||||
import { GBImporter } from '../packages/core.gbapp/services/GBImporter';
|
||||
import { GBMinService } from '../packages/core.gbapp/services/GBMinService';
|
||||
import { GBCustomerSatisfactionPackage } from '../packages/customer-satisfaction.gbapp';
|
||||
import { GBKBPackage } from '../packages/kb.gbapp';
|
||||
import { GBSecurityPackage } from '../packages/security.gblib';
|
||||
import { GBWhatsappPackage } from './../packages/whatsapp.gblib/index';
|
||||
|
||||
let appPackages = new Array<IGBPackage>();
|
||||
const appPackages = new Array<IGBPackage>();
|
||||
|
||||
/**
|
||||
* General Bots open-core entry point.
|
||||
|
@ -71,7 +71,7 @@ export class GBServer {
|
|||
* Program entry-point.
|
||||
*/
|
||||
|
||||
static run() {
|
||||
public static run() {
|
||||
|
||||
logger.info(`The Bot Server is in STARTING mode...`);
|
||||
|
||||
|
@ -79,8 +79,8 @@ export class GBServer {
|
|||
// bot instance. This allows the same server to attend multiple Bot on
|
||||
// the Marketplace until GB get serverless.
|
||||
|
||||
let port = process.env.port || process.env.PORT || 4242;
|
||||
let server = express();
|
||||
const port = process.env.port || process.env.PORT || 4242;
|
||||
const server = express();
|
||||
|
||||
server.use(bodyParser.json()); // to support JSON-encoded bodies
|
||||
server.use(
|
||||
|
@ -99,15 +99,15 @@ export class GBServer {
|
|||
// Reads basic configuration, initialize minimal services.
|
||||
|
||||
GBConfigService.init();
|
||||
let core = new GBCoreService();
|
||||
const core = new GBCoreService();
|
||||
|
||||
// Ensures cloud / on-premises infrastructure is setup.
|
||||
|
||||
logger.info(`Establishing a development local proxy (ngrok)...`);
|
||||
let proxyAddress = await core.ensureProxy(port);
|
||||
const proxyAddress = await core.ensureProxy(port);
|
||||
|
||||
let deployer = new GBDeployer(core, new GBImporter(core));
|
||||
let azureDeployer = new AzureDeployerService(deployer);
|
||||
const deployer = new GBDeployer(core, new GBImporter(core));
|
||||
const azureDeployer = new AzureDeployerService(deployer);
|
||||
|
||||
try {
|
||||
await core.initDatabase();
|
||||
|
@ -117,7 +117,7 @@ export class GBServer {
|
|||
bootInstance = await azureDeployer.deployFarm(proxyAddress);
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
"In case of error, please cleanup any infrastructure objects created during this procedure and .env before running again."
|
||||
'In case of error, please cleanup any infrastructure objects created during this procedure and .env before running again.'
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
|
@ -132,13 +132,13 @@ export class GBServer {
|
|||
|
||||
// Check admin password.
|
||||
|
||||
let conversationalService = new GBConversationalService(core);
|
||||
let adminService = new GBAdminService(core);
|
||||
let password = GBConfigService.get("ADMIN_PASS");
|
||||
const conversationalService = new GBConversationalService(core);
|
||||
const adminService = new GBAdminService(core);
|
||||
const password = GBConfigService.get('ADMIN_PASS');
|
||||
|
||||
if (!GBAdminService.StrongRegex.test(password)) {
|
||||
throw new Error(
|
||||
"Please, define a really strong password in ADMIN_PASS environment variable before running the server."
|
||||
'Please, define a really strong password in ADMIN_PASS environment variable before running the server.'
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ export class GBServer {
|
|||
GBWhatsappPackage
|
||||
].forEach(e => {
|
||||
logger.info(`Loading sys package: ${e.name}...`);
|
||||
let p = Object.create(e.prototype) as IGBPackage;
|
||||
const p = Object.create(e.prototype) as IGBPackage;
|
||||
p.loadPackage(core, core.sequelize);
|
||||
});
|
||||
|
||||
|
@ -165,9 +165,9 @@ export class GBServer {
|
|||
let instances: GuaribasInstance[];
|
||||
try {
|
||||
instances = await core.loadInstances();
|
||||
let instance = instances[0];
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
const instance = instances[0];
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
logger.info(`Updating bot endpoint to local reverse proxy (ngrok)...`);
|
||||
|
||||
await azureDeployer.updateBotProxy(
|
||||
|
@ -177,30 +177,30 @@ export class GBServer {
|
|||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.parent.code === "ELOGIN") {
|
||||
let group = GBConfigService.get("CLOUD_GROUP");
|
||||
let serverName = GBConfigService.get("STORAGE_SERVER").split(
|
||||
".database.windows.net"
|
||||
if (error.parent.code === 'ELOGIN') {
|
||||
const group = GBConfigService.get('CLOUD_GROUP');
|
||||
const serverName = GBConfigService.get('STORAGE_SERVER').split(
|
||||
'.database.windows.net'
|
||||
)[0];
|
||||
await azureDeployer.openStorageFirewall(group, serverName);
|
||||
} else {
|
||||
// Check if storage is empty and needs formatting.
|
||||
|
||||
let isInvalidObject =
|
||||
const isInvalidObject =
|
||||
error.parent.number == 208 || error.parent.errno == 1; // MSSQL or SQLITE.
|
||||
|
||||
if (isInvalidObject) {
|
||||
if (GBConfigService.get("STORAGE_SYNC") != "true") {
|
||||
throw `Operating storage is out of sync or there is a storage connection error. Try setting STORAGE_SYNC to true in .env file. Error: ${
|
||||
if (GBConfigService.get('STORAGE_SYNC') != 'true') {
|
||||
throw new Error(`Operating storage is out of sync or there is a storage connection error. Try setting STORAGE_SYNC to true in .env file. Error: ${
|
||||
error.message
|
||||
}.`;
|
||||
}.`);
|
||||
} else {
|
||||
logger.info(
|
||||
`Storage is empty. After collecting storage structure from all .gbapps it will get synced.`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw `Cannot connect to operating storage: ${error.message}.`;
|
||||
throw new Error(`Cannot connect to operating storage: ${error.message}.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ export class GBServer {
|
|||
// If instances is undefined here it's because storage has been formatted.
|
||||
// Load all instances from .gbot found on deploy package directory.
|
||||
if (!instances) {
|
||||
let saveInstance = new GuaribasInstance(bootInstance);
|
||||
const saveInstance = new GuaribasInstance(bootInstance);
|
||||
await saveInstance.save();
|
||||
instances = await core.loadInstances();
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ export class GBServer {
|
|||
// Setup server dynamic (per bot instance) resources and listeners.
|
||||
|
||||
logger.info(`Publishing instances...`);
|
||||
let minService = new GBMinService(
|
||||
const minService = new GBMinService(
|
||||
core,
|
||||
conversationalService,
|
||||
adminService,
|
||||
|
@ -230,13 +230,13 @@ export class GBServer {
|
|||
await minService.buildMin(server, appPackages, instances);
|
||||
logger.info(`The Bot Server is in RUNNING mode...`);
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
opn('http://localhost:4242');
|
||||
}
|
||||
|
||||
return core;
|
||||
} catch (err) {
|
||||
logger.error(`STOP: ${err} ${err.stack ? err.stack : ""}`);
|
||||
logger.error(`STOP: ${err} ${err.stack ? err.stack : ''}`);
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
const { createLogger, format, transports } = require('winston')
|
||||
const { createLogger, format, transports } = require('winston');
|
||||
|
||||
const config = {
|
||||
levels: {
|
||||
|
@ -53,7 +53,7 @@ const config = {
|
|||
silly: 'magenta',
|
||||
custom: 'yellow'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const logger = createLogger({
|
||||
format: format.combine(
|
||||
|
@ -62,11 +62,11 @@ const logger = createLogger({
|
|||
format.label({ label: 'GeneralBots' }),
|
||||
format.timestamp(),
|
||||
format.printf(nfo => {
|
||||
return `${nfo.timestamp} [${nfo.label}] ${nfo.level}: ${nfo.message}`
|
||||
return `${nfo.timestamp} [${nfo.label}] ${nfo.level}: ${nfo.message}`;
|
||||
})
|
||||
),
|
||||
levels: config.levels,
|
||||
transports: [new transports.Console()]
|
||||
})
|
||||
transports: [new transports.Console()]
|
||||
});
|
||||
|
||||
module.exports=logger
|
||||
module.exports = logger;
|
||||
|
|
Loading…
Add table
Reference in a new issue