Merge branch 'main' of https://github.com/GeneralBots/BotServer
1
.gitignore
vendored
|
@ -29,3 +29,4 @@ package-lock.json
|
||||||
yarn-lock.json
|
yarn-lock.json
|
||||||
logo.svg
|
logo.svg
|
||||||
screenshot.png
|
screenshot.png
|
||||||
|
data.db
|
||||||
|
|
47
.test-init.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import { expect, test } from 'vitest';
|
||||||
|
import { GBServer } from './src/app';
|
||||||
|
import { RootData } from './src/RootData';
|
||||||
|
import { GBMinInstance } from 'botlib';
|
||||||
|
import { Mutex } from 'async-mutex';
|
||||||
|
|
||||||
|
export default function init() {
|
||||||
|
|
||||||
|
const min = {
|
||||||
|
packages: null,
|
||||||
|
appPackages: null,
|
||||||
|
botId: 'gbtest',
|
||||||
|
instance: {botId: 'gbtest'},
|
||||||
|
core: {},
|
||||||
|
conversationalService: {},
|
||||||
|
kbService: {},
|
||||||
|
adminService: {},
|
||||||
|
deployService: {},
|
||||||
|
textServices: {},
|
||||||
|
bot: {},
|
||||||
|
dialogs: {},
|
||||||
|
userState: {},
|
||||||
|
userProfile: {},
|
||||||
|
whatsAppDirectLine: {},
|
||||||
|
cbMap: {},
|
||||||
|
scriptMap: {},
|
||||||
|
sandBoxMap: {},
|
||||||
|
gbappServices: {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GBServer.globals = new RootData();
|
||||||
|
GBServer.globals.server = null;
|
||||||
|
GBServer.globals.httpsServer = null;
|
||||||
|
GBServer.globals.webSessions = {};
|
||||||
|
GBServer.globals.processes = [0, { pid: 1, proc: {step: {}}}];
|
||||||
|
GBServer.globals.files = {};
|
||||||
|
GBServer.globals.appPackages = [];
|
||||||
|
GBServer.globals.sysPackages = [];
|
||||||
|
GBServer.globals.minInstances = [min];
|
||||||
|
GBServer.globals.minBoot = min;
|
||||||
|
GBServer.globals.wwwroot = null;
|
||||||
|
GBServer.globals.entryPointDialog = null;
|
||||||
|
GBServer.globals.debuggers = [];
|
||||||
|
GBServer.globals.indexSemaphore = new Mutex();
|
||||||
|
GBServer.globals.users = {1: {userId: 1}};
|
||||||
|
}
|
2
boot.mjs
|
@ -8,7 +8,7 @@ import pjson from './package.json' assert { type: 'json' };
|
||||||
|
|
||||||
// Displays version of Node JS being used at runtime and others attributes.
|
// Displays version of Node JS being used at runtime and others attributes.
|
||||||
|
|
||||||
process.stdout.write(`General Bots. BotServer@${pjson.version}, botlib@${pjson.dependencies.botlib}, botbuilder@${pjson.dependencies.botbuilder}, node@${process.version.replace('v', '')}, ${process.platform} ${process.arch} `);
|
process.stdout.write(`General Bots. BotServer@${pjson.version}, botlib@${pjson.dependencies.botlib}, node@${process.version.replace('v', '')}, ${process.platform} ${process.arch} `);
|
||||||
console.log(`\nLoading virtual machine source code files...`);
|
console.log(`\nLoading virtual machine source code files...`);
|
||||||
|
|
||||||
var __dirname = process.env.PWD || process.cwd();
|
var __dirname = process.env.PWD || process.cwd();
|
||||||
|
|
10
package.json
|
@ -76,7 +76,7 @@
|
||||||
"@azure/keyvault-keys": "4.8.0",
|
"@azure/keyvault-keys": "4.8.0",
|
||||||
"@azure/ms-rest-js": "2.7.0",
|
"@azure/ms-rest-js": "2.7.0",
|
||||||
"@azure/msal-node": "2.8.1",
|
"@azure/msal-node": "2.8.1",
|
||||||
"@azure/openai": "^2.0.0-beta.1",
|
"@azure/openai": "2.0.0-beta.1",
|
||||||
"@azure/search-documents": "12.0.0",
|
"@azure/search-documents": "12.0.0",
|
||||||
"@azure/storage-blob": "12.18.0",
|
"@azure/storage-blob": "12.18.0",
|
||||||
"@google-cloud/pubsub": "4.4.0",
|
"@google-cloud/pubsub": "4.4.0",
|
||||||
|
@ -137,11 +137,12 @@
|
||||||
"google-libphonenumber": "3.2.34",
|
"google-libphonenumber": "3.2.34",
|
||||||
"googleapis": "126.0.1",
|
"googleapis": "126.0.1",
|
||||||
"hnswlib-node": "3.0.0",
|
"hnswlib-node": "3.0.0",
|
||||||
"html-to-md": "^0.8.5",
|
"html-to-md": "0.8.5",
|
||||||
"http-proxy": "1.18.1",
|
"http-proxy": "1.18.1",
|
||||||
"ibm-watson": "9.1.0",
|
"ibm-watson": "9.1.0",
|
||||||
"instagram-private-api": "^1.46.1",
|
"instagram-private-api": "1.46.1",
|
||||||
"iso-639-1": "3.1.2",
|
"iso-639-1": "3.1.2",
|
||||||
|
"isomorphic-fetch": "3.0.0",
|
||||||
"join-images-updated": "1.1.11",
|
"join-images-updated": "1.1.11",
|
||||||
"js-md5": "0.8.3",
|
"js-md5": "0.8.3",
|
||||||
"json-schema-to-zod": "2.1.0",
|
"json-schema-to-zod": "2.1.0",
|
||||||
|
@ -210,7 +211,7 @@
|
||||||
"textract": "2.5.0",
|
"textract": "2.5.0",
|
||||||
"twilio": "5.1.0",
|
"twilio": "5.1.0",
|
||||||
"twitter-api-v2": "1.17.0",
|
"twitter-api-v2": "1.17.0",
|
||||||
"typeorm": "^0.3.20",
|
"typeorm": "0.3.20",
|
||||||
"typescript": "5.4.5",
|
"typescript": "5.4.5",
|
||||||
"url-join": "5.0.0",
|
"url-join": "5.0.0",
|
||||||
"vhost": "3.0.2",
|
"vhost": "3.0.2",
|
||||||
|
@ -218,6 +219,7 @@
|
||||||
"vm2-process": "2.1.5",
|
"vm2-process": "2.1.5",
|
||||||
"walk-promise": "0.2.0",
|
"walk-promise": "0.2.0",
|
||||||
"washyourmouthoutwithsoap": "1.0.2",
|
"washyourmouthoutwithsoap": "1.0.2",
|
||||||
|
"webdav-server": "2.6.2",
|
||||||
"whatsapp-cloud-api": "0.3.1",
|
"whatsapp-cloud-api": "0.3.1",
|
||||||
"whatsapp-web.js": "https://github.com/Julzk/whatsapp-web.js/tarball/jkr_hotfix_7",
|
"whatsapp-web.js": "https://github.com/Julzk/whatsapp-web.js/tarball/jkr_hotfix_7",
|
||||||
"winston": "3.13.0",
|
"winston": "3.13.0",
|
||||||
|
|
|
@ -313,7 +313,7 @@ export class AdminDialog extends IGBDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packageName.indexOf('.') !== -1) {
|
if (packageName.indexOf('.') !== -1) {
|
||||||
cmd1 = `deployPackage ${process.env.STORAGE_SITE} /${process.env.STORAGE_LIBRARY}/${botId}.gbai/${packageName}`;
|
cmd1 = `deployPackage ${process.env.STORAGE_SITE} /${GBConfigService.get('STORAGE_LIBRARY')}/${botId}.gbai/${packageName}`;
|
||||||
} else {
|
} else {
|
||||||
cmd1 = `deployPackage ${packageName}`;
|
cmd1 = `deployPackage ${packageName}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
@ -49,13 +47,14 @@ import { GBSharePointService } from '../../sharepoint.gblib/services/SharePointS
|
||||||
import { GuaribasAdmin } from '../models/AdminModel.js';
|
import { GuaribasAdmin } from '../models/AdminModel.js';
|
||||||
import msRestAzure from 'ms-rest-azure';
|
import msRestAzure from 'ms-rest-azure';
|
||||||
import Path from 'path';
|
import Path from 'path';
|
||||||
import { caseSensitive_Numbs_SpecialCharacters_PW, lowercase_PW } from 'super-strong-password-generator'
|
import { caseSensitive_Numbs_SpecialCharacters_PW, lowercase_PW } from 'super-strong-password-generator';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import Fs from 'fs';
|
import Fs from 'fs';
|
||||||
import { GBServer } from '../../../src/app.js';
|
import { GBServer } from '../../../src/app.js';
|
||||||
import { GuaribasUser } from '../../security.gbapp/models/index.js';
|
import { GuaribasUser } from '../../security.gbapp/models/index.js';
|
||||||
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js';
|
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js';
|
||||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||||
|
import { GBUtil } from '../../../src/util.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Services for server administration.
|
* Services for server administration.
|
||||||
|
@ -89,45 +88,40 @@ export class GBAdminService implements IGBAdminService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async getADALCredentialsFromUsername(username: string, password: string) {
|
public static async getADALCredentialsFromUsername(username: string, password: string) {
|
||||||
|
|
||||||
return await msRestAzure.loginWithUsernamePassword(username, password);
|
return await msRestAzure.loginWithUsernamePassword(username, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getMobileCode() {
|
public static getMobileCode() {
|
||||||
|
|
||||||
return this.getNumberIdentifier(6);
|
return this.getNumberIdentifier(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getRndPassword(): string {
|
public static getRndPassword(): string {
|
||||||
|
|
||||||
let password = caseSensitive_Numbs_SpecialCharacters_PW(15);
|
let password = caseSensitive_Numbs_SpecialCharacters_PW(15);
|
||||||
password = password.replace(/[\@\[\=\:\;\?\"\'\#]/gi, '*');
|
password = password.replace(/[\@\[\=\:\;\?\"\'\#]/gi, '*');
|
||||||
|
|
||||||
const removeRepeatedChars = (s, r) => {
|
const removeRepeatedChars = (s, r) => {
|
||||||
let res = '', last = null, counter = 0;
|
let res = '',
|
||||||
|
last = null,
|
||||||
|
counter = 0;
|
||||||
s.split('').forEach(char => {
|
s.split('').forEach(char => {
|
||||||
if (char == last)
|
if (char == last) counter++;
|
||||||
counter++;
|
|
||||||
else {
|
else {
|
||||||
counter = 0;
|
counter = 0;
|
||||||
last = char;
|
last = char;
|
||||||
}
|
}
|
||||||
if (counter < r)
|
if (counter < r) res += char;
|
||||||
res += char;
|
|
||||||
});
|
});
|
||||||
return res;
|
return res;
|
||||||
}
|
};
|
||||||
|
|
||||||
return removeRepeatedChars(password, 1);
|
return removeRepeatedChars(password, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getRndReadableIdentifier(): string {
|
public static getRndReadableIdentifier(): string {
|
||||||
|
|
||||||
return lowercase_PW(14);
|
return lowercase_PW(14);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getNumberIdentifier(digits: number = 14): string {
|
public static getNumberIdentifier(digits: number = 14): string {
|
||||||
|
|
||||||
if (digits <= 0) {
|
if (digits <= 0) {
|
||||||
throw new Error('Number of digits should be greater than 0.');
|
throw new Error('Number of digits should be greater than 0.');
|
||||||
}
|
}
|
||||||
|
@ -155,7 +149,6 @@ export class GBAdminService implements IGBAdminService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async undeployPackageCommand(text: string, min: GBMinInstance) {
|
public static async undeployPackageCommand(text: string, min: GBMinInstance) {
|
||||||
|
|
||||||
const packageName = text.split(' ')[1];
|
const packageName = text.split(' ')[1];
|
||||||
const importer = new GBImporter(min.core);
|
const importer = new GBImporter(min.core);
|
||||||
const deployer = new GBDeployer(min.core, importer);
|
const deployer = new GBDeployer(min.core, importer);
|
||||||
|
@ -167,7 +160,12 @@ export class GBAdminService implements IGBAdminService {
|
||||||
public static isSharePointPath(path: string) {
|
public static isSharePointPath(path: string) {
|
||||||
return path.indexOf('sharepoint.com') !== -1;
|
return path.indexOf('sharepoint.com') !== -1;
|
||||||
}
|
}
|
||||||
public static async deployPackageCommand(min: GBMinInstance, user: GuaribasUser, text: string, deployer: IGBDeployer) {
|
public static async deployPackageCommand(
|
||||||
|
min: GBMinInstance,
|
||||||
|
user: GuaribasUser,
|
||||||
|
text: string,
|
||||||
|
deployer: IGBDeployer
|
||||||
|
) {
|
||||||
const packageName = text.split(' ')[1];
|
const packageName = text.split(' ')[1];
|
||||||
|
|
||||||
if (!this.isSharePointPath(packageName)) {
|
if (!this.isSharePointPath(packageName)) {
|
||||||
|
@ -190,19 +188,21 @@ export class GBAdminService implements IGBAdminService {
|
||||||
await deployer['cleanupPackage'](min.instance, packageName);
|
await deployer['cleanupPackage'](min.instance, packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
await deployer['downloadFolder'](min,
|
if (!GBConfigService.get('STORAGE_NAME')) {
|
||||||
Path.join('work', `${gbai}`),
|
const path = Path.join(GBConfigService.get('STORAGE_LIBRARY'), gbaiPath);
|
||||||
Path.basename(localFolder));
|
GBUtil.copyIfNewerRecursive(path, localFolder);
|
||||||
|
} else {
|
||||||
|
await deployer['downloadFolder'](min, Path.join('work', `${gbai}`), Path.basename(localFolder));
|
||||||
|
}
|
||||||
await deployer['deployPackage2'](min, user, localFolder);
|
await deployer['deployPackage2'](min, user, localFolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static async rebuildIndexPackageCommand(min: GBMinInstance, deployer: GBDeployer) {
|
public static async rebuildIndexPackageCommand(min: GBMinInstance, deployer: GBDeployer) {
|
||||||
const service = await AzureDeployerService.createInstance(deployer);
|
const service = await AzureDeployerService.createInstance(deployer);
|
||||||
const searchIndex = min.instance.searchIndex ? min.instance.searchIndex : GBServer.globals.minBoot.instance.searchIndex;
|
const searchIndex = min.instance.searchIndex
|
||||||
await deployer.rebuildIndex(
|
? min.instance.searchIndex
|
||||||
min.instance,
|
: GBServer.globals.minBoot.instance.searchIndex;
|
||||||
service.getKBSearchSchema(searchIndex)
|
await deployer.rebuildIndex(min.instance, service.getKBSearchSchema(searchIndex));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async syncBotServerCommand(min: GBMinInstance, deployer: GBDeployer) {
|
public static async syncBotServerCommand(min: GBMinInstance, deployer: GBDeployer) {
|
||||||
|
@ -245,15 +245,15 @@ export class GBAdminService implements IGBAdminService {
|
||||||
return obj.value;
|
return obj.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async acquireElevatedToken(instanceId: number, root: boolean = false,
|
public async acquireElevatedToken(
|
||||||
|
instanceId: number,
|
||||||
|
root: boolean = false,
|
||||||
tokenName: string = '',
|
tokenName: string = '',
|
||||||
clientId: string = null,
|
clientId: string = null,
|
||||||
clientSecret: string = null,
|
clientSecret: string = null,
|
||||||
host: string = null,
|
host: string = null,
|
||||||
tenant: string = null
|
tenant: string = null
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
|
|
||||||
|
|
||||||
if (root) {
|
if (root) {
|
||||||
const minBoot = GBServer.globals.minBoot;
|
const minBoot = GBServer.globals.minBoot;
|
||||||
instanceId = minBoot.instance.instanceId;
|
instanceId = minBoot.instance.instanceId;
|
||||||
|
@ -267,7 +267,6 @@ export class GBAdminService implements IGBAdminService {
|
||||||
throw new Error(`/setupSecurity is required before running /publish.`);
|
throw new Error(`/setupSecurity is required before running /publish.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return new Promise<string>(async (resolve, reject) => {
|
return new Promise<string>(async (resolve, reject) => {
|
||||||
const instance = await this.core.loadInstanceById(instanceId);
|
const instance = await this.core.loadInstanceById(instanceId);
|
||||||
|
|
||||||
|
@ -276,14 +275,10 @@ export class GBAdminService implements IGBAdminService {
|
||||||
const accessToken = await this.getValue(instanceId, `${tokenName}accessToken`);
|
const accessToken = await this.getValue(instanceId, `${tokenName}accessToken`);
|
||||||
resolve(accessToken);
|
resolve(accessToken);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (tokenName && !root) {
|
if (tokenName && !root) {
|
||||||
|
|
||||||
const refreshToken = await this.getValue(instanceId, `${tokenName}refreshToken`);
|
const refreshToken = await this.getValue(instanceId, `${tokenName}refreshToken`);
|
||||||
|
|
||||||
let url = urlJoin(
|
let url = urlJoin(host, tenant, 'oauth/token');
|
||||||
host,
|
|
||||||
tenant, 'oauth/token');
|
|
||||||
let buff = new Buffer(`${clientId}:${clientSecret}`);
|
let buff = new Buffer(`${clientId}:${clientSecret}`);
|
||||||
const base64 = buff.toString('base64');
|
const base64 = buff.toString('base64');
|
||||||
|
|
||||||
|
@ -295,8 +290,8 @@ export class GBAdminService implements IGBAdminService {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
'grant_type': 'refresh_token',
|
grant_type: 'refresh_token',
|
||||||
'refresh_token': refreshToken
|
refresh_token: refreshToken
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
const result = await fetch(url, options);
|
const result = await fetch(url, options);
|
||||||
|
@ -313,15 +308,15 @@ export class GBAdminService implements IGBAdminService {
|
||||||
|
|
||||||
await this.setValue(instanceId, `${tokenName}accessToken`, token['access_token']);
|
await this.setValue(instanceId, `${tokenName}accessToken`, token['access_token']);
|
||||||
await this.setValue(instanceId, `${tokenName}refreshToken`, token['refresh_token']);
|
await this.setValue(instanceId, `${tokenName}refreshToken`, token['refresh_token']);
|
||||||
await this.setValue(instanceId, `${tokenName}expiresOn`,
|
await this.setValue(
|
||||||
new Date(Date.now() + (token['expires_in'] * 1000)).toString());
|
instanceId,
|
||||||
|
`${tokenName}expiresOn`,
|
||||||
|
new Date(Date.now() + token['expires_in'] * 1000).toString()
|
||||||
|
);
|
||||||
await this.setValue(instanceId, `${tokenName}AntiCSRFAttackState`, null);
|
await this.setValue(instanceId, `${tokenName}AntiCSRFAttackState`, null);
|
||||||
|
|
||||||
resolve(token['access_token']);
|
resolve(token['access_token']);
|
||||||
|
} else {
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
const oauth2 = tokenName ? 'oauth' : 'oauth2';
|
const oauth2 = tokenName ? 'oauth' : 'oauth2';
|
||||||
const authorizationUrl = urlJoin(
|
const authorizationUrl = urlJoin(
|
||||||
tokenName ? host : instance.authenticatorAuthorityHostUrl,
|
tokenName ? host : instance.authenticatorAuthorityHostUrl,
|
||||||
|
@ -359,5 +354,5 @@ export class GBAdminService implements IGBAdminService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async publish(min: GBMinInstance, packageName: string, republish: boolean): Promise<void> { }
|
public async publish(min: GBMinInstance, packageName: string, republish: boolean): Promise<void> {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| ( )_ _ |
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__,\| (˅) |( (_) ) |
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
| | | ( )_) | |
|
|
||||||
| (_) \___/' |
|
|
||||||
| |
|
| |
|
||||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
| Licensed under the AGPL-3.0. |
|
| Licensed under the AGPL-3.0. |
|
||||||
| |
|
| |
|
||||||
| According to our dual licensing model,this program can be used either |
|
| According to our dual licensing model, this program can be used either |
|
||||||
| under the terms of the GNU Affero General Public License,version 3, |
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
| or under a proprietary license. |
|
| or under a proprietary license. |
|
||||||
| |
|
| |
|
||||||
| The texts of the GNU Affero General Public License with an additional |
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
@ -19,13 +17,13 @@
|
||||||
| in the LICENSE file you have received along with this program. |
|
| in the LICENSE file you have received along with this program. |
|
||||||
| |
|
| |
|
||||||
| This program is distributed in the hope that it will be useful, |
|
| This program is distributed in the hope that it will be useful, |
|
||||||
| but WITHOUT ANY WARRANTY,without even the implied warranty of |
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
| GNU Affero General Public License for more details. |
|
| GNU Affero General Public License for more details. |
|
||||||
| |
|
| |
|
||||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
| The licensing of the program under the AGPLv3 does not imply a |
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
| trademark license. Therefore any rights,title and interest in |
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
| our trademarks remain entirely with us. |
|
| our trademarks remain entirely with us. |
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
@ -39,6 +37,7 @@ import SwaggerClient from 'swagger-client';
|
||||||
import { spawn } from 'child_process';
|
import { spawn } from 'child_process';
|
||||||
import { CodeServices } from '../../gpt.gblib/services/CodeServices.js';
|
import { CodeServices } from '../../gpt.gblib/services/CodeServices.js';
|
||||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||||
|
import { GBUtil } from '../../../src/util.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Web Automation services of conversation to be called by BASIC.
|
* Web Automation services of conversation to be called by BASIC.
|
||||||
|
@ -156,12 +155,8 @@ export class DebuggerService {
|
||||||
|
|
||||||
let min: GBMinInstance = GBServer.globals.minInstances.filter(p => p.instance.botId === botId)[0];
|
let min: GBMinInstance = GBServer.globals.minInstances.filter(p => p.instance.botId === botId)[0];
|
||||||
|
|
||||||
const client = await new SwaggerClient({
|
const client = await GBUtil.getDirectLineClient(min);
|
||||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
||||||
requestInterceptor: req => {
|
|
||||||
req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
GBServer.globals.debuggers[botId].client = client;
|
GBServer.globals.debuggers[botId].client = client;
|
||||||
const response = await client.apis.Conversations.Conversations_StartConversation();
|
const response = await client.apis.Conversations.Conversations_StartConversation();
|
||||||
const conversationId = response.obj.conversationId;
|
const conversationId = response.obj.conversationId;
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| ( )_ _ |
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__,\| (˅) |( (_) ) |
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
| | | ( )_) | |
|
|
||||||
| (_) \___/' |
|
|
||||||
| |
|
| |
|
||||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
| Licensed under the AGPL-3.0. |
|
| Licensed under the AGPL-3.0. |
|
||||||
| |
|
| |
|
||||||
| According to our dual licensing model,this program can be used either |
|
| According to our dual licensing model, this program can be used either |
|
||||||
| under the terms of the GNU Affero General Public License,version 3, |
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
| or under a proprietary license. |
|
| or under a proprietary license. |
|
||||||
| |
|
| |
|
||||||
| The texts of the GNU Affero General Public License with an additional |
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
@ -19,13 +17,13 @@
|
||||||
| in the LICENSE file you have received along with this program. |
|
| in the LICENSE file you have received along with this program. |
|
||||||
| |
|
| |
|
||||||
| This program is distributed in the hope that it will be useful, |
|
| This program is distributed in the hope that it will be useful, |
|
||||||
| but WITHOUT ANY WARRANTY,without even the implied warranty of |
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
| GNU Affero General Public License for more details. |
|
| GNU Affero General Public License for more details. |
|
||||||
| |
|
| |
|
||||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
| The licensing of the program under the AGPLv3 does not imply a |
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
| trademark license. Therefore any rights,title and interest in |
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
| our trademarks remain entirely with us. |
|
| our trademarks remain entirely with us. |
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
@ -429,7 +427,7 @@ export class DialogKeywords {
|
||||||
* @example TALK TOLIST (array,member)
|
* @example TALK TOLIST (array,member)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public async getToLst(pid, array, member) {
|
public async getToLst({pid, array, member}) {
|
||||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||||
|
|
||||||
if (!array) {
|
if (!array) {
|
||||||
|
@ -1350,12 +1348,7 @@ export class DialogKeywords {
|
||||||
|
|
||||||
const conversation = min['apiConversations'][pid];
|
const conversation = min['apiConversations'][pid];
|
||||||
|
|
||||||
const client = await new SwaggerClient({
|
const client = await GBUtil.getDirectLineClient(min);
|
||||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
||||||
requestInterceptor: req => {
|
|
||||||
req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
conversation.client = client;
|
conversation.client = client;
|
||||||
const response = await client.apis.Conversations.Conversations_StartConversation();
|
const response = await client.apis.Conversations.Conversations_StartConversation();
|
||||||
conversation.conversationId = response.obj.conversationId;
|
conversation.conversationId = response.obj.conversationId;
|
||||||
|
@ -1368,7 +1361,7 @@ export class DialogKeywords {
|
||||||
const step = proc.step;
|
const step = proc.step;
|
||||||
const min = GBServer.globals.minInstances.filter(p => p.instance.instanceId == proc.instanceId)[0];
|
const min = GBServer.globals.minInstances.filter(p => p.instance.instanceId == proc.instanceId)[0];
|
||||||
const sec = new SecService();
|
const sec = new SecService();
|
||||||
const user = await sec.getUserFromId(min.instance.instanceId, proc.userId);
|
const user = GBServer.globals.users [proc.userId];
|
||||||
const params = user ? JSON.parse(user.params) : {};
|
const params = user ? JSON.parse(user.params) : {};
|
||||||
return {
|
return {
|
||||||
min,
|
min,
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
import { GBVMService } from './GBVMService';
|
|
||||||
import { expect, test } from 'vitest'
|
|
||||||
|
|
||||||
test('Default', () => {
|
|
||||||
|
|
||||||
|
|
||||||
const args = GBVMService.getSetScheduleKeywordArgs(`
|
|
||||||
|
|
||||||
SET SCHEDULE "0 0 */1 * * *"
|
|
||||||
SET SCHEDULE "0 0 */3 * * *"
|
|
||||||
SET SCHEDULE "0 0 */2 * * *"
|
|
||||||
SET SCHEDULE "0 0 */2 * * *"
|
|
||||||
SET SCHEDULE "0 0 */3 * * *"
|
|
||||||
|
|
||||||
`);
|
|
||||||
|
|
||||||
expect(args.length).toBe(5);
|
|
||||||
|
|
||||||
});
|
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
import { GBMinInstance, GBService, IGBCoreService, GBLog } from 'botlib';
|
import { GBMinInstance, GBService, IGBCoreService, GBLog } from 'botlib';
|
||||||
import * as Fs from 'fs';
|
import * as Fs from 'fs';
|
||||||
import * as ji from 'just-indent'
|
import * as ji from 'just-indent';
|
||||||
import { GBServer } from '../../../src/app.js';
|
import { GBServer } from '../../../src/app.js';
|
||||||
import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js';
|
import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js';
|
||||||
import { CollectionUtil } from 'pragmatismo-io-framework';
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
|
@ -52,8 +52,8 @@ import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||||
import { GuaribasUser } from '../../security.gbapp/models/index.js';
|
import { GuaribasUser } from '../../security.gbapp/models/index.js';
|
||||||
import { SystemKeywords } from './SystemKeywords.js';
|
import { SystemKeywords } from './SystemKeywords.js';
|
||||||
import { Sequelize, QueryTypes } from '@sequelize/core';
|
import { Sequelize, QueryTypes } from '@sequelize/core';
|
||||||
import { z } from "zod";
|
import { z } from 'zod';
|
||||||
import { zodToJsonSchema } from "zod-to-json-schema";
|
import { zodToJsonSchema } from 'zod-to-json-schema';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview Decision was to priorize security(isolation) and debugging,
|
* @fileoverview Decision was to priorize security(isolation) and debugging,
|
||||||
|
@ -68,7 +68,8 @@ export class GBVMService extends GBService {
|
||||||
public static API_PORT = 1111;
|
public static API_PORT = 1111;
|
||||||
|
|
||||||
public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) {
|
public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) {
|
||||||
const files = await walkPromise(folder);
|
const ignore = Path.join('work', DialogKeywords.getGBAIPath(min.botId, 'gbdialog'), 'node_modules');
|
||||||
|
const files = await walkPromise(folder, { ignore: [ignore] });
|
||||||
|
|
||||||
await CollectionUtil.asyncForEach(files, async file => {
|
await CollectionUtil.asyncForEach(files, async file => {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
|
@ -77,9 +78,7 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
let filename: string = file.name;
|
let filename: string = file.name;
|
||||||
|
|
||||||
if (filename.endsWith('.docx')) {
|
|
||||||
filename = await this.loadDialog(filename, folder, min);
|
filename = await this.loadDialog(filename, folder, min);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,14 +90,11 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
//check every key for being same
|
//check every key for being same
|
||||||
return Object.keys(obj1).every(function (key) {
|
return Object.keys(obj1).every(function (key) {
|
||||||
|
|
||||||
//if object
|
//if object
|
||||||
if ((typeof obj1[key] == "object") && (typeof obj2[key] == "object")) {
|
if (typeof obj1[key] == 'object' && typeof obj2[key] == 'object') {
|
||||||
|
|
||||||
//recursively check
|
//recursively check
|
||||||
return GBVMService.compare(obj1[key], obj2[key]);
|
return GBVMService.compare(obj1[key], obj2[key]);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//do the normal compare
|
//do the normal compare
|
||||||
return obj1[key] === obj2[key];
|
return obj1[key] === obj2[key];
|
||||||
}
|
}
|
||||||
|
@ -106,14 +102,27 @@ export class GBVMService extends GBService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async loadDialog(filename: string, folder: string, min: GBMinInstance) {
|
public async loadDialog(filename: string, folder: string, min: GBMinInstance) {
|
||||||
|
const isWord = filename.endsWith('.docx');
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
isWord ||
|
||||||
|
filename.endsWith('.vbs') ||
|
||||||
|
filename.endsWith('.vb') ||
|
||||||
|
filename.endsWith('.vba') ||
|
||||||
|
filename.endsWith('.bas') ||
|
||||||
|
filename.endsWith('.basic')
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const wordFile = filename;
|
const wordFile = filename;
|
||||||
const vbsFile = filename.substr(0, filename.indexOf('docx')) + 'vbs';
|
const vbsFile = isWord ? filename.substr(0, filename.indexOf('docx')) + 'vbs' : filename;
|
||||||
const fullVbsFile = urlJoin(folder, vbsFile);
|
const fullVbsFile = urlJoin(folder, vbsFile);
|
||||||
const docxStat = Fs.statSync(urlJoin(folder, wordFile));
|
const docxStat = Fs.statSync(urlJoin(folder, wordFile));
|
||||||
const interval = 3000; // If compiled is older 30 seconds, then recompile.
|
const interval = 3000; // If compiled is older 30 seconds, then recompile.
|
||||||
let writeVBS = true;
|
let writeVBS = true;
|
||||||
|
|
||||||
|
|
||||||
// TODO: #412.
|
// TODO: #412.
|
||||||
// const subscription = {
|
// const subscription = {
|
||||||
// changeType: 'created,updated',
|
// changeType: 'created,updated',
|
||||||
|
@ -129,7 +138,6 @@ export class GBVMService extends GBService {
|
||||||
// await client.api('/subscriptions')
|
// await client.api('/subscriptions')
|
||||||
// .post(subscription);
|
// .post(subscription);
|
||||||
|
|
||||||
|
|
||||||
if (Fs.existsSync(fullVbsFile)) {
|
if (Fs.existsSync(fullVbsFile)) {
|
||||||
const vbsStat = Fs.statSync(fullVbsFile);
|
const vbsStat = Fs.statSync(fullVbsFile);
|
||||||
if (docxStat['mtimeMs'] < vbsStat['mtimeMs'] + interval) {
|
if (docxStat['mtimeMs'] < vbsStat['mtimeMs'] + interval) {
|
||||||
|
@ -140,26 +148,9 @@ export class GBVMService extends GBService {
|
||||||
let mainName = GBVMService.getMethodNameFromVBSFilename(filename);
|
let mainName = GBVMService.getMethodNameFromVBSFilename(filename);
|
||||||
min.scriptMap[filename] = mainName;
|
min.scriptMap[filename] = mainName;
|
||||||
|
|
||||||
if (writeVBS) {
|
if (writeVBS && GBConfigService.get('STORAGE_NAME')) {
|
||||||
let text = await this.getTextFromWord(folder, wordFile);
|
let text = await this.getTextFromWord(folder, wordFile);
|
||||||
|
|
||||||
// Pre process SET SCHEDULE calls.
|
|
||||||
|
|
||||||
const schedules = GBVMService.getSetScheduleKeywordArgs(text);
|
|
||||||
|
|
||||||
const s = new ScheduleServices();
|
|
||||||
await s.deleteScheduleIfAny(min, mainName);
|
|
||||||
|
|
||||||
let i = 1;
|
|
||||||
await CollectionUtil.asyncForEach(schedules, async (syntax) => {
|
|
||||||
|
|
||||||
if (s) {
|
|
||||||
await s.createOrUpdateSchedule(min, syntax, `${mainName};${i++}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
text = text.replace(/^\s*SET SCHEDULE (.*)/gim, '');
|
|
||||||
|
|
||||||
// Write VBS file without pragma keywords.
|
// Write VBS file without pragma keywords.
|
||||||
|
|
||||||
Fs.writeFileSync(urlJoin(folder, vbsFile), text);
|
Fs.writeFileSync(urlJoin(folder, vbsFile), text);
|
||||||
|
@ -167,6 +158,41 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
// Process node_modules install.
|
// Process node_modules install.
|
||||||
|
|
||||||
|
this.processNodeModules(folder, min);
|
||||||
|
|
||||||
|
// Hot swap for .vbs files.
|
||||||
|
|
||||||
|
const fullFilename = urlJoin(folder, filename);
|
||||||
|
if (process.env.DEV_HOTSWAP) {
|
||||||
|
Fs.watchFile(fullFilename, async () => {
|
||||||
|
await this.translateBASIC(mainName, fullFilename, min);
|
||||||
|
const parsedCode: string = Fs.readFileSync(jsfile, 'utf8');
|
||||||
|
min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const compiledAt = Fs.statSync(fullFilename);
|
||||||
|
const jsfile = urlJoin(folder, `${filename}.js`);
|
||||||
|
|
||||||
|
if (Fs.existsSync(jsfile)) {
|
||||||
|
const jsStat = Fs.statSync(jsfile);
|
||||||
|
const interval = 1000; // If compiled is older 1 seconds, then recompile.
|
||||||
|
if (compiledAt.isFile() && compiledAt['mtimeMs'] > jsStat['mtimeMs'] + interval) {
|
||||||
|
await this.translateBASIC(mainName, fullFilename, min);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await this.translateBASIC(mainName, fullFilename, min);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Syncronizes Database Objects with the ones returned from "Word".
|
||||||
|
|
||||||
|
this.syncStorageFromTABLE(folder, filename, min, mainName);
|
||||||
|
|
||||||
|
const parsedCode: string = Fs.readFileSync(jsfile, 'utf8');
|
||||||
|
min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode;
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
private processNodeModules(folder: string, min: GBMinInstance) {
|
||||||
const node_modules = urlJoin(process.env.PWD, folder, 'node_modules');
|
const node_modules = urlJoin(process.env.PWD, folder, 'node_modules');
|
||||||
if (!Fs.existsSync(node_modules)) {
|
if (!Fs.existsSync(node_modules)) {
|
||||||
const packageJson = `
|
const packageJson = `
|
||||||
|
@ -193,33 +219,9 @@ export class GBVMService extends GBService {
|
||||||
const npmPath = urlJoin(process.env.PWD, 'node_modules', '.bin', 'npm');
|
const npmPath = urlJoin(process.env.PWD, 'node_modules', '.bin', 'npm');
|
||||||
child_process.execSync(`${npmPath} install`, { cwd: folder });
|
child_process.execSync(`${npmPath} install`, { cwd: folder });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hot swap for .vbs files.
|
|
||||||
|
|
||||||
const fullFilename = urlJoin(folder, filename);
|
|
||||||
if (process.env.DEV_HOTSWAP) {
|
|
||||||
Fs.watchFile(fullFilename, async () => {
|
|
||||||
await this.translateBASIC(mainName, fullFilename, min);
|
|
||||||
const parsedCode: string = Fs.readFileSync(jsfile, 'utf8');
|
|
||||||
min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const compiledAt = Fs.statSync(fullFilename);
|
private syncStorageFromTABLE(folder: string, filename: string, min: GBMinInstance, mainName: string) {
|
||||||
const jsfile = urlJoin(folder, `${filename}.js`);
|
|
||||||
|
|
||||||
if (Fs.existsSync(jsfile)) {
|
|
||||||
const jsStat = Fs.statSync(jsfile);
|
|
||||||
const interval = 30000; // If compiled is older 30 seconds, then recompile.
|
|
||||||
if (compiledAt.isFile() && compiledAt['mtimeMs'] > jsStat['mtimeMs'] + interval) {
|
|
||||||
await this.translateBASIC(mainName, fullFilename, min);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await this.translateBASIC(mainName, fullFilename, min);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Syncronizes Database Objects with the ones returned from "Word".
|
|
||||||
|
|
||||||
const tablesFile = urlJoin(folder, `${filename}.tables.json`);
|
const tablesFile = urlJoin(folder, `${filename}.tables.json`);
|
||||||
let sync = false;
|
let sync = false;
|
||||||
|
|
||||||
|
@ -229,7 +231,6 @@ export class GBVMService extends GBService {
|
||||||
const tableDef = JSON.parse(Fs.readFileSync(tablesFile, 'utf8')) as any;
|
const tableDef = JSON.parse(Fs.readFileSync(tablesFile, 'utf8')) as any;
|
||||||
|
|
||||||
const getTypeBasedOnCondition = (t, size) => {
|
const getTypeBasedOnCondition = (t, size) => {
|
||||||
|
|
||||||
if (1) {
|
if (1) {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case 'string':
|
case 'string':
|
||||||
|
@ -253,7 +254,6 @@ export class GBVMService extends GBService {
|
||||||
default:
|
default:
|
||||||
return { type: 'TABLE', name: t };
|
return { type: 'TABLE', name: t };
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case 'string':
|
case 'string':
|
||||||
|
@ -277,43 +277,34 @@ export class GBVMService extends GBService {
|
||||||
default:
|
default:
|
||||||
return { key: 'TABLE', name: t };
|
return { key: 'TABLE', name: t };
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const associations = [];
|
const associations = [];
|
||||||
|
|
||||||
// Loads storage custom connections.
|
// Loads storage custom connections.
|
||||||
|
|
||||||
const path = DialogKeywords.getGBAIPath(min.botId, null);
|
const path = DialogKeywords.getGBAIPath(min.botId, null);
|
||||||
const filePath = Path.join('work', path, 'connections.json');
|
const filePath = Path.join('work', path, 'connections.json');
|
||||||
let connections = null;
|
let connections = null;
|
||||||
if (Fs.existsSync(filePath)) {
|
if (Fs.existsSync(filePath)) {
|
||||||
connections = JSON.parse(Fs.readFileSync(filePath, 'utf8'));
|
connections = JSON.parse(Fs.readFileSync(filePath, 'utf8'));
|
||||||
}
|
}
|
||||||
const shouldSync = min.core.getParam<boolean>(
|
const shouldSync = min.core.getParam<boolean>(min.instance, 'Synchronize Database', false);
|
||||||
min.instance,
|
|
||||||
'Synchronize Database',
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
tableDef.forEach(async t => {
|
tableDef.forEach(async t => {
|
||||||
|
|
||||||
const tableName = t.name.trim();
|
const tableName = t.name.trim();
|
||||||
|
|
||||||
// Determines autorelationship.
|
// Determines autorelationship.
|
||||||
|
|
||||||
Object.keys(t.fields).forEach(key => {
|
Object.keys(t.fields).forEach(key => {
|
||||||
let obj = t.fields[key];
|
let obj = t.fields[key];
|
||||||
obj.type = getTypeBasedOnCondition(obj.type, obj.size);
|
obj.type = getTypeBasedOnCondition(obj.type, obj.size);
|
||||||
if (obj.type.key === "TABLE") {
|
if (obj.type.key === 'TABLE') {
|
||||||
obj.type.key = "BIGINT"
|
obj.type.key = 'BIGINT';
|
||||||
associations.push({ from: tableName, to: obj.type.name });
|
associations.push({ from: tableName, to: obj.type.name });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cutom connection for TABLE.
|
// Cutom connection for TABLE.
|
||||||
|
|
||||||
const connectionName = t.connection;
|
const connectionName = t.connection;
|
||||||
let con;
|
let con;
|
||||||
|
|
||||||
|
@ -367,11 +358,12 @@ export class GBVMService extends GBService {
|
||||||
if (!min[connectionName]) {
|
if (!min[connectionName]) {
|
||||||
GBLogEx.info(min, `Loading custom connection ${connectionName}...`);
|
GBLogEx.info(min, `Loading custom connection ${connectionName}...`);
|
||||||
min[connectionName] = new Sequelize(storageName, username, password, sequelizeOptions);
|
min[connectionName] = new Sequelize(storageName, username, password, sequelizeOptions);
|
||||||
min[`llmconnection`] ={
|
min[`llmconnection`] = {
|
||||||
type: dialect,
|
type: dialect,
|
||||||
username,
|
username,
|
||||||
database: storageName, password};
|
database: storageName,
|
||||||
|
password
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,27 +372,22 @@ export class GBVMService extends GBService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Field checking, syncs if there is any difference.
|
// Field checking, syncs if there is any difference.
|
||||||
|
const seq = min[connectionName] ? min[connectionName] : minBoot.core.sequelize;
|
||||||
const seq = min[connectionName] ? min[connectionName]
|
|
||||||
: minBoot.core.sequelize;
|
|
||||||
|
|
||||||
if (seq) {
|
if (seq) {
|
||||||
|
|
||||||
const model = seq.models[tableName];
|
const model = seq.models[tableName];
|
||||||
if (model) {
|
if (model) {
|
||||||
// Except Id, checks if has same number of fields.
|
// Except Id, checks if has same number of fields.
|
||||||
|
|
||||||
let equals = 0;
|
let equals = 0;
|
||||||
Object.keys(t.fields).forEach(key => {
|
Object.keys(t.fields).forEach(key => {
|
||||||
let obj1 = t.fields[key];
|
let obj1 = t.fields[key];
|
||||||
let obj2 = model['fieldRawAttributesMap'][key];
|
let obj2 = model['fieldRawAttributesMap'][key];
|
||||||
|
|
||||||
if (key !== "id") {
|
if (key !== 'id') {
|
||||||
if (obj1 && obj2) {
|
if (obj1 && obj2) {
|
||||||
equals++;
|
equals++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (equals != Object.keys(t.fields).length) {
|
if (equals != Object.keys(t.fields).length) {
|
||||||
|
@ -414,19 +401,21 @@ export class GBVMService extends GBService {
|
||||||
let tables;
|
let tables;
|
||||||
|
|
||||||
if (con.storageDriver === 'mssql') {
|
if (con.storageDriver === 'mssql') {
|
||||||
tables = await seq.query(`SELECT table_name, table_schema
|
tables = await seq.query(
|
||||||
|
`SELECT table_name, table_schema
|
||||||
FROM information_schema.tables
|
FROM information_schema.tables
|
||||||
WHERE table_type = 'BASE TABLE'
|
WHERE table_type = 'BASE TABLE'
|
||||||
ORDER BY table_name ASC`, {
|
ORDER BY table_name ASC`,
|
||||||
|
{
|
||||||
type: QueryTypes.RAW
|
type: QueryTypes.RAW
|
||||||
})[0]
|
|
||||||
}
|
}
|
||||||
else if (con.storageDriver === 'mariadb') {
|
)[0];
|
||||||
|
} else if (con.storageDriver === 'mariadb') {
|
||||||
tables = await seq.getQueryInterface().showAllTables();
|
tables = await seq.getQueryInterface().showAllTables();
|
||||||
}
|
}
|
||||||
|
|
||||||
let found = false;
|
let found = false;
|
||||||
tables.forEach((storageTable) => {
|
tables.forEach(storageTable => {
|
||||||
if (storageTable['table_name'] === tableName) {
|
if (storageTable['table_name'] === tableName) {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
@ -441,15 +430,17 @@ export class GBVMService extends GBService {
|
||||||
try {
|
try {
|
||||||
to.hasMany(from);
|
to.hasMany(from);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`BASIC: Invalid relationship in ${mainName}: from ${e.from} to ${e.to} (${min.botId})... ${error.message}`);
|
throw new Error(
|
||||||
|
`BASIC: Invalid relationship in ${mainName}: from ${e.from} to ${e.to} (${min.botId})... ${error.message}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (sync && shouldSync) {
|
if (sync && shouldSync) {
|
||||||
|
GBLogEx.info(
|
||||||
GBLogEx.info(min, `BASIC: Syncing changes for TABLE ${connectionName} ${tableName} keyword (${min.botId})...`);
|
min,
|
||||||
|
`BASIC: Syncing changes for TABLE ${connectionName} ${tableName} keyword (${min.botId})...`
|
||||||
|
);
|
||||||
|
|
||||||
await seq.sync({
|
await seq.sync({
|
||||||
alter: true,
|
alter: true,
|
||||||
|
@ -460,18 +451,29 @@ export class GBVMService extends GBService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedCode: string = Fs.readFileSync(jsfile, 'utf8');
|
|
||||||
min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode;
|
|
||||||
return filename;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async translateBASIC(mainName, filename: any, min: GBMinInstance) {
|
public async translateBASIC(mainName, filename: any, min: GBMinInstance) {
|
||||||
|
|
||||||
// Converts General Bots BASIC into regular VBS
|
// Converts General Bots BASIC into regular VBS
|
||||||
|
|
||||||
let basicCode: string = Fs.readFileSync(filename, 'utf8');
|
let basicCode: string = Fs.readFileSync(filename, 'utf8');
|
||||||
|
|
||||||
|
// Pre process SET SCHEDULE calls.
|
||||||
|
|
||||||
|
const schedules = GBVMService.getSetScheduleKeywordArgs(basicCode);
|
||||||
|
|
||||||
|
const s = new ScheduleServices();
|
||||||
|
await s.deleteScheduleIfAny(min, mainName);
|
||||||
|
|
||||||
|
let i = 1;
|
||||||
|
await CollectionUtil.asyncForEach(schedules, async syntax => {
|
||||||
|
if (s) {
|
||||||
|
await s.createOrUpdateSchedule(min, syntax, `${mainName};${i++}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
basicCode = basicCode.replace(/^\s*SET SCHEDULE (.*)/gim, '');
|
||||||
|
|
||||||
// Process INCLUDE keyword to include another
|
// Process INCLUDE keyword to include another
|
||||||
// dialog inside the dialog.
|
// dialog inside the dialog.
|
||||||
|
|
||||||
|
@ -712,7 +714,6 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
Fs.writeFileSync(jsfile, code);
|
Fs.writeFileSync(jsfile, code);
|
||||||
GBLogEx.info(min, `[GBVMService] Finished loading of ${filename}, JavaScript from Word: \n ${code}`);
|
GBLogEx.info(min, `[GBVMService] Finished loading of ${filename}, JavaScript from Word: \n ${code}`);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async executeTasks(min, tasks) {
|
private async executeTasks(min, tasks) {
|
||||||
|
@ -720,12 +721,10 @@ export class GBVMService extends GBService {
|
||||||
const task = tasks[i];
|
const task = tasks[i];
|
||||||
|
|
||||||
if (task.kind === 'writeTableDefinition') {
|
if (task.kind === 'writeTableDefinition') {
|
||||||
|
|
||||||
// Creates an empty object that will receive Sequelize fields.
|
// Creates an empty object that will receive Sequelize fields.
|
||||||
|
|
||||||
const tablesFile = `${task.file}.tables.json`;
|
const tablesFile = `${task.file}.tables.json`;
|
||||||
Fs.writeFileSync(tablesFile, JSON.stringify(task.tables));
|
Fs.writeFileSync(tablesFile, JSON.stringify(task.tables));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -744,10 +743,10 @@ export class GBVMService extends GBService {
|
||||||
lines.forEach(line => {
|
lines.forEach(line => {
|
||||||
if (line.trim()) {
|
if (line.trim()) {
|
||||||
console.log(line);
|
console.log(line);
|
||||||
const keyword = /\s*SET SCHEDULE (.*)/gi;
|
const keyword = /^\s*SET SCHEDULE (.*)/gi;
|
||||||
let result: any = keyword.exec(line);
|
let result: any = keyword.exec(line);
|
||||||
if (result) {
|
if (result) {
|
||||||
result = result[1].replace(/\`|\"|\'/, '')
|
result = result[1].replace(/\`|\"|\'/, '');
|
||||||
result = result.trim();
|
result = result.trim();
|
||||||
results.push(result);
|
results.push(result);
|
||||||
}
|
}
|
||||||
|
@ -756,6 +755,7 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getTextFromWord(folder: string, filename: string) {
|
private async getTextFromWord(folder: string, filename: string) {
|
||||||
return new Promise<string>(async (resolve, reject) => {
|
return new Promise<string>(async (resolve, reject) => {
|
||||||
const path = urlJoin(folder, filename);
|
const path = urlJoin(folder, filename);
|
||||||
|
@ -777,7 +777,6 @@ export class GBVMService extends GBService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static normalizeQuotes(text: any) {
|
public static normalizeQuotes(text: any) {
|
||||||
|
|
||||||
text = text.replace(/\"/gm, '`');
|
text = text.replace(/\"/gm, '`');
|
||||||
text = text.replace(/\¨/gm, '`');
|
text = text.replace(/\¨/gm, '`');
|
||||||
text = text.replace(/\“/gm, '`');
|
text = text.replace(/\“/gm, '`');
|
||||||
|
@ -791,27 +790,22 @@ export class GBVMService extends GBService {
|
||||||
public static getMetadata(mainName: string, propertiesText, description) {
|
public static getMetadata(mainName: string, propertiesText, description) {
|
||||||
let properties = {};
|
let properties = {};
|
||||||
if (!propertiesText || !description) {
|
if (!propertiesText || !description) {
|
||||||
|
return {};
|
||||||
return {}
|
|
||||||
}
|
}
|
||||||
const getType = asClause => {
|
const getType = asClause => {
|
||||||
|
|
||||||
asClause = asClause.trim().toUpperCase();
|
asClause = asClause.trim().toUpperCase();
|
||||||
|
|
||||||
if (asClause.indexOf('STRING') !== -1) {
|
if (asClause.indexOf('STRING') !== -1) {
|
||||||
return 'string';
|
return 'string';
|
||||||
}
|
} else if (asClause.indexOf('OBJECT') !== -1) {
|
||||||
else if (asClause.indexOf('OBJECT') !== -1) {
|
|
||||||
return 'object';
|
return 'object';
|
||||||
}
|
} else if (asClause.indexOf('INTEGER') !== -1 || asClause.indexOf('NUMBER') !== -1) {
|
||||||
else if (asClause.indexOf('INTEGER') !== -1 || asClause.indexOf('NUMBER') !== -1) {
|
|
||||||
return 'number';
|
return 'number';
|
||||||
} else {
|
} else {
|
||||||
return 'enum';
|
return 'enum';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
for (let i = 0; i < propertiesText.length; i++) {
|
for (let i = 0; i < propertiesText.length; i++) {
|
||||||
const propertiesExp = propertiesText[i];
|
const propertiesExp = propertiesText[i];
|
||||||
const t = getType(propertiesExp[2]);
|
const t = getType(propertiesExp[2]);
|
||||||
|
@ -834,21 +828,19 @@ export class GBVMService extends GBService {
|
||||||
properties[propertiesExp[1].trim()] = element;
|
properties[propertiesExp[1].trim()] = element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let json = {
|
let json = {
|
||||||
type: "function",
|
type: 'function',
|
||||||
function: {
|
function: {
|
||||||
name: `${mainName}`,
|
name: `${mainName}`,
|
||||||
description: description ? description : '',
|
description: description ? description : '',
|
||||||
parameters: zodToJsonSchema(z.object(properties))
|
parameters: zodToJsonSchema(z.object(properties))
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async parseField(line) {
|
public async parseField(line) {
|
||||||
|
|
||||||
let required = line.indexOf('*') !== -1;
|
let required = line.indexOf('*') !== -1;
|
||||||
let unique = /\bunique\b/gi.test(line);
|
let unique = /\bunique\b/gi.test(line);
|
||||||
let primaryKey = /\bkey\b/gi.test(line);
|
let primaryKey = /\bkey\b/gi.test(line);
|
||||||
|
@ -870,7 +862,8 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
let definition = {
|
let definition = {
|
||||||
allowNull: !required,
|
allowNull: !required,
|
||||||
unique: unique, primaryKey: primaryKey,
|
unique: unique,
|
||||||
|
primaryKey: primaryKey,
|
||||||
autoIncrement: autoIncrement
|
autoIncrement: autoIncrement
|
||||||
};
|
};
|
||||||
definition['type'] = t;
|
definition['type'] = t;
|
||||||
|
@ -889,7 +882,6 @@ export class GBVMService extends GBService {
|
||||||
* @param code General Bots BASIC
|
* @param code General Bots BASIC
|
||||||
*/
|
*/
|
||||||
public async convert(filename: string, mainName: string, code: string) {
|
public async convert(filename: string, mainName: string, code: string) {
|
||||||
|
|
||||||
// Start and End of VB2TS tags of processing.
|
// Start and End of VB2TS tags of processing.
|
||||||
|
|
||||||
code = process.env.ENABLE_AUTH ? `hear GBLogExin as login\n${code}` : code;
|
code = process.env.ENABLE_AUTH ? `hear GBLogExin as login\n${code}` : code;
|
||||||
|
@ -910,7 +902,6 @@ export class GBVMService extends GBService {
|
||||||
const outputLines = [];
|
const outputLines = [];
|
||||||
let emmitIndex = 1;
|
let emmitIndex = 1;
|
||||||
for (let i = 1; i <= lines.length; i++) {
|
for (let i = 1; i <= lines.length; i++) {
|
||||||
|
|
||||||
let line = lines[i - 1];
|
let line = lines[i - 1];
|
||||||
|
|
||||||
// Remove lines before statements.
|
// Remove lines before statements.
|
||||||
|
@ -961,12 +952,12 @@ export class GBVMService extends GBService {
|
||||||
const endTableKeyword = /^\s*END TABLE\s*/gim;
|
const endTableKeyword = /^\s*END TABLE\s*/gim;
|
||||||
let endTableReg = endTableKeyword.exec(line);
|
let endTableReg = endTableKeyword.exec(line);
|
||||||
if (endTableReg && table) {
|
if (endTableReg && table) {
|
||||||
|
|
||||||
tables.push({
|
tables.push({
|
||||||
name: table, fields: fields, connection: connection
|
name: table,
|
||||||
|
fields: fields,
|
||||||
|
connection: connection
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
fields = {};
|
fields = {};
|
||||||
table = null;
|
table = null;
|
||||||
connection = null;
|
connection = null;
|
||||||
|
@ -1006,14 +997,14 @@ export class GBVMService extends GBService {
|
||||||
const talkKeyword = /^\s*BEGIN TALK\s*/gim;
|
const talkKeyword = /^\s*BEGIN TALK\s*/gim;
|
||||||
let talkReg = talkKeyword.exec(line);
|
let talkReg = talkKeyword.exec(line);
|
||||||
if (talkReg && !talk) {
|
if (talkReg && !talk) {
|
||||||
talk = "await dk.talk ({pid: pid, text: `";
|
talk = 'await dk.talk ({pid: pid, text: `';
|
||||||
emmit = false;
|
emmit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const systemPromptKeyword = /^\s*BEGIN SYSTEM PROMPT\s*/gim;
|
const systemPromptKeyword = /^\s*BEGIN SYSTEM PROMPT\s*/gim;
|
||||||
let systemPromptReg = systemPromptKeyword.exec(line);
|
let systemPromptReg = systemPromptKeyword.exec(line);
|
||||||
if (systemPromptReg && !systemPrompt) {
|
if (systemPromptReg && !systemPrompt) {
|
||||||
systemPrompt = "await sys.setSystemPrompt ({pid: pid, text: `";
|
systemPrompt = 'await sys.setSystemPrompt ({pid: pid, text: `';
|
||||||
emmit = false;
|
emmit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1031,9 +1022,10 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
if (tables) {
|
if (tables) {
|
||||||
tasks.push({
|
tasks.push({
|
||||||
kind: 'writeTableDefinition', file: filename, tables
|
kind: 'writeTableDefinition',
|
||||||
|
file: filename,
|
||||||
|
tables
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
code = `${outputLines.join('\n')}\n`;
|
code = `${outputLines.join('\n')}\n`;
|
||||||
|
@ -1046,14 +1038,7 @@ export class GBVMService extends GBService {
|
||||||
/**
|
/**
|
||||||
* Executes the converted JavaScript from BASIC code inside execution context.
|
* Executes the converted JavaScript from BASIC code inside execution context.
|
||||||
*/
|
*/
|
||||||
public static async callVM(
|
public static async callVM(text: string, min: GBMinInstance, step, pid, debug: boolean = false, params = []) {
|
||||||
text: string,
|
|
||||||
min: GBMinInstance,
|
|
||||||
step,
|
|
||||||
pid,
|
|
||||||
debug: boolean = false,
|
|
||||||
params = []
|
|
||||||
) {
|
|
||||||
// Creates a class DialogKeywords which is the *this* pointer
|
// Creates a class DialogKeywords which is the *this* pointer
|
||||||
// in BASIC.
|
// in BASIC.
|
||||||
|
|
||||||
|
@ -1069,8 +1054,7 @@ export class GBVMService extends GBService {
|
||||||
// These variables will be automatically be available as normal BASIC variables.
|
// These variables will be automatically be available as normal BASIC variables.
|
||||||
|
|
||||||
try {
|
try {
|
||||||
variables['aadToken'] = await (min.adminService as any)['acquireElevatedToken']
|
variables['aadToken'] = await (min.adminService as any)['acquireElevatedToken'](min.instance.instanceId, false);
|
||||||
(min.instance.instanceId, false);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
variables['aadToken'] = 'ERROR: Configure /setupSecurity before using aadToken variable.';
|
variables['aadToken'] = 'ERROR: Configure /setupSecurity before using aadToken variable.';
|
||||||
}
|
}
|
||||||
|
@ -1111,12 +1095,10 @@ export class GBVMService extends GBService {
|
||||||
let code = min.sandBoxMap[text];
|
let code = min.sandBoxMap[text];
|
||||||
const channel = step ? step.context.activity.channelId : 'web';
|
const channel = step ? step.context.activity.channelId : 'web';
|
||||||
|
|
||||||
|
|
||||||
const dk = new DialogKeywords();
|
const dk = new DialogKeywords();
|
||||||
const sys = new SystemKeywords();
|
const sys = new SystemKeywords();
|
||||||
await dk.setFilter({ pid: pid, value: null });
|
await dk.setFilter({ pid: pid, value: null });
|
||||||
|
|
||||||
|
|
||||||
// Find all tokens in .gbot Config.
|
// Find all tokens in .gbot Config.
|
||||||
|
|
||||||
const strFind = ' Client ID';
|
const strFind = ' Client ID';
|
||||||
|
@ -1152,7 +1134,7 @@ export class GBVMService extends GBService {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
sandbox['resolve'] = resolve;
|
sandbox['resolve'] = resolve;
|
||||||
// TODO: #411 sandbox['reject'] = reject;
|
// TODO: #411 sandbox['reject'] = reject;
|
||||||
sandbox['reject'] = ()=>{};
|
sandbox['reject'] = () => {};
|
||||||
|
|
||||||
const vm1 = new NodeVM({
|
const vm1 = new NodeVM({
|
||||||
allowAsync: true,
|
allowAsync: true,
|
||||||
|
@ -1169,7 +1151,6 @@ export class GBVMService extends GBService {
|
||||||
const s = new VMScript(code, { filename: scriptPath });
|
const s = new VMScript(code, { filename: scriptPath });
|
||||||
result = vm1.run(s);
|
result = vm1.run(s);
|
||||||
});
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
} else {
|
} else {
|
||||||
const runnerPath = urlJoin(
|
const runnerPath = urlJoin(
|
||||||
|
@ -1200,10 +1181,15 @@ export class GBVMService extends GBService {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`BASIC RUNTIME ERR: ${error.message ? error.message : error}\n Stack:${error.stack}`);
|
throw new Error(`BASIC RUNTIME ERR: ${error.message ? error.message : error}\n Stack:${error.stack}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createProcessInfo(user: GuaribasUser, min: GBMinInstance, channel: any, executable: string, step = null) {
|
public static createProcessInfo(
|
||||||
|
user: GuaribasUser,
|
||||||
|
min: GBMinInstance,
|
||||||
|
channel: any,
|
||||||
|
executable: string,
|
||||||
|
step = null
|
||||||
|
) {
|
||||||
const pid = GBAdminService.getNumberIdentifier();
|
const pid = GBAdminService.getNumberIdentifier();
|
||||||
GBServer.globals.processes[pid] = {
|
GBServer.globals.processes[pid] = {
|
||||||
pid: pid,
|
pid: pid,
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| ( )_ _ |
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__,\| (˅) |( (_) ) |
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
| | | ( )_) | |
|
|
||||||
| (_) \___/' |
|
|
||||||
| |
|
| |
|
||||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
| Licensed under the AGPL-3.0. |
|
| Licensed under the AGPL-3.0. |
|
||||||
| |
|
| |
|
||||||
| According to our dual licensing model,this program can be used either |
|
| According to our dual licensing model, this program can be used either |
|
||||||
| under the terms of the GNU Affero General Public License,version 3, |
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
| or under a proprietary license. |
|
| or under a proprietary license. |
|
||||||
| |
|
| |
|
||||||
| The texts of the GNU Affero General Public License with an additional |
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
@ -19,13 +17,13 @@
|
||||||
| in the LICENSE file you have received along with this program. |
|
| in the LICENSE file you have received along with this program. |
|
||||||
| |
|
| |
|
||||||
| This program is distributed in the hope that it will be useful, |
|
| This program is distributed in the hope that it will be useful, |
|
||||||
| but WITHOUT ANY WARRANTY,without even the implied warranty of |
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
| GNU Affero General Public License for more details. |
|
| GNU Affero General Public License for more details. |
|
||||||
| |
|
| |
|
||||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
| The licensing of the program under the AGPLv3 does not imply a |
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
| trademark license. Therefore any rights,title and interest in |
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
| our trademarks remain entirely with us. |
|
| our trademarks remain entirely with us. |
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
@ -35,13 +33,13 @@
|
||||||
import Path from 'path';
|
import Path from 'path';
|
||||||
import { GBLog, GBMinInstance } from 'botlib';
|
import { GBLog, GBMinInstance } from 'botlib';
|
||||||
import { DialogKeywords } from './DialogKeywords.js';
|
import { DialogKeywords } from './DialogKeywords.js';
|
||||||
import sharp from 'sharp';
|
|
||||||
import joinImages from 'join-images-updated';
|
import joinImages from 'join-images-updated';
|
||||||
import { CollectionUtil } from 'pragmatismo-io-framework';
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
||||||
import urlJoin from 'url-join';
|
import urlJoin from 'url-join';
|
||||||
import { GBServer } from '../../../src/app.js';
|
import { GBServer } from '../../../src/app.js';
|
||||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||||
|
import sharp from 'sharp';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image processing services of conversation to be called by BASIC.
|
* Image processing services of conversation to be called by BASIC.
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| ( )_ _ |
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
| _ _ _ __ _ _ __ __ __ _ _ | ,_)(_) __ __ _ |
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__,\| (˅) |( (_) ) |
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(___/(_) (_)`\__/' |
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
| | | ( )_) | |
|
|
||||||
| (_) \__/' |
|
|
||||||
| |
|
| |
|
||||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
| Licensed under the AGPL-3.0. |
|
| Licensed under the AGPL-3.0. |
|
||||||
| |
|
| |
|
||||||
| According to our dual licensing model,this program can be used either |
|
| According to our dual licensing model, this program can be used either |
|
||||||
| under the terms of the GNU Affero General Public License,version 3, |
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
| or under a proprietary license. |
|
| or under a proprietary license. |
|
||||||
| |
|
| |
|
||||||
| The texts of the GNU Affero General Public License with an additional |
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
@ -19,17 +17,18 @@
|
||||||
| in the LICENSE file you have received along with this program. |
|
| in the LICENSE file you have received along with this program. |
|
||||||
| |
|
| |
|
||||||
| This program is distributed in the hope that it will be useful, |
|
| This program is distributed in the hope that it will be useful, |
|
||||||
| but WITHOUT ANY WARRANTY,without even the implied warranty of |
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
| GNU Affero General Public License for more details. |
|
| GNU Affero General Public License for more details. |
|
||||||
| |
|
| |
|
||||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
| The licensing of the program under the AGPLv3 does not imply a |
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
| trademark license. Therefore any rights,title and interest in |
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
| our trademarks remain entirely with us. |
|
| our trademarks remain entirely with us. |
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
||||||
|
|
|
@ -47,15 +47,14 @@ import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||||
* Basic services for BASIC manipulation.
|
* Basic services for BASIC manipulation.
|
||||||
*/
|
*/
|
||||||
export class ScheduleServices extends GBService {
|
export class ScheduleServices extends GBService {
|
||||||
|
|
||||||
public async deleteScheduleIfAny(min: GBMinInstance, name: string) {
|
public async deleteScheduleIfAny(min: GBMinInstance, name: string) {
|
||||||
|
|
||||||
let i = 1;
|
let i = 1;
|
||||||
while (i <= 10) {
|
while (i <= 10) {
|
||||||
const task = min['scheduleMap'] ? min['scheduleMap'][name + i] : null;
|
const task = min['scheduleMap'] ? min['scheduleMap'][name + i] : null;
|
||||||
|
|
||||||
if (task) {
|
if (task) {
|
||||||
task.destroy();
|
task.destroy();
|
||||||
|
}
|
||||||
const id = `${name};${i}`;
|
const id = `${name};${i}`;
|
||||||
|
|
||||||
delete min['scheduleMap'][id];
|
delete min['scheduleMap'][id];
|
||||||
|
@ -69,11 +68,9 @@ export class ScheduleServices extends GBService {
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
GBLogEx.info(min, `BASIC: Removed ${name} SET SCHEDULE and ${count} rows from storage on: ${min.botId}...`);
|
GBLogEx.info(min, `BASIC: Removed ${name} SET SCHEDULE and ${count} rows from storage on: ${min.botId}...`);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -113,12 +110,10 @@ export class ScheduleServices extends GBService {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let lastName = '';
|
let lastName = '';
|
||||||
|
|
||||||
await CollectionUtil.asyncForEach(schedules, async (item) => {
|
await CollectionUtil.asyncForEach(schedules, async item => {
|
||||||
|
|
||||||
if (item.name === lastName) {
|
if (item.name === lastName) {
|
||||||
item.name = item.name + ++i;
|
item.name = item.name + ++i;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +164,6 @@ export class ScheduleServices extends GBService {
|
||||||
},
|
},
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
GBLogEx.error(min, `Running .gbdialog word ${item.name} : ${error}...`);
|
GBLogEx.error(min, `Running .gbdialog word ${item.name} : ${error}...`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ export class SystemKeywords {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async append({ pid, args }) {
|
public async append({ pid, args }) {
|
||||||
|
if (!args) return [];
|
||||||
let array = [].concat(...args);
|
let array = [].concat(...args);
|
||||||
return array.filter(function (item, pos) {
|
return array.filter(function (item, pos) {
|
||||||
return item;
|
return item;
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| ( )_ _ |
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__,\| (˅) |( (_) ) |
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
| | | ( )_) | |
|
|
||||||
| (_) \___/' |
|
|
||||||
| |
|
| |
|
||||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
| Licensed under the AGPL-3.0. |
|
| Licensed under the AGPL-3.0. |
|
||||||
| |
|
| |
|
||||||
| According to our dual licensing model,this program can be used either |
|
| According to our dual licensing model, this program can be used either |
|
||||||
| under the terms of the GNU Affero General Public License,version 3, |
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
| or under a proprietary license. |
|
| or under a proprietary license. |
|
||||||
| |
|
| |
|
||||||
| The texts of the GNU Affero General Public License with an additional |
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
@ -19,13 +17,13 @@
|
||||||
| in the LICENSE file you have received along with this program. |
|
| in the LICENSE file you have received along with this program. |
|
||||||
| |
|
| |
|
||||||
| This program is distributed in the hope that it will be useful, |
|
| This program is distributed in the hope that it will be useful, |
|
||||||
| but WITHOUT ANY WARRANTY,without even the implied warranty of |
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
| GNU Affero General Public License for more details. |
|
| GNU Affero General Public License for more details. |
|
||||||
| |
|
| |
|
||||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
| The licensing of the program under the AGPLv3 does not imply a |
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
| trademark license. Therefore any rights,title and interest in |
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
| our trademarks remain entirely with us. |
|
| our trademarks remain entirely with us. |
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
16
packages/basic.gblib/tests/DialogKeywords.test.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { expect, test } from 'vitest';
|
||||||
|
import { DialogKeywords } from '../services/DialogKeywords';
|
||||||
|
import init from '../../../.test-init'
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
const dk = new DialogKeywords();
|
||||||
|
const pid = 1;
|
||||||
|
|
||||||
|
test('TOLIST', async () => {
|
||||||
|
|
||||||
|
const obj = [{a:1, b:2}, {a:2, b:4}];
|
||||||
|
|
||||||
|
expect(await dk.getToLst({ pid, array: obj, member:'a' }))
|
||||||
|
.toBe("1,2");
|
||||||
|
});
|
43
packages/basic.gblib/tests/GBVMService.test.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import { GBVMService } from '../services/GBVMService';
|
||||||
|
import { expect, test } from 'vitest'
|
||||||
|
|
||||||
|
test('Default', () => {
|
||||||
|
|
||||||
|
|
||||||
|
const args = GBVMService.getSetScheduleKeywordArgs(`
|
||||||
|
|
||||||
|
SET SCHEDULE "0 0 */1 * * *"
|
||||||
|
SET SCHEDULE "0 0 */3 * * *"
|
||||||
|
SET SCHEDULE "0 0 */2 * * *"
|
||||||
|
SET SCHEDULE "0 0 */2 * * *"
|
||||||
|
SET SCHEDULE "0 0 */3 * * *"
|
||||||
|
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(args.length).toBe(5);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('Compare', () => {
|
||||||
|
|
||||||
|
expect(GBVMService.compare(1,1)).toBeTruthy();
|
||||||
|
expect(GBVMService.compare({a:1},{a:1})).toBeTruthy();
|
||||||
|
expect(GBVMService.compare({a:1},{a:2})).toBeFalsy();
|
||||||
|
expect(GBVMService.compare({a:1, b:2},{a:1, b:2})).toBeTruthy();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Parse Storage Field', async () => {
|
||||||
|
|
||||||
|
const s = new GBVMService();
|
||||||
|
|
||||||
|
expect(await s.parseField('name STRING(30)')).toStrictEqual({name: 'name', definition: {
|
||||||
|
allowNull: true,
|
||||||
|
unique: false, primaryKey: false,
|
||||||
|
size: 30,
|
||||||
|
autoIncrement: false,
|
||||||
|
type:"STRING"
|
||||||
|
}});
|
||||||
|
|
||||||
|
});
|
36
packages/basic.gblib/tests/SystemKeywords.test.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { GBVMService } from '../services/GBVMService';
|
||||||
|
import { expect, test } from 'vitest';
|
||||||
|
import { SystemKeywords } from '../services/SystemKeywords';
|
||||||
|
|
||||||
|
const s = new SystemKeywords();
|
||||||
|
const pid = 1;
|
||||||
|
|
||||||
|
test('APPEND', async () => {
|
||||||
|
expect(await s.append({ pid, args: [1, 1, 1, 1] })).toStrictEqual([1, 1, 1, 1]);
|
||||||
|
expect(await s.append({ pid, args: [1] })).toStrictEqual([1]);
|
||||||
|
expect(await s.append({ pid, args: [] })).toStrictEqual([]);
|
||||||
|
expect(await s.append({ pid, args: null })).toStrictEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('COMPARE', () => {
|
||||||
|
expect(GBVMService.compare(1, 1)).toBeTruthy();
|
||||||
|
expect(GBVMService.compare({ a: 1 }, { a: 1 })).toBeTruthy();
|
||||||
|
expect(GBVMService.compare({ a: 1 }, { a: 2 })).toBeFalsy();
|
||||||
|
expect(GBVMService.compare({ a: 1, b: 2 }, { a: 1, b: 2 })).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Parse Storage Field', async () => {
|
||||||
|
const s = new GBVMService();
|
||||||
|
|
||||||
|
expect(await s.parseField('name STRING(30)')).toStrictEqual({
|
||||||
|
name: 'name',
|
||||||
|
definition: {
|
||||||
|
allowNull: true,
|
||||||
|
unique: false,
|
||||||
|
primaryKey: false,
|
||||||
|
size: 30,
|
||||||
|
autoIncrement: false,
|
||||||
|
type: 'STRING'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -36,11 +36,11 @@
|
||||||
|
|
||||||
import { BotAdapter } from 'botbuilder';
|
import { BotAdapter } from 'botbuilder';
|
||||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||||
import { GBLog, GBMinInstance, IGBDialog } from 'botlib';
|
import { GBMinInstance, IGBDialog } from 'botlib';
|
||||||
import { GBServer } from '../../../src/app.js';
|
import { GBServer } from '../../../src/app.js';
|
||||||
import { GBConversationalService } from '../services/GBConversationalService.js';
|
|
||||||
import { Messages } from '../strings.js';
|
import { Messages } from '../strings.js';
|
||||||
import { GBLogEx } from '../services/GBLogEx.js';
|
import { GBLogEx } from '../services/GBLogEx.js';
|
||||||
|
import { GBConfigService } from '../services/GBConfigService.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog for Welcoming people.
|
* Dialog for Welcoming people.
|
||||||
|
@ -65,7 +65,7 @@ export class WelcomeDialog extends IGBDialog {
|
||||||
async step => {
|
async step => {
|
||||||
if (
|
if (
|
||||||
GBServer.globals.entryPointDialog !== null &&
|
GBServer.globals.entryPointDialog !== null &&
|
||||||
min.instance.botId === process.env.BOT_ID &&
|
min.instance.botId === GBConfigService.get('BOT_ID') &&
|
||||||
step.context.activity.channelId === 'webchat'
|
step.context.activity.channelId === 'webchat'
|
||||||
) {
|
) {
|
||||||
return step.replaceDialog(GBServer.globals.entryPointDialog);
|
return step.replaceDialog(GBServer.globals.entryPointDialog);
|
||||||
|
|
|
@ -42,7 +42,7 @@ import * as en from 'dotenv-extended';
|
||||||
*/
|
*/
|
||||||
export class GBConfigService {
|
export class GBConfigService {
|
||||||
public static getBoolean(value: string): boolean {
|
public static getBoolean(value: string): boolean {
|
||||||
return (this.get(value) as unknown) as boolean;
|
return this.get(value) as unknown as boolean;
|
||||||
}
|
}
|
||||||
public static getServerPort(): string {
|
public static getServerPort(): string {
|
||||||
if (process.env.PORT) {
|
if (process.env.PORT) {
|
||||||
|
@ -79,13 +79,19 @@ export class GBConfigService {
|
||||||
public static get(key: string): string | undefined {
|
public static get(key: string): string | undefined {
|
||||||
let value = GBConfigService.tryGet(key);
|
let value = GBConfigService.tryGet(key);
|
||||||
|
|
||||||
if (value === undefined) {
|
if (!value) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
case 'STORAGE_NAME':
|
||||||
|
value = null;
|
||||||
|
break;
|
||||||
case 'CLOUD_USERNAME':
|
case 'CLOUD_USERNAME':
|
||||||
value = undefined;
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
|
case 'STORAGE_LIBRARY':
|
||||||
|
value = `${process.env.HOME}/gbpackages`;
|
||||||
|
break;
|
||||||
case 'BOT_ID':
|
case 'BOT_ID':
|
||||||
value = undefined;
|
value = 'default';
|
||||||
break;
|
break;
|
||||||
case 'CLOUD_PASSWORD':
|
case 'CLOUD_PASSWORD':
|
||||||
value = undefined;
|
value = undefined;
|
||||||
|
@ -103,10 +109,10 @@ export class GBConfigService {
|
||||||
value = undefined;
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
case 'STORAGE_DIALECT':
|
case 'STORAGE_DIALECT':
|
||||||
value = undefined;
|
value = 'sqlite';
|
||||||
break;
|
break;
|
||||||
case 'STORAGE_FILE':
|
case 'STORAGE_FILE':
|
||||||
value = './guaribas.sqlite';
|
value = './data.db';
|
||||||
break;
|
break;
|
||||||
case 'GBKB_AUTO_DEPLOY':
|
case 'GBKB_AUTO_DEPLOY':
|
||||||
value = false;
|
value = false;
|
||||||
|
@ -160,7 +166,7 @@ export class GBConfigService {
|
||||||
value = true;
|
value = true;
|
||||||
break;
|
break;
|
||||||
case 'BOT_URL':
|
case 'BOT_URL':
|
||||||
value = undefined;
|
value = 'http://localhost:4242';
|
||||||
break;
|
break;
|
||||||
case 'STORAGE_SERVER':
|
case 'STORAGE_SERVER':
|
||||||
value = undefined;
|
value = undefined;
|
||||||
|
|
|
@ -341,6 +341,7 @@ export class GBConversationalService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendEvent(min: GBMinInstance, step: GBDialogStep, name: string, value: Object): Promise<any> {
|
public async sendEvent(min: GBMinInstance, step: GBDialogStep, name: string, value: Object): Promise<any> {
|
||||||
|
|
||||||
if (step.context.activity.channelId !== 'msteams' && step.context.activity.channelId !== 'omnichannel') {
|
if (step.context.activity.channelId !== 'msteams' && step.context.activity.channelId !== 'omnichannel') {
|
||||||
GBLogEx.info(
|
GBLogEx.info(
|
||||||
min,
|
min,
|
||||||
|
|
|
@ -50,6 +50,7 @@ import { GBSecurityPackage } from '../../security.gbapp/index.js';
|
||||||
import { GBWhatsappPackage } from '../../whatsapp.gblib/index.js';
|
import { GBWhatsappPackage } from '../../whatsapp.gblib/index.js';
|
||||||
import { GuaribasApplications, GuaribasInstance, GuaribasLog } from '../models/GBModel.js';
|
import { GuaribasApplications, GuaribasInstance, GuaribasLog } from '../models/GBModel.js';
|
||||||
import { GBConfigService } from './GBConfigService.js';
|
import { GBConfigService } from './GBConfigService.js';
|
||||||
|
import mkdirp from 'mkdirp';
|
||||||
import { GBAzureDeployerPackage } from '../../azuredeployer.gbapp/index.js';
|
import { GBAzureDeployerPackage } from '../../azuredeployer.gbapp/index.js';
|
||||||
import { GBSharePointPackage } from '../../sharepoint.gblib/index.js';
|
import { GBSharePointPackage } from '../../sharepoint.gblib/index.js';
|
||||||
import { CollectionUtil } from 'pragmatismo-io-framework';
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
|
@ -109,7 +110,7 @@ export class GBCoreService implements IGBCoreService {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.adminService = new GBAdminService(this);
|
this.adminService = new GBAdminService(this);
|
||||||
}
|
}
|
||||||
public async ensureInstances(instances: IGBInstance[], bootInstance: any, core: IGBCoreService) { }
|
public async ensureInstances(instances: IGBInstance[], bootInstance: any, core: IGBCoreService) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets database config and connect to storage. Currently two databases
|
* Gets database config and connect to storage. Currently two databases
|
||||||
|
@ -131,6 +132,12 @@ export class GBCoreService implements IGBCoreService {
|
||||||
password = GBConfigService.get('STORAGE_PASSWORD');
|
password = GBConfigService.get('STORAGE_PASSWORD');
|
||||||
} else if (this.dialect === 'sqlite') {
|
} else if (this.dialect === 'sqlite') {
|
||||||
storage = GBConfigService.get('STORAGE_FILE');
|
storage = GBConfigService.get('STORAGE_FILE');
|
||||||
|
|
||||||
|
if (!Fs.existsSync(storage)){
|
||||||
|
process.env.STORAGE_SYNC = 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Unknown dialect: ${this.dialect}.`);
|
throw new Error(`Unknown dialect: ${this.dialect}.`);
|
||||||
}
|
}
|
||||||
|
@ -231,12 +238,11 @@ export class GBCoreService implements IGBCoreService {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all items to start several listeners.
|
* Loads all items to start several listeners.
|
||||||
*/
|
*/
|
||||||
public async loadInstances(): Promise<IGBInstance[]> {
|
public async loadInstances(): Promise<IGBInstance[]> {
|
||||||
if (process.env.LOAD_ONLY !== undefined) {
|
if (process.env.LOAD_ONLY) {
|
||||||
const bots = process.env.LOAD_ONLY.split(`;`);
|
const bots = process.env.LOAD_ONLY.split(`;`);
|
||||||
const and = [];
|
const and = [];
|
||||||
await CollectionUtil.asyncForEach(bots, async e => {
|
await CollectionUtil.asyncForEach(bots, async e => {
|
||||||
|
@ -426,12 +432,11 @@ ENDPOINT_UPDATE=true
|
||||||
let instances: IGBInstance[];
|
let instances: IGBInstance[];
|
||||||
try {
|
try {
|
||||||
instances = await core.loadInstances();
|
instances = await core.loadInstances();
|
||||||
const group = GBConfigService.get('CLOUD_GROUP')??GBConfigService.get('BOT_ID');
|
|
||||||
if (process.env.ENDPOINT_UPDATE === 'true') {
|
if (process.env.ENDPOINT_UPDATE === 'true') {
|
||||||
|
const group = GBConfigService.get('CLOUD_GROUP') ?? GBConfigService.get('BOT_ID');
|
||||||
await CollectionUtil.asyncForEach(instances, async instance => {
|
await CollectionUtil.asyncForEach(instances, async instance => {
|
||||||
GBLogEx.info(instance.instanceId, `Updating bot endpoint for ${instance.botId}...`);
|
GBLogEx.info(instance.instanceId, `Updating bot endpoint for ${instance.botId}...`);
|
||||||
try {
|
try {
|
||||||
|
|
||||||
await installationDeployer.updateBotProxy(
|
await installationDeployer.updateBotProxy(
|
||||||
instance.botId,
|
instance.botId,
|
||||||
group,
|
group,
|
||||||
|
@ -459,7 +464,10 @@ ENDPOINT_UPDATE=true
|
||||||
Try setting STORAGE_SYNC to true in .env file. Error: ${error.message}.`
|
Try setting STORAGE_SYNC to true in .env file. Error: ${error.message}.`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
GBLogEx.info(0, `Storage is empty. After collecting storage structure from all .gbapps it will get synced.`);
|
GBLogEx.info(
|
||||||
|
0,
|
||||||
|
`Storage is empty. After collecting storage structure from all .gbapps it will get synced.`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Cannot connect to operating storage: ${error.message}.`);
|
throw new Error(`Cannot connect to operating storage: ${error.message}.`);
|
||||||
|
@ -512,14 +520,7 @@ ENDPOINT_UPDATE=true
|
||||||
* before starting the server.
|
* before starting the server.
|
||||||
*/
|
*/
|
||||||
public ensureAdminIsSecured() {
|
public ensureAdminIsSecured() {
|
||||||
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.'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public async createBootInstance(
|
public async createBootInstance(
|
||||||
core: GBCoreService,
|
core: GBCoreService,
|
||||||
|
@ -529,9 +530,10 @@ ENDPOINT_UPDATE=true
|
||||||
return await this.createBootInstanceEx(
|
return await this.createBootInstanceEx(
|
||||||
core,
|
core,
|
||||||
installationDeployer,
|
installationDeployer,
|
||||||
proxyAddress, null,
|
proxyAddress,
|
||||||
GBConfigService.get('FREE_TIER'));
|
null,
|
||||||
|
GBConfigService.get('FREE_TIER')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Creates the first bot instance (boot instance) used to "boot" the server.
|
* Creates the first bot instance (boot instance) used to "boot" the server.
|
||||||
|
@ -548,8 +550,10 @@ ENDPOINT_UPDATE=true
|
||||||
) {
|
) {
|
||||||
GBLogEx.info(0, `Deploying cognitive infrastructure (on the cloud / on premises)...`);
|
GBLogEx.info(0, `Deploying cognitive infrastructure (on the cloud / on premises)...`);
|
||||||
try {
|
try {
|
||||||
const { instance, credentials, subscriptionId, installationDeployer }
|
const { instance, credentials, subscriptionId, installationDeployer } = await StartDialog.createBaseInstance(
|
||||||
= await StartDialog.createBaseInstance(deployer, freeTier);
|
deployer,
|
||||||
|
freeTier
|
||||||
|
);
|
||||||
installationDeployer['core'] = this;
|
installationDeployer['core'] = this;
|
||||||
const changedInstance = await installationDeployer['deployFarm2'](
|
const changedInstance = await installationDeployer['deployFarm2'](
|
||||||
proxyAddress,
|
proxyAddress,
|
||||||
|
@ -668,27 +672,26 @@ ENDPOINT_UPDATE=true
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setConfig(min, name: string, value: any): Promise<any> {
|
public async setConfig(min, name: string, value: any): Promise<any> {
|
||||||
|
|
||||||
// Handles calls for BASIC persistence on sheet files.
|
// Handles calls for BASIC persistence on sheet files.
|
||||||
|
|
||||||
GBLog.info( `Defining Config.xlsx variable ${name}= '${value}'...`);
|
GBLog.info(`Defining Config.xlsx variable ${name}= '${value}'...`);
|
||||||
|
|
||||||
let { baseUrl, client } = await GBDeployer.internalGetDriveClient(min);
|
let { baseUrl, client } = await GBDeployer.internalGetDriveClient(min);
|
||||||
|
|
||||||
const maxLines = 512;
|
const maxLines = 512;
|
||||||
const file = "Config.xlsx";
|
const file = 'Config.xlsx';
|
||||||
const path = DialogKeywords.getGBAIPath(min.botId, `gbot`);;
|
const path = DialogKeywords.getGBAIPath(min.botId, `gbot`);
|
||||||
|
|
||||||
let document = await (new SystemKeywords()).internalGetDocument(client, baseUrl, path, file);
|
let document = await new SystemKeywords().internalGetDocument(client, baseUrl, path, file);
|
||||||
|
|
||||||
// Creates workbook session that will be discarded.
|
// Creates book session that will be discarded.
|
||||||
|
|
||||||
let sheets = await client
|
let sheets = await client.api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets`).get();
|
||||||
.api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets`)
|
|
||||||
.get();
|
|
||||||
|
|
||||||
let results = await client
|
let results = await client
|
||||||
.api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='A1:A${maxLines}')`)
|
.api(
|
||||||
|
`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='A1:A${maxLines}')`
|
||||||
|
)
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
const rows = results.text;
|
const rows = results.text;
|
||||||
|
@ -708,12 +711,12 @@ ENDPOINT_UPDATE=true
|
||||||
body.values[0][0] = value;
|
body.values[0][0] = value;
|
||||||
|
|
||||||
await client
|
await client
|
||||||
.api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='${address}')`)
|
.api(
|
||||||
|
`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='${address}')`
|
||||||
|
)
|
||||||
.patch(body);
|
.patch(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a dynamic param from instance. Dynamic params are defined in Config.xlsx
|
* Get a dynamic param from instance. Dynamic params are defined in Config.xlsx
|
||||||
* and loaded into the work folder from comida command.
|
* and loaded into the work folder from comida command.
|
||||||
|
@ -729,8 +732,7 @@ ENDPOINT_UPDATE=true
|
||||||
// Gets .gbot Params from specified bot.
|
// Gets .gbot Params from specified bot.
|
||||||
|
|
||||||
if (instance.params) {
|
if (instance.params) {
|
||||||
|
params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params);
|
||||||
params = typeof (instance.params) === 'object' ? instance.params : JSON.parse(instance.params);
|
|
||||||
params = GBUtil.caseInsensitive(params);
|
params = GBUtil.caseInsensitive(params);
|
||||||
value = params ? params[name] : defaultValue;
|
value = params ? params[name] : defaultValue;
|
||||||
}
|
}
|
||||||
|
@ -740,7 +742,6 @@ ENDPOINT_UPDATE=true
|
||||||
params = GBUtil.caseInsensitive(instance['dataValues']);
|
params = GBUtil.caseInsensitive(instance['dataValues']);
|
||||||
|
|
||||||
if (params && !value) {
|
if (params && !value) {
|
||||||
|
|
||||||
// Retrieves the value from specified bot instance (no params collection).
|
// Retrieves the value from specified bot instance (no params collection).
|
||||||
|
|
||||||
value = instance['dataValues'][name];
|
value = instance['dataValues'][name];
|
||||||
|
@ -749,27 +750,23 @@ ENDPOINT_UPDATE=true
|
||||||
|
|
||||||
const minBoot = GBServer.globals.minBoot as any;
|
const minBoot = GBServer.globals.minBoot as any;
|
||||||
|
|
||||||
if (
|
if (minBoot.instance && !value && instance.botId != minBoot.instance.botId) {
|
||||||
minBoot.instance &&
|
|
||||||
!value && instance.botId != minBoot.instance.botId) {
|
|
||||||
|
|
||||||
instance = minBoot.instance;
|
instance = minBoot.instance;
|
||||||
|
|
||||||
if(instance.params){
|
if (instance.params) {
|
||||||
params = typeof (instance.params) === 'object' ? instance.params : JSON.parse(instance.params);
|
params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params);
|
||||||
params = GBUtil.caseInsensitive(params);
|
params = GBUtil.caseInsensitive(params);
|
||||||
value = params ? params[name] : defaultValue;
|
value = params ? params[name] : defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If still did not found in boot bot params, try instance fields.
|
// If still did not found in boot bot params, try instance fields.
|
||||||
|
|
||||||
if (!value){
|
if (!value) {
|
||||||
value = instance['dataValues'][name];
|
value = instance['dataValues'][name];
|
||||||
}
|
}
|
||||||
if (!value){
|
if (!value) {
|
||||||
value = instance[name];
|
value = instance[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -798,7 +795,7 @@ ENDPOINT_UPDATE=true
|
||||||
let params = null;
|
let params = null;
|
||||||
const list = [];
|
const list = [];
|
||||||
if (instance.params) {
|
if (instance.params) {
|
||||||
params = typeof (instance.params) === 'object' ? instance.params : JSON.parse(instance.params);
|
params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(params).forEach(e => {
|
Object.keys(params).forEach(e => {
|
||||||
|
@ -810,5 +807,79 @@ ENDPOINT_UPDATE=true
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async ensureFolders(instances, deployer: GBDeployer) {
|
||||||
|
let libraryPath = GBConfigService.get('STORAGE_LIBRARY');
|
||||||
|
|
||||||
|
if (!Fs.existsSync(libraryPath)) {
|
||||||
|
mkdirp.sync(libraryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.syncBotStorage(instances, 'default', deployer, libraryPath);
|
||||||
|
|
||||||
|
const files = Fs.readdirSync(libraryPath);
|
||||||
|
await CollectionUtil.asyncForEach(files, async file => {
|
||||||
|
|
||||||
|
if (file.trim().toLowerCase() !== 'default.gbai'){
|
||||||
|
|
||||||
|
let botId = file.replace(/\.gbai/, '');
|
||||||
|
|
||||||
|
await this.syncBotStorage(instances, botId, deployer, libraryPath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async syncBotStorage(instances: any, botId: any, deployer: GBDeployer, libraryPath: string) {
|
||||||
|
let instance = instances.find(p => p.botId.toLowerCase().trim() === botId.toLowerCase().trim());
|
||||||
|
|
||||||
|
if (!instance) {
|
||||||
|
|
||||||
|
GBLog.info(`Importing package ${botId}...`);
|
||||||
|
|
||||||
|
// Creates a bot.
|
||||||
|
|
||||||
|
let mobile = null,
|
||||||
|
email = null;
|
||||||
|
|
||||||
|
instance = await deployer.deployBlankBot(botId, mobile, email);
|
||||||
|
const gbaiPath = Path.join(libraryPath, `${botId}.gbai`);
|
||||||
|
|
||||||
|
if (!Fs.existsSync(gbaiPath)) {
|
||||||
|
|
||||||
|
Fs.mkdirSync(gbaiPath, { recursive: true });
|
||||||
|
|
||||||
|
const base = Path.join(process.env.PWD, 'templates', 'default.gbai');
|
||||||
|
|
||||||
|
Fs.cpSync(Path.join(base, `default.gbkb`), Path.join(gbaiPath,`default.gbkb`), {
|
||||||
|
errorOnExist: false,
|
||||||
|
force: true,
|
||||||
|
recursive: true
|
||||||
|
});
|
||||||
|
Fs.cpSync(Path.join(base, `default.gbot`), Path.join(gbaiPath, `default.gbot`), {
|
||||||
|
errorOnExist: false,
|
||||||
|
force: true,
|
||||||
|
recursive: true
|
||||||
|
});
|
||||||
|
Fs.cpSync(Path.join(base, `default.gbtheme`), Path.join(gbaiPath, `default.gbtheme`), {
|
||||||
|
errorOnExist: false,
|
||||||
|
force: true,
|
||||||
|
recursive: true
|
||||||
|
});
|
||||||
|
Fs.cpSync(Path.join(base, `default.gbdata`), Path.join(gbaiPath, `default.gbdata`), {
|
||||||
|
errorOnExist: false,
|
||||||
|
force: true,
|
||||||
|
recursive: true
|
||||||
|
});
|
||||||
|
Fs.cpSync(Path.join(base, `default.gbdialog`), Path.join(gbaiPath, `default.gbdialog`), {
|
||||||
|
errorOnExist: false,
|
||||||
|
force: true,
|
||||||
|
recursive: true
|
||||||
|
});
|
||||||
|
Fs.cpSync(Path.join(base, `default.gbdrive`), Path.join(gbaiPath, `default.gbdrive`), {
|
||||||
|
errorOnExist: false,
|
||||||
|
force: true,
|
||||||
|
recursive: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,8 @@ import { AzureSearch } from 'pragmatismo-io-framework';
|
||||||
import { CollectionUtil } from 'pragmatismo-io-framework';
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
import { GBServer } from '../../../src/app.js';
|
import { GBServer } from '../../../src/app.js';
|
||||||
import { GBVMService } from '../../basic.gblib/services/GBVMService.js';
|
import { GBVMService } from '../../basic.gblib/services/GBVMService.js';
|
||||||
|
import Excel from 'exceljs';
|
||||||
|
import asyncPromise from 'async-promises';
|
||||||
import { GuaribasPackage } from '../models/GBModel.js';
|
import { GuaribasPackage } from '../models/GBModel.js';
|
||||||
import { GBAdminService } from './../../admin.gbapp/services/GBAdminService.js';
|
import { GBAdminService } from './../../admin.gbapp/services/GBAdminService.js';
|
||||||
import { AzureDeployerService } from './../../azuredeployer.gbapp/services/AzureDeployerService.js';
|
import { AzureDeployerService } from './../../azuredeployer.gbapp/services/AzureDeployerService.js';
|
||||||
|
@ -118,7 +120,7 @@ export class GBDeployer implements IGBDeployer {
|
||||||
);
|
);
|
||||||
|
|
||||||
const siteId = process.env.STORAGE_SITE_ID;
|
const siteId = process.env.STORAGE_SITE_ID;
|
||||||
const libraryId = process.env.STORAGE_LIBRARY;
|
const libraryId = GBConfigService.get('STORAGE_LIBRARY');
|
||||||
|
|
||||||
const client = MicrosoftGraph.Client.init({
|
const client = MicrosoftGraph.Client.init({
|
||||||
authProvider: done => {
|
authProvider: done => {
|
||||||
|
@ -220,6 +222,7 @@ export class GBDeployer implements IGBDeployer {
|
||||||
const instance = await this.importer.createBotInstance(botId);
|
const instance = await this.importer.createBotInstance(botId);
|
||||||
const bootInstance = GBServer.globals.bootInstance;
|
const bootInstance = GBServer.globals.bootInstance;
|
||||||
|
|
||||||
|
if (GBConfigService.get('STORAGE_NAME')) {
|
||||||
// Gets the access token to perform service operations.
|
// Gets the access token to perform service operations.
|
||||||
|
|
||||||
const accessToken = await (GBServer.globals.minBoot.adminService as any)['acquireElevatedToken'](
|
const accessToken = await (GBServer.globals.minBoot.adminService as any)['acquireElevatedToken'](
|
||||||
|
@ -231,11 +234,12 @@ export class GBDeployer implements IGBDeployer {
|
||||||
|
|
||||||
const service = await AzureDeployerService.createInstance(this);
|
const service = await AzureDeployerService.createInstance(this);
|
||||||
const application = await service.createApplication(accessToken, botId);
|
const application = await service.createApplication(accessToken, botId);
|
||||||
|
|
||||||
// Fills new instance base information and get App secret.
|
// Fills new instance base information and get App secret.
|
||||||
|
|
||||||
instance.marketplaceId = (application as any).appId;
|
instance.marketplaceId = (application as any).appId;
|
||||||
instance.marketplacePassword = await service.createApplicationSecret(accessToken, (application as any).id);
|
instance.marketplacePassword = await service.createApplicationSecret(accessToken, (application as any).id);
|
||||||
|
}
|
||||||
|
|
||||||
instance.adminPass = GBAdminService.getRndPassword();
|
instance.adminPass = GBAdminService.getRndPassword();
|
||||||
instance.title = botId;
|
instance.title = botId;
|
||||||
instance.activationCode = instance.botId.substring(0, 15);
|
instance.activationCode = instance.botId.substring(0, 15);
|
||||||
|
@ -247,10 +251,17 @@ export class GBDeployer implements IGBDeployer {
|
||||||
// Saves bot information to the store.
|
// Saves bot information to the store.
|
||||||
|
|
||||||
await this.core.saveInstance(instance);
|
await this.core.saveInstance(instance);
|
||||||
|
if (GBConfigService.get('STORAGE_NAME')) {
|
||||||
|
await this.deployBotOnAzure(instance, GBServer.globals.publicAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Makes available bot to the channels and .gbui interfaces.
|
||||||
|
|
||||||
|
await GBServer.globals.minService.mountBot(instance);
|
||||||
|
|
||||||
// Creates remaining objects on the cloud and updates instance information.
|
// Creates remaining objects on the cloud and updates instance information.
|
||||||
|
|
||||||
return await this.deployBotFull(instance, GBServer.globals.publicAddress);
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -265,7 +276,7 @@ export class GBDeployer implements IGBDeployer {
|
||||||
/**
|
/**
|
||||||
* Performs all tasks of deploying a new bot on the cloud.
|
* Performs all tasks of deploying a new bot on the cloud.
|
||||||
*/
|
*/
|
||||||
public async deployBotFull(instance: IGBInstance, publicAddress: string): Promise<IGBInstance> {
|
public async deployBotOnAzure(instance: IGBInstance, publicAddress: string): Promise<IGBInstance> {
|
||||||
// Reads base configuration from environent file.
|
// Reads base configuration from environent file.
|
||||||
|
|
||||||
const service = await AzureDeployerService.createInstance(this);
|
const service = await AzureDeployerService.createInstance(this);
|
||||||
|
@ -286,7 +297,6 @@ export class GBDeployer implements IGBDeployer {
|
||||||
`${publicAddress}/api/messages/${instance.botId}`
|
`${publicAddress}/api/messages/${instance.botId}`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Internally create resources on cloud provider.
|
// Internally create resources on cloud provider.
|
||||||
|
|
||||||
instance = await service.internalDeployBot(
|
instance = await service.internalDeployBot(
|
||||||
|
@ -305,10 +315,6 @@ export class GBDeployer implements IGBDeployer {
|
||||||
subscriptionId
|
subscriptionId
|
||||||
);
|
);
|
||||||
|
|
||||||
// Makes available bot to the channels and .gbui interfaces.
|
|
||||||
|
|
||||||
await GBServer.globals.minService.mountBot(instance);
|
|
||||||
await GBServer.globals.minService.ensureAPI();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Saves final instance object and returns it.
|
// Saves final instance object and returns it.
|
||||||
|
@ -326,7 +332,6 @@ export class GBDeployer implements IGBDeployer {
|
||||||
|
|
||||||
let embedding;
|
let embedding;
|
||||||
if (!azureOpenAIEmbeddingModel) {
|
if (!azureOpenAIEmbeddingModel) {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,7 +349,6 @@ export class GBDeployer implements IGBDeployer {
|
||||||
vectorStore = new HNSWLib(embedding, {
|
vectorStore = new HNSWLib(embedding, {
|
||||||
space: 'cosine'
|
space: 'cosine'
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
return vectorStore;
|
return vectorStore;
|
||||||
}
|
}
|
||||||
|
@ -412,70 +416,50 @@ export class GBDeployer implements IGBDeployer {
|
||||||
public async deployBotFromLocalPath(localPath: string, publicAddress: string): Promise<void> {
|
public async deployBotFromLocalPath(localPath: string, publicAddress: string): Promise<void> {
|
||||||
const packageName = Path.basename(localPath);
|
const packageName = Path.basename(localPath);
|
||||||
const instance = await this.importer.importIfNotExistsBotPackage(undefined, packageName, localPath);
|
const instance = await this.importer.importIfNotExistsBotPackage(undefined, packageName, localPath);
|
||||||
await this.deployBotFull(instance, publicAddress);
|
await this.deployBotOnAzure(instance, publicAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all para from tabular file Config.xlsx.
|
* Loads all para from tabular file Config.xlsx.
|
||||||
*/
|
*/
|
||||||
public async loadParamsFromTabular(min: GBMinInstance): Promise<any> {
|
public async loadParamsFromTabular(min: GBMinInstance, path): Promise<any> {
|
||||||
const siteId = process.env.STORAGE_SITE_ID;
|
const workbook = new Excel.Workbook();
|
||||||
const libraryId = process.env.STORAGE_LIBRARY;
|
const data = await workbook.xlsx.readFile(Path.join(path, 'Config.xlsx'));
|
||||||
|
|
||||||
GBLogEx.info(min, `Connecting to Config.xslx (siteId: ${siteId}, libraryId: ${libraryId})...`);
|
let worksheet: any;
|
||||||
|
for (let t = 0; t < data.worksheets.length; t++) {
|
||||||
|
worksheet = data.worksheets[t];
|
||||||
|
if (worksheet) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const rows = worksheet._rows;
|
||||||
|
GBLogEx.info(min, `Processing ${rows.length} rows from Config file ${path}...`);
|
||||||
|
let list = [];
|
||||||
|
|
||||||
// Connects to MSFT storage.
|
// Skips the header lines.
|
||||||
|
|
||||||
const token = await (min.adminService as any)['acquireElevatedToken'](min.instance.instanceId, true);
|
for (let index = 0; index < 6; index++) {
|
||||||
|
rows.shift();
|
||||||
|
}
|
||||||
|
|
||||||
const client = MicrosoftGraph.Client.init({
|
|
||||||
authProvider: done => {
|
let obj = {};
|
||||||
done(null, token);
|
await asyncPromise.eachSeries(rows, async line => {
|
||||||
|
|
||||||
|
if (line && line._cells[0] && line._cells[1] && line._cells[0].text) {
|
||||||
|
|
||||||
|
// Extracts values from columns in the current line.
|
||||||
|
|
||||||
|
obj[line._cells[0].text] = line._cells[1].text;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Retrieves all files in .bot folder.
|
GBLogEx.info(min, GBUtil.toYAML(list));
|
||||||
|
|
||||||
const botId = min.instance.botId;
|
|
||||||
const path = DialogKeywords.getGBAIPath(botId, 'gbot');
|
|
||||||
let url = `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/root:/${path}:/children`;
|
|
||||||
|
|
||||||
GBLogEx.info(min, `Loading .gbot from Excel: ${url}`);
|
|
||||||
const res = await client.api(url).get();
|
|
||||||
|
|
||||||
// Finds Config.xlsx.
|
|
||||||
|
|
||||||
const document = res.value.filter(m => {
|
|
||||||
return m.name === 'Config.xlsx';
|
|
||||||
});
|
|
||||||
if (document === undefined || document.length === 0) {
|
|
||||||
GBLogEx.info(min, `Config.xlsx not found on .bot folder, check the package.`);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads all rows in Config.xlsx that contains a pair of name/value
|
|
||||||
// and fills an object that is returned to be saved in params instance field.
|
|
||||||
|
|
||||||
const results = await client
|
|
||||||
.api(
|
|
||||||
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/items/${document[0].id}/workbook/worksheets('General')/range(address='A7:B100')`
|
|
||||||
)
|
|
||||||
.get();
|
|
||||||
let index = 0,
|
|
||||||
obj = {};
|
|
||||||
for (; index < results.text.length; index++) {
|
|
||||||
if (results.text[index][0] === '') {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
obj[results.text[index][0]] = results.text[index][1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all para from tabular file Config.xlsx.
|
|
||||||
*/
|
*/
|
||||||
public async downloadFolder(
|
public async downloadFolder(
|
||||||
min: GBMinInstance,
|
min: GBMinInstance,
|
||||||
|
@ -632,14 +616,7 @@ export class GBDeployer implements IGBDeployer {
|
||||||
case '.gbot':
|
case '.gbot':
|
||||||
// Extracts configuration information from .gbot files.
|
// Extracts configuration information from .gbot files.
|
||||||
|
|
||||||
if (process.env.ENABLE_PARAMS_ONLINE === 'false') {
|
min.instance.params = await this.loadParamsFromTabular(min, localPath);
|
||||||
if (Fs.existsSync(localPath)) {
|
|
||||||
GBLogEx.info(min, `Loading .gbot from ${localPath}.`);
|
|
||||||
await this.deployBotFromLocalPath(localPath, GBServer.globals.publicAddress);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
min.instance.params = await this.loadParamsFromTabular(min);
|
|
||||||
}
|
|
||||||
|
|
||||||
let connections = [];
|
let connections = [];
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| ( )_ _ |
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ _ _ _ |
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/ \ /`\ /'_`\ |
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| |*| |( (_) ) |
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
| | | ( )_) | |
|
|
||||||
| (_) \___/' |
|
|
||||||
| |
|
| |
|
||||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
| Licensed under the AGPL-3.0. |
|
| Licensed under the AGPL-3.0. |
|
||||||
|
|
|
@ -44,7 +44,9 @@ import Fs from 'fs';
|
||||||
import arrayBufferToBuffer from 'arraybuffer-to-buffer';
|
import arrayBufferToBuffer from 'arraybuffer-to-buffer';
|
||||||
import { NlpManager } from 'node-nlp';
|
import { NlpManager } from 'node-nlp';
|
||||||
import Koa from 'koa';
|
import Koa from 'koa';
|
||||||
|
import { v2 as webdav } from 'webdav-server';
|
||||||
import { createRpcServer } from '@push-rpc/core';
|
import { createRpcServer } from '@push-rpc/core';
|
||||||
|
import { start as startRouter } from '../../../packages/core.gbapp/services/router/bridge.js';
|
||||||
import wash from 'washyourmouthoutwithsoap';
|
import wash from 'washyourmouthoutwithsoap';
|
||||||
import {
|
import {
|
||||||
AutoSaveStateMiddleware,
|
AutoSaveStateMiddleware,
|
||||||
|
@ -140,10 +142,7 @@ export class GBMinService {
|
||||||
this.deployer = deployer;
|
this.deployer = deployer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async enableAPI(min: GBMinInstance) {}
|
||||||
public async enableAPI(min: GBMinInstance) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new minimal instance for each bot.
|
* Constructs a new minimal instance for each bot.
|
||||||
|
@ -168,25 +167,20 @@ export class GBMinService {
|
||||||
|
|
||||||
let i = 1;
|
let i = 1;
|
||||||
|
|
||||||
if (instances.length > 1) {
|
|
||||||
}
|
|
||||||
|
|
||||||
await CollectionUtil.asyncForEach(
|
await CollectionUtil.asyncForEach(
|
||||||
instances,
|
instances,
|
||||||
(async instance => {
|
(async instance => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
GBLog.info(`Mounting ${instance.botId}...`)
|
GBLog.info(`Mounting ${instance.botId}...`);
|
||||||
await this['mountBot'](instance);
|
await this['mountBot'](instance);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
GBLog.error(`Error mounting bot ${instance.botId}: ${error.message}\n${error.stack}`);
|
GBLog.error(`Error mounting bot ${instance.botId}: ${error.message}\n${error.stack}`);
|
||||||
}
|
}
|
||||||
}).bind(this)
|
}).bind(this)
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Loads API.
|
|
||||||
|
|
||||||
await this.ensureAPI();
|
|
||||||
|
|
||||||
// Loads schedules.
|
// Loads schedules.
|
||||||
|
|
||||||
GBLogEx.info(0, `Loading SET SCHEDULE entries...`);
|
GBLogEx.info(0, `Loading SET SCHEDULE entries...`);
|
||||||
|
@ -196,6 +190,37 @@ export class GBMinService {
|
||||||
GBLogEx.info(0, `All Bot instances loaded.`);
|
GBLogEx.info(0, `All Bot instances loaded.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async startSimpleTest(min) {
|
||||||
|
if (process.env.TEST_MESSAGE && min['isDefault']) {
|
||||||
|
GBLogEx.info(min, `Starting auto test with '${process.env.TEST_MESSAGE}'.`);
|
||||||
|
|
||||||
|
const client = await GBUtil.getDirectLineClient(min);
|
||||||
|
|
||||||
|
const response = await client.apis.Conversations.Conversations_StartConversation();
|
||||||
|
const conversationId = response.obj.conversationId;
|
||||||
|
GBServer.globals.debugConversationId = conversationId;
|
||||||
|
|
||||||
|
const steps = process.env.TEST_MESSAGE.split(';');
|
||||||
|
|
||||||
|
await CollectionUtil.asyncForEach(steps, async (step) => {
|
||||||
|
client.apis.Conversations.Conversations_PostActivity({
|
||||||
|
conversationId: conversationId,
|
||||||
|
activity: {
|
||||||
|
textFormat: 'plain',
|
||||||
|
text: step,
|
||||||
|
type: 'message',
|
||||||
|
from: {
|
||||||
|
id: 'test',
|
||||||
|
name: 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await GBUtil.sleep(3000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes bot endpoint from web listeners and remove bot instance
|
* Removes bot endpoint from web listeners and remove bot instance
|
||||||
* from list of global server bot instances.
|
* from list of global server bot instances.
|
||||||
|
@ -234,7 +259,7 @@ export class GBMinService {
|
||||||
/**
|
/**
|
||||||
* Unmounts the bot web site (default.gbui) secure domain, if any.
|
* Unmounts the bot web site (default.gbui) secure domain, if any.
|
||||||
*/
|
*/
|
||||||
public async unloadDomain(instance: IGBInstance) { }
|
public async unloadDomain(instance: IGBInstance) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mount the instance by creating an BOT Framework bot object,
|
* Mount the instance by creating an BOT Framework bot object,
|
||||||
|
@ -243,6 +268,7 @@ export class GBMinService {
|
||||||
*/
|
*/
|
||||||
public async mountBot(instance: IGBInstance) {
|
public async mountBot(instance: IGBInstance) {
|
||||||
|
|
||||||
|
|
||||||
// Build bot adapter.
|
// Build bot adapter.
|
||||||
|
|
||||||
const { min, adapter, conversationState } = await this.buildBotAdapter(
|
const { min, adapter, conversationState } = await this.buildBotAdapter(
|
||||||
|
@ -254,10 +280,14 @@ export class GBMinService {
|
||||||
// https://github.com/GeneralBots/BotServer/issues/286
|
// https://github.com/GeneralBots/BotServer/issues/286
|
||||||
// min['groupCache'] = await KBService.getGroupReplies(instance.instanceId);
|
// min['groupCache'] = await KBService.getGroupReplies(instance.instanceId);
|
||||||
|
|
||||||
|
min['isDefault'] = GBServer.globals.minInstances.length === 0;
|
||||||
|
|
||||||
GBServer.globals.minInstances.push(min);
|
GBServer.globals.minInstances.push(min);
|
||||||
const user = null; // No user context.
|
const user = null; // No user context.
|
||||||
|
|
||||||
await this.deployer['deployPackage2'](min, user, 'packages/default.gbtheme');
|
// Serves individual URL for each bot conversational interface.
|
||||||
|
|
||||||
|
await this.deployer['deployPackage2'](min, user, 'templates/default.gbai/default.gbtheme');
|
||||||
|
|
||||||
// Install per bot deployed packages.
|
// Install per bot deployed packages.
|
||||||
|
|
||||||
|
@ -318,21 +348,23 @@ export class GBMinService {
|
||||||
mkdirp.sync(dir);
|
mkdirp.sync(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loads Named Entity data for this bot.
|
if (!GBConfigService.get('STORAGE_NAME')) {
|
||||||
|
dir = Path.join(GBConfigService.get('STORAGE_LIBRARY'), 'work', gbai);
|
||||||
|
|
||||||
// TODO: await KBService.RefreshNER(min);
|
const server = GBServer.globals.webDavServer;
|
||||||
|
server.setFileSystem(`/${botId}`, new webdav.PhysicalFileSystem(dir), success => {
|
||||||
|
GBLogEx.info(1, `WebDav for ${botId} loaded.`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Calls the loadBot context.activity for all packages.
|
// Calls the loadBot context.activity for all packages.
|
||||||
|
|
||||||
await this.invokeLoadBot(min.appPackages, GBServer.globals.sysPackages, min);
|
await this.invokeLoadBot(min.appPackages, GBServer.globals.sysPackages, min);
|
||||||
|
|
||||||
// Serves individual URL for each bot conversational interface.
|
|
||||||
|
|
||||||
const receiver = async (req, res) => {
|
const receiver = async (req, res) => {
|
||||||
await this.receiver(req, res, conversationState, min, instance, GBServer.globals.appPackages);
|
await this.receiver(req, res, conversationState, min, instance, GBServer.globals.appPackages);
|
||||||
};
|
};
|
||||||
const url = `/api/messages/${instance.botId}`;
|
let url = `/api/messages/${instance.botId}`;
|
||||||
GBServer.globals.server.post(url, receiver);
|
|
||||||
GBServer.globals.server.get(url, (req, res) => {
|
GBServer.globals.server.get(url, (req, res) => {
|
||||||
if (req.query['hub.mode'] === 'subscribe') {
|
if (req.query['hub.mode'] === 'subscribe') {
|
||||||
if (req.query['hub.verify_token'] === process.env.FACEBOOK_VERIFY_TOKEN) {
|
if (req.query['hub.verify_token'] === process.env.FACEBOOK_VERIFY_TOKEN) {
|
||||||
|
@ -347,39 +379,6 @@ export class GBMinService {
|
||||||
});
|
});
|
||||||
GBLog.verbose(`GeneralBots(${instance.engineName}) listening on: ${url}.`);
|
GBLog.verbose(`GeneralBots(${instance.engineName}) listening on: ${url}.`);
|
||||||
|
|
||||||
// Test code.
|
|
||||||
if (process.env.TEST_MESSAGE) {
|
|
||||||
GBLogEx.info(min, `Starting auto test with '${process.env.TEST_MESSAGE}'.`);
|
|
||||||
|
|
||||||
const client = await new SwaggerClient({
|
|
||||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
||||||
requestInterceptor: req => {
|
|
||||||
req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await client.apis.Conversations.Conversations_StartConversation();
|
|
||||||
const conversationId = response.obj.conversationId;
|
|
||||||
GBServer.globals.debugConversationId = conversationId;
|
|
||||||
|
|
||||||
const steps = process.env.TEST_MESSAGE.split(';');
|
|
||||||
|
|
||||||
await CollectionUtil.asyncForEach(steps, async step => {
|
|
||||||
client.apis.Conversations.Conversations_PostActivity({
|
|
||||||
conversationId: conversationId,
|
|
||||||
activity: {
|
|
||||||
textFormat: 'plain',
|
|
||||||
text: step,
|
|
||||||
type: 'message',
|
|
||||||
from: {
|
|
||||||
id: 'test',
|
|
||||||
name: 'test'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await GBUtil.sleep(3000);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Generates MS Teams manifest.
|
// Generates MS Teams manifest.
|
||||||
|
|
||||||
|
@ -390,7 +389,6 @@ export class GBMinService {
|
||||||
const data = await this.deployer.getBotManifest(instance);
|
const data = await this.deployer.getBotManifest(instance);
|
||||||
Fs.writeFileSync(packageTeams, data);
|
Fs.writeFileSync(packageTeams, data);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Serves individual URL for each bot user interface.
|
// Serves individual URL for each bot user interface.
|
||||||
|
|
||||||
|
@ -426,9 +424,8 @@ export class GBMinService {
|
||||||
|
|
||||||
// Setups official handler for WhatsApp.
|
// Setups official handler for WhatsApp.
|
||||||
|
|
||||||
GBServer.globals.server.all(`/${min.instance.botId}/whatsapp`, async (req, res) => {
|
GBServer.globals.server
|
||||||
|
.all(`/${min.instance.botId}/whatsapp`, async (req, res) => {
|
||||||
|
|
||||||
if (req.query['hub.mode'] === 'subscribe') {
|
if (req.query['hub.mode'] === 'subscribe') {
|
||||||
const val = req.query['hub.verify_token'];
|
const val = req.query['hub.verify_token'];
|
||||||
|
|
||||||
|
@ -453,10 +450,18 @@ export class GBMinService {
|
||||||
whatsAppDirectLine = WhatsappDirectLine.botsByNumber[to];
|
whatsAppDirectLine = WhatsappDirectLine.botsByNumber[to];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (whatsAppDirectLine) {
|
||||||
await whatsAppDirectLine.WhatsAppCallback(req, res, whatsAppDirectLine.botId);
|
await whatsAppDirectLine.WhatsAppCallback(req, res, whatsAppDirectLine.botId);
|
||||||
}).bind(min);
|
}
|
||||||
|
})
|
||||||
|
.bind(min);
|
||||||
|
|
||||||
GBDeployer.mountGBKBAssets(`${botId}.gbkb`, botId, `${botId}.gbkb`);
|
GBDeployer.mountGBKBAssets(`${botId}.gbkb`, botId, `${botId}.gbkb`);
|
||||||
|
|
||||||
|
// Loads API.
|
||||||
|
|
||||||
|
await this.ensureAPI();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getProviderName(req: any, res: any) {
|
public static getProviderName(req: any, res: any) {
|
||||||
|
@ -510,9 +515,7 @@ export class GBMinService {
|
||||||
* on https://<gbhost>/<BotId>/token URL.
|
* on https://<gbhost>/<BotId>/token URL.
|
||||||
*/
|
*/
|
||||||
private handleOAuthTokenRequests(server: any, min: GBMinInstance, instance: IGBInstance) {
|
private handleOAuthTokenRequests(server: any, min: GBMinInstance, instance: IGBInstance) {
|
||||||
|
|
||||||
server.get(`/${min.instance.botId}/token`, async (req, res) => {
|
server.get(`/${min.instance.botId}/token`, async (req, res) => {
|
||||||
|
|
||||||
let tokenName = req.query['value'];
|
let tokenName = req.query['value'];
|
||||||
if (!tokenName) {
|
if (!tokenName) {
|
||||||
tokenName = '';
|
tokenName = '';
|
||||||
|
@ -535,9 +538,7 @@ export class GBMinService {
|
||||||
if (tokenName) {
|
if (tokenName) {
|
||||||
const code = req?.query?.code;
|
const code = req?.query?.code;
|
||||||
|
|
||||||
let url = urlJoin(
|
let url = urlJoin(host, tenant, 'oauth/token');
|
||||||
host,
|
|
||||||
tenant, 'oauth/token');
|
|
||||||
let buff = new Buffer(`${clientId}:${clientSecret}`);
|
let buff = new Buffer(`${clientId}:${clientSecret}`);
|
||||||
const base64 = buff.toString('base64');
|
const base64 = buff.toString('base64');
|
||||||
|
|
||||||
|
@ -549,14 +550,14 @@ export class GBMinService {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
},
|
},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
'grant_type': 'authorization_code',
|
grant_type: 'authorization_code',
|
||||||
'code': code
|
code: code
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
const result = await fetch(url, options);
|
const result = await fetch(url, options);
|
||||||
|
|
||||||
if (result.status != 200) {
|
if (result.status != 200) {
|
||||||
throw new Error(`handleOAuthTokenRequests error: ${result.status}: ${result.statusText}.`)
|
throw new Error(`handleOAuthTokenRequests error: ${result.status}: ${result.statusText}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const text = await result.text();
|
const text = await result.text();
|
||||||
|
@ -564,24 +565,31 @@ export class GBMinService {
|
||||||
|
|
||||||
// Saves token to the database.
|
// Saves token to the database.
|
||||||
|
|
||||||
await this.adminService.setValue(instance.instanceId,
|
await this.adminService.setValue(
|
||||||
`${tokenName}accessToken`, token['accessToken'] ? token['accessToken'] : token['access_token']);
|
instance.instanceId,
|
||||||
await this.adminService.setValue(instance.instanceId,
|
`${tokenName}accessToken`,
|
||||||
`${tokenName}refreshToken`, token['refreshToken'] ? token['refreshToken'] : token['refresh_token']);
|
token['accessToken'] ? token['accessToken'] : token['access_token']
|
||||||
|
);
|
||||||
|
await this.adminService.setValue(
|
||||||
|
instance.instanceId,
|
||||||
|
`${tokenName}refreshToken`,
|
||||||
|
token['refreshToken'] ? token['refreshToken'] : token['refresh_token']
|
||||||
|
);
|
||||||
|
|
||||||
await this.adminService.setValue(instance.instanceId,
|
await this.adminService.setValue(
|
||||||
`${tokenName}expiresOn`, token['expiresOn'] ?
|
instance.instanceId,
|
||||||
token['expiresOn'].toString() :
|
`${tokenName}expiresOn`,
|
||||||
new Date(Date.now() + (token['expires_in'] * 1000)).toString());
|
token['expiresOn']
|
||||||
|
? token['expiresOn'].toString()
|
||||||
|
: new Date(Date.now() + token['expires_in'] * 1000).toString()
|
||||||
|
);
|
||||||
await this.adminService.setValue(instance.instanceId, `${tokenName}AntiCSRFAttackState`, null);
|
await this.adminService.setValue(instance.instanceId, `${tokenName}AntiCSRFAttackState`, null);
|
||||||
|
} else {
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const authenticationContext = new AuthenticationContext.AuthenticationContext(
|
const authenticationContext = new AuthenticationContext.AuthenticationContext(
|
||||||
urlJoin(
|
urlJoin(
|
||||||
tokenName ? host : min.instance.authenticatorAuthorityHostUrl,
|
tokenName ? host : min.instance.authenticatorAuthorityHostUrl,
|
||||||
tokenName ? tenant : min.instance.authenticatorTenant)
|
tokenName ? tenant : min.instance.authenticatorTenant
|
||||||
|
)
|
||||||
);
|
);
|
||||||
const resource = 'https://graph.microsoft.com';
|
const resource = 'https://graph.microsoft.com';
|
||||||
|
|
||||||
|
@ -595,26 +603,24 @@ export class GBMinService {
|
||||||
tokenName ? clientSecret : instance.marketplacePassword,
|
tokenName ? clientSecret : instance.marketplacePassword,
|
||||||
async (err, token) => {
|
async (err, token) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
||||||
const msg = `handleOAuthTokenRequests: Error acquiring token: ${err}`;
|
const msg = `handleOAuthTokenRequests: Error acquiring token: ${err}`;
|
||||||
|
|
||||||
GBLog.error(msg);
|
GBLog.error(msg);
|
||||||
res.send(msg);
|
res.send(msg);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Saves token to the database.
|
// Saves token to the database.
|
||||||
|
|
||||||
await this.adminService.setValue(instance.instanceId, `${tokenName}accessToken`, token['accessToken']);
|
await this.adminService.setValue(instance.instanceId, `${tokenName}accessToken`, token['accessToken']);
|
||||||
await this.adminService.setValue(instance.instanceId, `${tokenName}refreshToken`, token['refreshToken']);
|
await this.adminService.setValue(instance.instanceId, `${tokenName}refreshToken`, token['refreshToken']);
|
||||||
await this.adminService.setValue(instance.instanceId, `${tokenName}expiresOn`, token['expiresOn'].toString());
|
await this.adminService.setValue(
|
||||||
|
instance.instanceId,
|
||||||
|
`${tokenName}expiresOn`,
|
||||||
|
token['expiresOn'].toString()
|
||||||
|
);
|
||||||
await this.adminService.setValue(instance.instanceId, `${tokenName}AntiCSRFAttackState`, null);
|
await this.adminService.setValue(instance.instanceId, `${tokenName}AntiCSRFAttackState`, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// Inform the home for default .gbui after finishing token retrival.
|
// Inform the home for default .gbui after finishing token retrival.
|
||||||
|
|
||||||
|
@ -633,7 +639,8 @@ export class GBMinService {
|
||||||
min.instance.authenticatorTenant,
|
min.instance.authenticatorTenant,
|
||||||
'/oauth2/authorize'
|
'/oauth2/authorize'
|
||||||
);
|
);
|
||||||
authorizationUrl = `${authorizationUrl}?response_type=code&client_id=${min.instance.marketplaceId
|
authorizationUrl = `${authorizationUrl}?response_type=code&client_id=${
|
||||||
|
min.instance.marketplaceId
|
||||||
}&redirect_uri=${urlJoin(process.env.BOT_URL, min.instance.botId, 'token')}`;
|
}&redirect_uri=${urlJoin(process.env.BOT_URL, min.instance.botId, 'token')}`;
|
||||||
GBLogEx.info(min, `HandleOAuthRequests: ${authorizationUrl}.`);
|
GBLogEx.info(min, `HandleOAuthRequests: ${authorizationUrl}.`);
|
||||||
res.redirect(authorizationUrl);
|
res.redirect(authorizationUrl);
|
||||||
|
@ -651,7 +658,6 @@ export class GBMinService {
|
||||||
botId = GBConfigService.get('BOT_ID');
|
botId = GBConfigService.get('BOT_ID');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Loads by the botId itself or by the activationCode field.
|
// Loads by the botId itself or by the activationCode field.
|
||||||
|
|
||||||
let instance = await this.core.loadInstanceByBotId(botId);
|
let instance = await this.core.loadInstanceByBotId(botId);
|
||||||
|
@ -663,7 +669,6 @@ export class GBMinService {
|
||||||
if (instance !== null) {
|
if (instance !== null) {
|
||||||
// Gets the webchat token, speech token and theme.
|
// Gets the webchat token, speech token and theme.
|
||||||
|
|
||||||
const webchatTokenContainer = await this.getWebchatToken(instance);
|
|
||||||
const speechToken = instance.speechKey != undefined ? await this.getSTSToken(instance) : null;
|
const speechToken = instance.speechKey != undefined ? await this.getSTSToken(instance) : null;
|
||||||
let theme = instance.theme;
|
let theme = instance.theme;
|
||||||
|
|
||||||
|
@ -673,14 +678,15 @@ export class GBMinService {
|
||||||
theme = `default.gbtheme`;
|
theme = `default.gbtheme`;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.send(
|
let logo = this.core.getParam(instance, 'Logo', null);
|
||||||
JSON.stringify({
|
|
||||||
|
logo = logo ? urlJoin(instance.botId, 'cache', logo) : 'images/logo-gb.png';
|
||||||
|
|
||||||
|
let config = {
|
||||||
instanceId: instance.instanceId,
|
instanceId: instance.instanceId,
|
||||||
botId: botId,
|
botId: botId,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
webchatToken: webchatTokenContainer.token,
|
|
||||||
speechToken: speechToken,
|
speechToken: speechToken,
|
||||||
conversationId: webchatTokenContainer.conversationId,
|
|
||||||
authenticatorTenant: instance.authenticatorTenant,
|
authenticatorTenant: instance.authenticatorTenant,
|
||||||
authenticatorClientId: instance.marketplaceId,
|
authenticatorClientId: instance.marketplaceId,
|
||||||
paramLogoImageUrl: this.core.getParam(instance, 'Logo Image Url', null),
|
paramLogoImageUrl: this.core.getParam(instance, 'Logo Image Url', null),
|
||||||
|
@ -688,14 +694,20 @@ export class GBMinService {
|
||||||
paramLogoImageWidth: this.core.getParam(instance, 'Logo Image Width', null),
|
paramLogoImageWidth: this.core.getParam(instance, 'Logo Image Width', null),
|
||||||
paramLogoImageHeight: this.core.getParam(instance, 'Logo Image Height', null),
|
paramLogoImageHeight: this.core.getParam(instance, 'Logo Image Height', null),
|
||||||
paramLogoImageType: this.core.getParam(instance, 'Logo Image Type', null),
|
paramLogoImageType: this.core.getParam(instance, 'Logo Image Type', null),
|
||||||
logo: this.core.getParam(instance, 'Logo', null),
|
logo: logo,
|
||||||
color1: this.core.getParam(instance, 'Color1', null),
|
color1: this.core.getParam(instance, 'Color1', null),
|
||||||
color2: this.core.getParam(instance, 'Color2', null),
|
color2: this.core.getParam(instance, 'Color2', null)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!GBConfigService.get('STORAGE_NAME')) {
|
||||||
|
config['domain'] = `http://localhost:${process.env.PORT}/directline/${botId}`;
|
||||||
|
} else {
|
||||||
|
const webchatTokenContainer = await this.getWebchatToken(instance);
|
||||||
|
(config['conversationId'] = webchatTokenContainer.conversationId),
|
||||||
|
(config['webchatToken'] = webchatTokenContainer.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send(JSON.stringify(config));
|
||||||
})
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
const error = `Instance not found while retrieving from .gbui web client: ${botId}.`;
|
const error = `Instance not found while retrieving from .gbui web client: ${botId}.`;
|
||||||
res.sendStatus(error);
|
res.sendStatus(error);
|
||||||
|
@ -753,12 +765,18 @@ export class GBMinService {
|
||||||
private async buildBotAdapter(instance: any, sysPackages: IGBPackage[], appPackages: IGBPackage[]) {
|
private async buildBotAdapter(instance: any, sysPackages: IGBPackage[], appPackages: IGBPackage[]) {
|
||||||
// MSFT stuff.
|
// MSFT stuff.
|
||||||
|
|
||||||
const adapter = new BotFrameworkAdapter({
|
let config = {
|
||||||
appId: instance.marketplaceId ? instance.marketplaceId : GBConfigService.get('MARKETPLACE_ID'),
|
appId: instance.marketplaceId ? instance.marketplaceId : GBConfigService.get('MARKETPLACE_ID'),
|
||||||
appPassword: instance.marketplacePassword
|
appPassword: instance.marketplacePassword
|
||||||
? instance.marketplacePassword
|
? instance.marketplacePassword
|
||||||
: GBConfigService.get('MARKETPLACE_SECRET')
|
: GBConfigService.get('MARKETPLACE_SECRET')
|
||||||
});
|
};
|
||||||
|
if (!GBConfigService.get('STORAGE_NAME')) {
|
||||||
|
startRouter(GBServer.globals.server, instance.botId);
|
||||||
|
config['clientOptions'] = { baseUri: `http://localhost:${process.env.PORT}` };
|
||||||
|
}
|
||||||
|
|
||||||
|
const adapter = new BotFrameworkAdapter(config);
|
||||||
const storage = new MemoryStorage();
|
const storage = new MemoryStorage();
|
||||||
const conversationState = new ConversationState(storage);
|
const conversationState = new ConversationState(storage);
|
||||||
const userState = new UserState(storage);
|
const userState = new UserState(storage);
|
||||||
|
@ -771,6 +789,28 @@ export class GBMinService {
|
||||||
// The minimal bot is built here.
|
// The minimal bot is built here.
|
||||||
|
|
||||||
const min = new GBMinInstance();
|
const min = new GBMinInstance();
|
||||||
|
|
||||||
|
// Setups default BOT Framework dialogs.
|
||||||
|
|
||||||
|
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 AttachmentPrompt('attachmentPrompt'));
|
||||||
|
|
||||||
|
min.dialogs.add(new ConfirmPrompt('confirmPrompt'));
|
||||||
|
if (process.env.ENABLE_AUTH) {
|
||||||
|
min.dialogs.add(
|
||||||
|
new OAuthPrompt('oAuthPrompt', {
|
||||||
|
connectionName: 'OAuth2',
|
||||||
|
text: 'Please sign in to General Bots.',
|
||||||
|
title: 'Sign in',
|
||||||
|
timeout: 300000
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
min.botId = instance.botId;
|
min.botId = instance.botId;
|
||||||
min.bot = adapter;
|
min.bot = adapter;
|
||||||
min.userState = userState;
|
min.userState = userState;
|
||||||
|
@ -793,6 +833,15 @@ export class GBMinService {
|
||||||
min['apiConversations'] = {};
|
min['apiConversations'] = {};
|
||||||
min.packages = sysPackages;
|
min.packages = sysPackages;
|
||||||
|
|
||||||
|
const receiver = async (req, res) => {
|
||||||
|
await this.receiver(req, res, conversationState, min, instance, GBServer.globals.appPackages);
|
||||||
|
};
|
||||||
|
|
||||||
|
let url = `/api/messages/${instance.botId}`;
|
||||||
|
GBServer.globals.server.post(url, receiver);
|
||||||
|
url = `/api/messages`;
|
||||||
|
GBServer.globals.server.post(url, receiver);
|
||||||
|
|
||||||
// NLP Manager.
|
// NLP Manager.
|
||||||
|
|
||||||
const manager = new NlpManager({ languages: ['pt'], forceNER: true });
|
const manager = new NlpManager({ languages: ['pt'], forceNER: true });
|
||||||
|
@ -802,7 +851,6 @@ export class GBMinService {
|
||||||
GBServer.globals.minBoot = min;
|
GBServer.globals.minBoot = min;
|
||||||
GBServer.globals.minBoot.instance.marketplaceId = GBConfigService.get('MARKETPLACE_ID');
|
GBServer.globals.minBoot.instance.marketplaceId = GBConfigService.get('MARKETPLACE_ID');
|
||||||
GBServer.globals.minBoot.instance.marketplacePassword = GBConfigService.get('MARKETPLACE_SECRET');
|
GBServer.globals.minBoot.instance.marketplacePassword = GBConfigService.get('MARKETPLACE_SECRET');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (min.instance.facebookWorkplaceVerifyToken) {
|
if (min.instance.facebookWorkplaceVerifyToken) {
|
||||||
|
@ -860,8 +908,7 @@ export class GBMinService {
|
||||||
|
|
||||||
await min.whatsAppDirectLine.setup(true);
|
await min.whatsAppDirectLine.setup(true);
|
||||||
} else {
|
} else {
|
||||||
if (min !== minBoot && minBoot.instance.whatsappServiceKey
|
if (min !== minBoot && minBoot.instance.whatsappServiceKey && min.instance.webchatKey) {
|
||||||
&& min.instance.webchatKey) {
|
|
||||||
min.whatsAppDirectLine = new WhatsappDirectLine(
|
min.whatsAppDirectLine = new WhatsappDirectLine(
|
||||||
min,
|
min,
|
||||||
min.botId,
|
min.botId,
|
||||||
|
@ -882,26 +929,6 @@ export class GBMinService {
|
||||||
WhatsappDirectLine.botsByNumber[botNumber] = min.whatsAppDirectLine;
|
WhatsappDirectLine.botsByNumber[botNumber] = min.whatsAppDirectLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setups default BOT Framework dialogs.
|
|
||||||
|
|
||||||
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 AttachmentPrompt('attachmentPrompt'));
|
|
||||||
|
|
||||||
min.dialogs.add(new ConfirmPrompt('confirmPrompt'));
|
|
||||||
if (process.env.ENABLE_AUTH) {
|
|
||||||
min.dialogs.add(
|
|
||||||
new OAuthPrompt('oAuthPrompt', {
|
|
||||||
connectionName: 'OAuth2',
|
|
||||||
text: 'Please sign in to General Bots.',
|
|
||||||
title: 'Sign in',
|
|
||||||
timeout: 300000
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return { min, adapter, conversationState };
|
return { min, adapter, conversationState };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1087,7 +1114,10 @@ export class GBMinService {
|
||||||
const startDialog = min.core.getParam(min.instance, 'Start Dialog', null);
|
const startDialog = min.core.getParam(min.instance, 'Start Dialog', null);
|
||||||
if (startDialog) {
|
if (startDialog) {
|
||||||
await sec.setParam(userId, 'welcomed', 'true');
|
await sec.setParam(userId, 'welcomed', 'true');
|
||||||
GBLogEx.info(min, `Auto start (teams) dialog is now being called: ${startDialog} for ${min.instance.botId}...`);
|
GBLogEx.info(
|
||||||
|
min,
|
||||||
|
`Auto start (teams) dialog is now being called: ${startDialog} for ${min.instance.botId}...`
|
||||||
|
);
|
||||||
await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid);
|
await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1095,7 +1125,8 @@ export class GBMinService {
|
||||||
|
|
||||||
// Required for F0 handling of persisted conversations.
|
// Required for F0 handling of persisted conversations.
|
||||||
|
|
||||||
GBLogEx.info(min,
|
GBLogEx.info(
|
||||||
|
min,
|
||||||
`Input> ${context.activity.text} (type: ${context.activity.type}, name: ${context.activity.name}, channelId: ${context.activity.channelId})`
|
`Input> ${context.activity.text} (type: ${context.activity.type}, name: ${context.activity.name}, channelId: ${context.activity.channelId})`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1104,7 +1135,6 @@ export class GBMinService {
|
||||||
|
|
||||||
const startDialog = min.core.getParam(min.instance, 'Start Dialog', null);
|
const startDialog = min.core.getParam(min.instance, 'Start Dialog', null);
|
||||||
|
|
||||||
|
|
||||||
if (context.activity.type === 'installationUpdate') {
|
if (context.activity.type === 'installationUpdate') {
|
||||||
GBLogEx.info(min, `Bot installed on Teams.`);
|
GBLogEx.info(min, `Bot installed on Teams.`);
|
||||||
} else if (context.activity.type === 'conversationUpdate' && context.activity.membersAdded.length > 0) {
|
} else if (context.activity.type === 'conversationUpdate' && context.activity.membersAdded.length > 0) {
|
||||||
|
@ -1133,7 +1163,8 @@ export class GBMinService {
|
||||||
) {
|
) {
|
||||||
min['conversationWelcomed'][step.context.activity.conversation.id] = true;
|
min['conversationWelcomed'][step.context.activity.conversation.id] = true;
|
||||||
|
|
||||||
GBLogEx.info(min,
|
GBLogEx.info(
|
||||||
|
min,
|
||||||
`Auto start (web 1) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...`
|
`Auto start (web 1) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...`
|
||||||
);
|
);
|
||||||
await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid);
|
await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid);
|
||||||
|
@ -1147,7 +1178,6 @@ export class GBMinService {
|
||||||
} else if (context.activity.type === 'message') {
|
} else if (context.activity.type === 'message') {
|
||||||
// Processes messages activities.
|
// Processes messages activities.
|
||||||
|
|
||||||
|
|
||||||
await this.processMessageActivity(context, min, step, pid);
|
await this.processMessageActivity(context, min, step, pid);
|
||||||
} else if (context.activity.type === 'event') {
|
} else if (context.activity.type === 'event') {
|
||||||
// Processes events activities.
|
// Processes events activities.
|
||||||
|
@ -1155,7 +1185,8 @@ export class GBMinService {
|
||||||
await this.processEventActivity(min, user, context, step);
|
await this.processEventActivity(min, user, context, step);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const msg = `ERROR: ${error.message} ${error.stack} ${error.error ? error.error.body : ''} ${error.error ? (error.error.stack ? error.error.stack : '') : ''
|
const msg = `ERROR: ${error.message} ${error.stack} ${error.error ? error.error.body : ''} ${
|
||||||
|
error.error ? (error.error.stack ? error.error.stack : '') : ''
|
||||||
}`;
|
}`;
|
||||||
GBLog.error(msg);
|
GBLog.error(msg);
|
||||||
|
|
||||||
|
@ -1170,7 +1201,17 @@ export class GBMinService {
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (!GBConfigService.get('STORAGE_NAME')) {
|
||||||
|
const context = adapter['createContext'](req);
|
||||||
|
context['_activity'] = context.activity.body;
|
||||||
|
await handler(context);
|
||||||
|
// Return status
|
||||||
|
res.status(200);
|
||||||
|
|
||||||
|
res.end();
|
||||||
|
} else {
|
||||||
await adapter['processActivity'](req, res, handler);
|
await adapter['processActivity'](req, res, handler);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code === 401) {
|
if (error.code === 401) {
|
||||||
GBLog.error('Calling processActivity due to Signing Key could not be retrieved error.');
|
GBLog.error('Calling processActivity due to Signing Key could not be retrieved error.');
|
||||||
|
@ -1209,7 +1250,10 @@ export class GBMinService {
|
||||||
const startDialog = min.core.getParam(min.instance, 'Start Dialog', null);
|
const startDialog = min.core.getParam(min.instance, 'Start Dialog', null);
|
||||||
if (startDialog && !min['conversationWelcomed'][step.context.activity.conversation.id]) {
|
if (startDialog && !min['conversationWelcomed'][step.context.activity.conversation.id]) {
|
||||||
user.welcomed = true;
|
user.welcomed = true;
|
||||||
GBLogEx.info(min, `Auto start (web 2) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...`);
|
GBLogEx.info(
|
||||||
|
min,
|
||||||
|
`Auto start (web 2) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...`
|
||||||
|
);
|
||||||
await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid);
|
await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid);
|
||||||
}
|
}
|
||||||
} else if (context.activity.name === 'updateToken') {
|
} else if (context.activity.name === 'updateToken') {
|
||||||
|
@ -1263,7 +1307,6 @@ export class GBMinService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleUploads(min, step, user, params, autoSave) {
|
private async handleUploads(min, step, user, params, autoSave) {
|
||||||
|
|
||||||
// Prepare Promises to download each attachment and then execute each Promise.
|
// Prepare Promises to download each attachment and then execute each Promise.
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -1294,7 +1337,6 @@ export class GBMinService {
|
||||||
GBServer.globals.files[handle] = gbfile;
|
GBServer.globals.files[handle] = gbfile;
|
||||||
|
|
||||||
if (!min.cbMap[user.userId] && autoSave) {
|
if (!min.cbMap[user.userId] && autoSave) {
|
||||||
|
|
||||||
const result = await t['internalAutoSave']({ min: min, handle: handle });
|
const result = await t['internalAutoSave']({ min: min, handle: handle });
|
||||||
await min.conversationalService.sendText(
|
await min.conversationalService.sendText(
|
||||||
min,
|
min,
|
||||||
|
@ -1303,12 +1345,9 @@ export class GBMinService {
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return gbfile;
|
return gbfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
await this.sendActivity('Error uploading file. Please,start again.');
|
await this.sendActivity('Error uploading file. Please,start again.');
|
||||||
}
|
}
|
||||||
|
@ -1367,7 +1406,8 @@ export class GBMinService {
|
||||||
context.activity.text = context.activity.text.trim();
|
context.activity.text = context.activity.text.trim();
|
||||||
|
|
||||||
const member = context.activity.from;
|
const member = context.activity.from;
|
||||||
let memberId, email;
|
let memberId = null,
|
||||||
|
email = null;
|
||||||
|
|
||||||
// Processes e-mail from id in case of Teams messages.
|
// Processes e-mail from id in case of Teams messages.
|
||||||
|
|
||||||
|
@ -1399,10 +1439,8 @@ export class GBMinService {
|
||||||
const userId = user.userId;
|
const userId = user.userId;
|
||||||
const params = user.params ? JSON.parse(user.params) : {};
|
const params = user.params ? JSON.parse(user.params) : {};
|
||||||
|
|
||||||
|
|
||||||
let message: GuaribasConversationMessage;
|
let message: GuaribasConversationMessage;
|
||||||
if (process.env.PRIVACY_STORE_MESSAGES === 'true') {
|
if (process.env.PRIVACY_STORE_MESSAGES === 'true') {
|
||||||
|
|
||||||
// Adds message to the analytics layer.
|
// Adds message to the analytics layer.
|
||||||
|
|
||||||
const analytics = new AnalyticsService();
|
const analytics = new AnalyticsService();
|
||||||
|
@ -1420,7 +1458,6 @@ export class GBMinService {
|
||||||
userId,
|
userId,
|
||||||
context.activity.text
|
context.activity.text
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1439,7 +1476,8 @@ export class GBMinService {
|
||||||
) {
|
) {
|
||||||
await sec.setParam(userId, 'welcomed', 'true');
|
await sec.setParam(userId, 'welcomed', 'true');
|
||||||
min['conversationWelcomed'][step.context.activity.conversation.id] = true;
|
min['conversationWelcomed'][step.context.activity.conversation.id] = true;
|
||||||
GBLogEx.info(min,
|
GBLogEx.info(
|
||||||
|
min,
|
||||||
`Auto start (4) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...`
|
`Auto start (4) dialog is now being called: ${startDialog} for ${min.instance.instanceId}...`
|
||||||
);
|
);
|
||||||
await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid);
|
await GBVMService.callVM(startDialog.toLowerCase(), min, step, pid);
|
||||||
|
@ -1500,21 +1538,18 @@ export class GBMinService {
|
||||||
} else {
|
} else {
|
||||||
// Removes unwanted chars in input text.
|
// Removes unwanted chars in input text.
|
||||||
|
|
||||||
|
|
||||||
step.context.activity['originalText'] = context.activity.text;
|
step.context.activity['originalText'] = context.activity.text;
|
||||||
const text = await GBConversationalService.handleText(min, user, step, context.activity.text);
|
const text = await GBConversationalService.handleText(min, user, step, context.activity.text);
|
||||||
step.context.activity['originalText']
|
step.context.activity['originalText'];
|
||||||
step.context.activity['text'] = text;
|
step.context.activity['text'] = text;
|
||||||
|
|
||||||
|
if (notes && text && text !== '') {
|
||||||
if (notes && text && text !== "") {
|
|
||||||
const sys = new SystemKeywords();
|
const sys = new SystemKeywords();
|
||||||
await sys.note({ pid, text });
|
await sys.note({ pid, text });
|
||||||
await step.context.sendActivity('OK.');
|
await step.context.sendActivity('OK.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Checks for bad words on input text.
|
// Checks for bad words on input text.
|
||||||
|
|
||||||
const hasBadWord = wash.check(step.context.activity.locale, text);
|
const hasBadWord = wash.check(step.context.activity.locale, text);
|
||||||
|
@ -1549,7 +1584,7 @@ export class GBMinService {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (min.cbMap[userId] && min.cbMap[userId].promise === '!GBHEAR') {
|
if (min.cbMap[userId] && min.cbMap[userId].promise === '!GBHEAR') {
|
||||||
min.cbMap[userId].promise = step.context.activity['originalText'];;
|
min.cbMap[userId].promise = step.context.activity['originalText'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is a dialog in course, continue to the next step.
|
// If there is a dialog in course, continue to the next step.
|
||||||
|
@ -1557,7 +1592,8 @@ export class GBMinService {
|
||||||
try {
|
try {
|
||||||
await step.continueDialog();
|
await step.continueDialog();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const msg = `ERROR: ${error.message} ${error.stack} ${error.error ? error.error.body : ''} ${error.error ? (error.error.stack ? error.error.stack : '') : ''
|
const msg = `ERROR: ${error.message} ${error.stack} ${error.error ? error.error.body : ''} ${
|
||||||
|
error.error ? (error.error.stack ? error.error.stack : '') : ''
|
||||||
}`;
|
}`;
|
||||||
GBLog.error(msg);
|
GBLog.error(msg);
|
||||||
await min.conversationalService.sendText(
|
await min.conversationalService.sendText(
|
||||||
|
@ -1601,7 +1637,6 @@ export class GBMinService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ensureAPI() {
|
public async ensureAPI() {
|
||||||
|
|
||||||
const mins = GBServer.globals.minInstances;
|
const mins = GBServer.globals.minInstances;
|
||||||
|
|
||||||
function getRemoteId(ctx: Koa.Context) {
|
function getRemoteId(ctx: Koa.Context) {
|
||||||
|
@ -1611,14 +1646,11 @@ export class GBMinService {
|
||||||
const close = async () => {
|
const close = async () => {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if (GBServer.globals.server.apiServer) {
|
if (GBServer.globals.server.apiServer) {
|
||||||
GBServer.globals.server.apiServer.close(
|
GBServer.globals.server.apiServer.close(cb => {
|
||||||
cb => {
|
|
||||||
resolve(true);
|
resolve(true);
|
||||||
GBLogEx.info(0, 'Reloading General Bots API...');
|
GBLogEx.info(0, 'Reloading General Bots API...');
|
||||||
}
|
});
|
||||||
);
|
} else {
|
||||||
}
|
|
||||||
else {
|
|
||||||
resolve(true);
|
resolve(true);
|
||||||
GBLogEx.info(0, 'Loading General Bots API...');
|
GBLogEx.info(0, 'Loading General Bots API...');
|
||||||
}
|
}
|
||||||
|
@ -1629,11 +1661,9 @@ export class GBMinService {
|
||||||
|
|
||||||
let proxies = {};
|
let proxies = {};
|
||||||
await CollectionUtil.asyncForEach(mins, async min => {
|
await CollectionUtil.asyncForEach(mins, async min => {
|
||||||
|
|
||||||
let dialogs = {};
|
let dialogs = {};
|
||||||
await CollectionUtil.asyncForEach(Object.values(min.scriptMap), async script => {
|
await CollectionUtil.asyncForEach(Object.values(min.scriptMap), async script => {
|
||||||
|
dialogs[script] = async data => {
|
||||||
dialogs[script] = async (data) => {
|
|
||||||
let sec = new SecService();
|
let sec = new SecService();
|
||||||
const user = await sec.ensureUser(
|
const user = await sec.ensureUser(
|
||||||
min,
|
min,
|
||||||
|
@ -1649,13 +1679,7 @@ export class GBMinService {
|
||||||
if (script === 'start') {
|
if (script === 'start') {
|
||||||
pid = GBVMService.createProcessInfo(user, min, 'api', null);
|
pid = GBVMService.createProcessInfo(user, min, 'api', null);
|
||||||
|
|
||||||
|
const client = await GBUtil.getDirectLineClient(min);
|
||||||
const client = await new SwaggerClient({
|
|
||||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
||||||
requestInterceptor: req => {
|
|
||||||
req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const response = await client.apis.Conversations.Conversations_StartConversation();
|
const response = await client.apis.Conversations.Conversations_StartConversation();
|
||||||
|
|
||||||
min['apiConversations'][pid] = { conversation: response.obj, client: client };
|
min['apiConversations'][pid] = { conversation: response.obj, client: client };
|
||||||
|
@ -1668,7 +1692,7 @@ export class GBMinService {
|
||||||
ret = pid;
|
ret = pid;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const proxy = {
|
const proxy = {
|
||||||
|
@ -1686,10 +1710,10 @@ export class GBMinService {
|
||||||
pingSendTimeout: null,
|
pingSendTimeout: null,
|
||||||
keepAliveTimeout: null,
|
keepAliveTimeout: null,
|
||||||
listeners: {
|
listeners: {
|
||||||
unsubscribed(subscriptions: number): void { },
|
unsubscribed(subscriptions: number): void {},
|
||||||
subscribed(subscriptions: number): void { },
|
subscribed(subscriptions: number): void {},
|
||||||
disconnected(remoteId: string, connections: number): void { },
|
disconnected(remoteId: string, connections: number): void {},
|
||||||
connected(remoteId: string, connections: number): void { },
|
connected(remoteId: string, connections: number): void {},
|
||||||
messageIn(...params): void {
|
messageIn(...params): void {
|
||||||
params.shift();
|
params.shift();
|
||||||
},
|
},
|
||||||
|
@ -1699,16 +1723,8 @@ export class GBMinService {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
GBServer.globals.server.apiServer = createKoaHttpServer(
|
GBServer.globals.server.apiServer = createKoaHttpServer(GBVMService.API_PORT, getRemoteId, { prefix: `api/v3` });
|
||||||
GBVMService.API_PORT,
|
|
||||||
getRemoteId, { prefix: `api/v3` });
|
|
||||||
|
|
||||||
createRpcServer(
|
|
||||||
proxies,
|
|
||||||
GBServer.globals.server.apiServer,
|
|
||||||
opts
|
|
||||||
);
|
|
||||||
|
|
||||||
|
createRpcServer(proxies, GBServer.globals.server.apiServer, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
360
packages/core.gbapp/services/router/bridge.ts
Normal file
|
@ -0,0 +1,360 @@
|
||||||
|
import bodyParser from 'body-parser';
|
||||||
|
import express from 'express';
|
||||||
|
import fetch from 'isomorphic-fetch';
|
||||||
|
import moment from 'moment';
|
||||||
|
import * as uuidv4 from 'uuid';
|
||||||
|
|
||||||
|
import { IActivity, IBotData, IConversation, IConversationUpdateActivity, IMessageActivity } from './types';
|
||||||
|
import { GBConfigService } from '../GBConfigService.js';
|
||||||
|
|
||||||
|
const expiresIn = 1800;
|
||||||
|
const conversationsCleanupInterval = 10000;
|
||||||
|
const conversations: { [key: string]: IConversation } = {};
|
||||||
|
const botDataStore: { [key: string]: IBotData } = {};
|
||||||
|
|
||||||
|
export const getRouter = (
|
||||||
|
serviceUrl: string,
|
||||||
|
botUrl: string,
|
||||||
|
conversationInitRequired = true,
|
||||||
|
botId
|
||||||
|
): express.Router => {
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.use(bodyParser.json()); // for parsing application/json
|
||||||
|
router.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
|
||||||
|
router.use((req, res, next) => {
|
||||||
|
res.header('Access-Control-Allow-Origin', '*');
|
||||||
|
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, PATCH, OPTIONS');
|
||||||
|
res.header(
|
||||||
|
'Access-Control-Allow-Headers',
|
||||||
|
'Origin, X-Requested-With, Content-Type, Accept, Authorization, x-ms-bot-agent'
|
||||||
|
);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
// CLIENT ENDPOINT
|
||||||
|
router.options(`/directline/${botId}/`, (req, res) => {
|
||||||
|
res.status(200).end();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Creates a conversation
|
||||||
|
const reqs = (req, res) => {
|
||||||
|
const conversationId: string = uuidv4.v4().toString();
|
||||||
|
conversations[conversationId] = {
|
||||||
|
conversationId,
|
||||||
|
history: []
|
||||||
|
};
|
||||||
|
console.log('Created conversation with conversationId: ' + conversationId);
|
||||||
|
|
||||||
|
const activity = createConversationUpdateActivity(serviceUrl, conversationId);
|
||||||
|
fetch(botUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(activity),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}).then(response => {
|
||||||
|
res.status(response.status).send({
|
||||||
|
conversationId,
|
||||||
|
expiresIn
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
router.post('/v3/directline/conversations', reqs);
|
||||||
|
router.post(`/directline/${botId}/conversations`, reqs);
|
||||||
|
router.post(`/directline/conversations`, reqs);
|
||||||
|
|
||||||
|
// Reconnect API
|
||||||
|
router.get('/v3/directline/conversations/:conversationId', (req, res) => {
|
||||||
|
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
||||||
|
if (conversation) {
|
||||||
|
res.status(200).send(conversation);
|
||||||
|
} else {
|
||||||
|
// Conversation was never initialized
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn('/v3/directline/conversations/:conversationId not implemented');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Gets activities from store (local history array for now)
|
||||||
|
router.get(`/directline/${botId}/conversations/:conversationId/activities`, (req, res) => {
|
||||||
|
const watermark = req.query.watermark && req.query.watermark !== 'null' ? Number(req.query.watermark) : 0;
|
||||||
|
|
||||||
|
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
||||||
|
|
||||||
|
if (conversation) {
|
||||||
|
// If the bot has pushed anything into the history array
|
||||||
|
if (conversation.history.length > watermark) {
|
||||||
|
const activities = conversation.history.slice(watermark);
|
||||||
|
res.status(200).json({
|
||||||
|
activities,
|
||||||
|
watermark: watermark + activities.length
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.status(200).send({
|
||||||
|
activities: [],
|
||||||
|
watermark
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Conversation was never initialized
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sends message to bot. Assumes message activities
|
||||||
|
router.post(`/directline/${botId}/conversations/:conversationId/activities`, (req, res) => {
|
||||||
|
const incomingActivity = req.body;
|
||||||
|
// Make copy of activity. Add required fields
|
||||||
|
const activity = createMessageActivity(incomingActivity, serviceUrl, req.params.conversationId);
|
||||||
|
|
||||||
|
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
||||||
|
|
||||||
|
if (conversation) {
|
||||||
|
conversation.history.push(activity);
|
||||||
|
fetch(botUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(activity),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}).then(response => {
|
||||||
|
res.status(response.status).json({ id: activity.id });
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Conversation was never initialized
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/v3/directline/conversations/:conversationId/upload', (req, res) => {
|
||||||
|
console.warn('/v3/directline/conversations/:conversationId/upload not implemented');
|
||||||
|
});
|
||||||
|
router.get('/v3/directline/conversations/:conversationId/stream', (req, res) => {
|
||||||
|
console.warn('/v3/directline/conversations/:conversationId/stream not implemented');
|
||||||
|
});
|
||||||
|
|
||||||
|
// BOT CONVERSATION ENDPOINT
|
||||||
|
|
||||||
|
router.post('/v3/conversations', (req, res) => {
|
||||||
|
console.warn('/v3/conversations not implemented');
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/v3/conversations/:conversationId/activities', (req, res) => {
|
||||||
|
let activity: IActivity;
|
||||||
|
|
||||||
|
activity = req.body;
|
||||||
|
activity.id = uuidv4.v4();
|
||||||
|
activity.from = { id: 'id', name: 'Bot' };
|
||||||
|
|
||||||
|
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
||||||
|
if (conversation) {
|
||||||
|
conversation.history.push(activity);
|
||||||
|
res.status(200).send();
|
||||||
|
} else {
|
||||||
|
// Conversation was never initialized
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/v3/conversations/:conversationId/activities/:activityId', (req, res) => {
|
||||||
|
let activity: IActivity;
|
||||||
|
|
||||||
|
activity = req.body;
|
||||||
|
activity.id = uuidv4.v4();
|
||||||
|
activity.from = { id: 'id', name: 'Bot' };
|
||||||
|
|
||||||
|
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
||||||
|
if (conversation) {
|
||||||
|
conversation.history.push(activity);
|
||||||
|
res.status(200).send();
|
||||||
|
} else {
|
||||||
|
// Conversation was never initialized
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/v3/conversations/:conversationId/members', (req, res) => {
|
||||||
|
console.warn('/v3/conversations/:conversationId/members not implemented');
|
||||||
|
});
|
||||||
|
router.get('/v3/conversations/:conversationId/activities/:activityId/members', (req, res) => {
|
||||||
|
console.warn('/v3/conversations/:conversationId/activities/:activityId/members');
|
||||||
|
});
|
||||||
|
|
||||||
|
// BOTSTATE ENDPOINT
|
||||||
|
|
||||||
|
router.get('/v3/botstate/:channelId/users/:userId', (req, res) => {
|
||||||
|
console.log('Called GET user data');
|
||||||
|
getBotData(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/v3/botstate/:channelId/conversations/:conversationId', (req, res) => {
|
||||||
|
console.log('Called GET conversation data');
|
||||||
|
getBotData(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/v3/botstate/:channelId/conversations/:conversationId/users/:userId', (req, res) => {
|
||||||
|
console.log('Called GET private conversation data');
|
||||||
|
getBotData(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/v3/botstate/:channelId/users/:userId', (req, res) => {
|
||||||
|
console.log('Called POST setUserData');
|
||||||
|
setUserData(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/v3/botstate/:channelId/conversations/:conversationId', (req, res) => {
|
||||||
|
console.log('Called POST setConversationData');
|
||||||
|
setConversationData(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/v3/botstate/:channelId/conversations/:conversationId/users/:userId', (req, res) => {
|
||||||
|
setPrivateConversationData(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.delete('/v3/botstate/:channelId/users/:userId', (req, res) => {
|
||||||
|
console.log('Called DELETE deleteStateForUser');
|
||||||
|
deleteStateForUser(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
return router;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param app The express app where your offline-directline endpoint will live
|
||||||
|
* @param port The port where your offline-directline will be hosted
|
||||||
|
* @param botUrl The url of the bot (e.g. http://127.0.0.1:3978/api/messages)
|
||||||
|
* @param conversationInitRequired Requires that a conversation is initialized before it is accessed, returning a 400
|
||||||
|
* when not the case. If set to false, a new conversation reference is created on the fly. This is true by default.
|
||||||
|
*/
|
||||||
|
export const initializeRoutes = (
|
||||||
|
app: express.Express,
|
||||||
|
port: number,
|
||||||
|
botUrl: string,
|
||||||
|
conversationInitRequired = true,
|
||||||
|
botId
|
||||||
|
) => {
|
||||||
|
conversationsCleanup();
|
||||||
|
|
||||||
|
const directLineEndpoint = `http://127.0.0.1:${port}`;
|
||||||
|
const router = getRouter(directLineEndpoint, botUrl, conversationInitRequired, botId);
|
||||||
|
|
||||||
|
app.use(router);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getConversation = (conversationId: string, conversationInitRequired: boolean) => {
|
||||||
|
// Create conversation on the fly when needed and init not required
|
||||||
|
if (!conversations[conversationId] && !conversationInitRequired) {
|
||||||
|
conversations[conversationId] = {
|
||||||
|
conversationId,
|
||||||
|
history: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return conversations[conversationId];
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBotDataKey = (channelId: string, conversationId: string, userId: string) => {
|
||||||
|
return `$${channelId || '*'}!${conversationId || '*'}!${userId || '*'}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setBotData = (channelId: string, conversationId: string, userId: string, incomingData: IBotData): IBotData => {
|
||||||
|
const key = getBotDataKey(channelId, conversationId, userId);
|
||||||
|
const newData: IBotData = {
|
||||||
|
eTag: new Date().getTime().toString(),
|
||||||
|
data: incomingData.data
|
||||||
|
};
|
||||||
|
|
||||||
|
if (incomingData) {
|
||||||
|
botDataStore[key] = newData;
|
||||||
|
} else {
|
||||||
|
delete botDataStore[key];
|
||||||
|
newData.eTag = '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
return newData;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBotData = (req: express.Request, res: express.Response) => {
|
||||||
|
const key = getBotDataKey(req.params.channelId, req.params.conversationId, req.params.userId);
|
||||||
|
console.log('Data key: ' + key);
|
||||||
|
|
||||||
|
res.status(200).send(botDataStore[key] || { data: null, eTag: '*' });
|
||||||
|
};
|
||||||
|
|
||||||
|
const setUserData = (req: express.Request, res: express.Response) => {
|
||||||
|
res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body));
|
||||||
|
};
|
||||||
|
|
||||||
|
const setConversationData = (req: express.Request, res: express.Response) => {
|
||||||
|
res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body));
|
||||||
|
};
|
||||||
|
|
||||||
|
const setPrivateConversationData = (req: express.Request, res: express.Response) => {
|
||||||
|
res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const start = (server, botId) => {
|
||||||
|
const port = GBConfigService.getServerPort();
|
||||||
|
initializeRoutes(server, Number(port), `http://127.0.0.1:${port}/api/messages/${botId}`, null, botId);
|
||||||
|
|
||||||
|
if (botId === 'default') {
|
||||||
|
initializeRoutes(server, Number(port), `http://127.0.0.1:${port}/api/messages`, null, botId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteStateForUser = (req: express.Request, res: express.Response) => {
|
||||||
|
Object.keys(botDataStore).forEach(key => {
|
||||||
|
if (key.endsWith(`!{req.query.userId}`)) {
|
||||||
|
delete botDataStore[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
res.status(200).send();
|
||||||
|
};
|
||||||
|
|
||||||
|
// CLIENT ENDPOINT HELPERS
|
||||||
|
const createMessageActivity = (
|
||||||
|
incomingActivity: IMessageActivity,
|
||||||
|
serviceUrl: string,
|
||||||
|
conversationId: string
|
||||||
|
): IMessageActivity => {
|
||||||
|
return {
|
||||||
|
...incomingActivity,
|
||||||
|
channelId: 'emulator',
|
||||||
|
serviceUrl,
|
||||||
|
conversation: { id: conversationId },
|
||||||
|
id: uuidv4.v4()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const createConversationUpdateActivity = (serviceUrl: string, conversationId: string): IConversationUpdateActivity => {
|
||||||
|
const activity: IConversationUpdateActivity = {
|
||||||
|
type: 'conversationUpdate',
|
||||||
|
channelId: 'emulator',
|
||||||
|
serviceUrl,
|
||||||
|
conversation: { id: conversationId },
|
||||||
|
id: uuidv4.v4(),
|
||||||
|
membersAdded: [],
|
||||||
|
membersRemoved: [],
|
||||||
|
from: { id: 'offline-directline', name: 'Offline Directline Server' }
|
||||||
|
};
|
||||||
|
return activity;
|
||||||
|
};
|
||||||
|
|
||||||
|
const conversationsCleanup = () => {
|
||||||
|
setInterval(() => {
|
||||||
|
const expiresTime = moment().subtract(expiresIn, 'seconds');
|
||||||
|
Object.keys(conversations).forEach(conversationId => {
|
||||||
|
if (conversations[conversationId].history.length > 0) {
|
||||||
|
const lastTime = moment(
|
||||||
|
conversations[conversationId].history[conversations[conversationId].history.length - 1].localTimestamp
|
||||||
|
);
|
||||||
|
if (lastTime < expiresTime) {
|
||||||
|
delete conversations[conversationId];
|
||||||
|
console.log('deleted cId: ' + conversationId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, conversationsCleanupInterval);
|
||||||
|
};
|
66
packages/core.gbapp/services/router/types.ts
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
export interface IUser {
|
||||||
|
id: string,
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IChannelAccount {
|
||||||
|
id?: string,
|
||||||
|
name?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IConversationAccount extends IChannelAccount {
|
||||||
|
isGroup?: boolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAttachment {
|
||||||
|
contentType?: string,
|
||||||
|
contentUrl?: string,
|
||||||
|
content?: any,
|
||||||
|
name?: string,
|
||||||
|
thumbnailUrl?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IEntity {
|
||||||
|
type?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IActivity {
|
||||||
|
type?: string,
|
||||||
|
id?: string,
|
||||||
|
serviceUrl?: string,
|
||||||
|
timestamp?: string,
|
||||||
|
localTimestamp?: string,
|
||||||
|
channelId?: string,
|
||||||
|
from?: IChannelAccount,
|
||||||
|
conversation?: IConversationAccount,
|
||||||
|
recipient?: IChannelAccount,
|
||||||
|
replyToId?: string,
|
||||||
|
channelData?: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMessageActivity extends IActivity {
|
||||||
|
locale?: string,
|
||||||
|
text?: string,
|
||||||
|
summary?: string,
|
||||||
|
textFormat?: string,
|
||||||
|
attachmentLayout?: string,
|
||||||
|
attachments?: IAttachment[],
|
||||||
|
entities?: IEntity[],
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBotData {
|
||||||
|
eTag: string;
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IConversation {
|
||||||
|
conversationId: string,
|
||||||
|
history?: IActivity[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IConversationUpdateActivity extends IActivity {
|
||||||
|
membersAdded?: IChannelAccount[],
|
||||||
|
membersRemoved?: IChannelAccount[],
|
||||||
|
topicName?: string,
|
||||||
|
historyDisclosed?: boolean,
|
||||||
|
}
|
|
@ -1,77 +0,0 @@
|
||||||
' General Bots Copyright (c) pragmatismo.cloud. All rights reserved. Licensed under the AGPL-3.0.
|
|
||||||
' Rules from http://jsfiddle.net/roderick/dym05hsy
|
|
||||||
|
|
||||||
talk "How many installments do you want to pay your Credit?"
|
|
||||||
hear installments
|
|
||||||
|
|
||||||
if installments > 60 then
|
|
||||||
talk "The maximum number of payments is 60"
|
|
||||||
else
|
|
||||||
talk "What is the amount requested?"
|
|
||||||
hear amount
|
|
||||||
|
|
||||||
if amount >100000 then
|
|
||||||
talk "We are sorry, we can only accept proposals bellow 100k"
|
|
||||||
else
|
|
||||||
|
|
||||||
talk "What is the best due date?"
|
|
||||||
hear dueDate
|
|
||||||
|
|
||||||
interestRate = 0
|
|
||||||
adjustment = 0
|
|
||||||
|
|
||||||
if installments < 12 then
|
|
||||||
interestRate = 1.60
|
|
||||||
adjustment = 0.09748
|
|
||||||
end if
|
|
||||||
|
|
||||||
if installments > 12 and installments < 18 then
|
|
||||||
interestRate = 1.66
|
|
||||||
adjustment = 0.06869
|
|
||||||
end if
|
|
||||||
|
|
||||||
if installments > 18 and installments < 36 then
|
|
||||||
interestRate = 1.64
|
|
||||||
adjustment = 0.05397
|
|
||||||
end if
|
|
||||||
|
|
||||||
if installments > 36 and installments < 48 then
|
|
||||||
interestRate = 1.62
|
|
||||||
adjustment = 0.03931
|
|
||||||
end if
|
|
||||||
|
|
||||||
if installments > 48 and installments < 60 then
|
|
||||||
interestRate = 1.70
|
|
||||||
adjustment = 0.03270
|
|
||||||
end if
|
|
||||||
|
|
||||||
if installments = 60 then
|
|
||||||
interestRate = 1.79
|
|
||||||
adjustment = 0.02916
|
|
||||||
end if
|
|
||||||
|
|
||||||
if installments > 60 then
|
|
||||||
talk "The maximum number of payments is 60"
|
|
||||||
end if
|
|
||||||
|
|
||||||
nInstallments = parseInt(installments)
|
|
||||||
vamount = parseFloat(amount)
|
|
||||||
initialPayment = vamount * 0.3 ' 30% of the value
|
|
||||||
tac = 800
|
|
||||||
adjustment = 1.3
|
|
||||||
|
|
||||||
totalValue = amount - initialPayment + tac
|
|
||||||
paymentValue = totalValue * adjustment
|
|
||||||
finalValue = paymentValue * nInstallments + initialPayment
|
|
||||||
|
|
||||||
talk "Congratulations! Your credit analysis is **done**:"
|
|
||||||
talk "First payment: **" + initialPayment + "**"
|
|
||||||
talk "Payment value: **" + paymentValue + "**"
|
|
||||||
talk "Interest Rate: **" + interestRate + "%**"
|
|
||||||
talk "Total Value: **" + totalValue + "**"
|
|
||||||
talk "Final Value: **" + finalValue + "**"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end if
|
|
||||||
end if
|
|
|
@ -1,50 +0,0 @@
|
||||||
' General Bots Copyright (c) pragmatismo.cloud. All rights reserved. Licensed under the AGPL-3.0.
|
|
||||||
|
|
||||||
talk "Quer pagar quanto?"
|
|
||||||
hear amount
|
|
||||||
|
|
||||||
talk "Para onde?"
|
|
||||||
hear address
|
|
||||||
|
|
||||||
if amount < 5 then
|
|
||||||
talk "O mínimo que vendo este produto é 5."
|
|
||||||
else
|
|
||||||
|
|
||||||
if address is in "Rio" then
|
|
||||||
get payment amount
|
|
||||||
delivery to address
|
|
||||||
else
|
|
||||||
talk "Vou ver se tenho um parceiro para entregar aí e te falo. Eu só entrego no Rio."
|
|
||||||
end if
|
|
||||||
end if
|
|
||||||
|
|
||||||
talk "Valeu!"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Falar "Qual seu nome?"
|
|
||||||
Ouvir nome
|
|
||||||
|
|
||||||
Falar "Informe seu CEP, por favor:"
|
|
||||||
Ouvir CEP
|
|
||||||
|
|
||||||
Address = CEP
|
|
||||||
|
|
||||||
Confira seu endereço:
|
|
||||||
|
|
||||||
Address.Street
|
|
||||||
Address.Number
|
|
||||||
|
|
||||||
|
|
||||||
Falar "Manda sua localização para eu pedir a alguém para sair agora com o seu pedido"
|
|
||||||
Hear Location
|
|
||||||
|
|
||||||
SAve "Pedidos.xlsx", Nome, From, Location.Street, Location.Number
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Falar "Manda sua localização que eu encontro o posto mais próximo"
|
|
||||||
Hear Location
|
|
||||||
|
|
||||||
Find "Postos.xlsx", "Endereço=" + Location
|
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
if consulta = "cpf" then
|
|
||||||
talk "Qual seu CPF?"
|
|
||||||
hear cpf
|
|
||||||
talk "Aguarde alguns instantes que eu localizo seu cadastro..."
|
|
||||||
row = find "Cadastro.xlsx", "CPF=" + cpf
|
|
||||||
if row != null then
|
|
||||||
talk "Oi, " + row.Nome + "Tudo bem? "
|
|
||||||
talk "Seu código de cliente é " + row.Cod
|
|
||||||
talk "Vamos te enviar o pedido para seu endereço em: " + row.Endereço
|
|
||||||
send file "boleta.pdf", "Pague já e evite multas!"
|
|
||||||
else
|
|
||||||
talk "Tente novamente."
|
|
||||||
end if
|
|
||||||
else
|
|
||||||
talk "Qual seria seu código?"
|
|
||||||
hear cod
|
|
||||||
talk "Aguarde alguns instantes que eu localizo seu cadastro..."
|
|
||||||
row = find "Cadastro.xlsx", "Cod=" + cod
|
|
||||||
if row != null then
|
|
||||||
talk "Oi, " + row.Nome + "Tudo bem? "
|
|
||||||
talk "Seu CPF é " + row.CPF
|
|
||||||
talk "Vamos te enviar o pedido para seu endereço em: " + row.Endereço
|
|
||||||
send file "boleta.pdf", "Pague já e evite multas!"
|
|
||||||
else
|
|
||||||
talk "Tente novamente."
|
|
||||||
end if
|
|
||||||
end if
|
|
|
@ -1,5 +0,0 @@
|
||||||
talk “Olá! Seja bem vinda(o)!”
|
|
||||||
|
|
||||||
X = find “campanhas.xlsx”, “nome=1239” OR TALK “Desculpe-me, não localizei seu nome.”
|
|
||||||
|
|
||||||
talk “opa, vamos lá!” + x.nome
|
|
|
@ -1,12 +0,0 @@
|
||||||
' General Bots Copyright (c) pragmatismo.cloud. All rights reserved. Licensed under the AGPL-3.0.
|
|
||||||
|
|
||||||
talk "Quer pagar quanto?"
|
|
||||||
hear amount
|
|
||||||
|
|
||||||
if amount < 5 then
|
|
||||||
talk "O mínimo que vendo este produto é 5."
|
|
||||||
else
|
|
||||||
get payment amount
|
|
||||||
end if
|
|
||||||
|
|
||||||
talk "Valeu!"
|
|
|
@ -1,9 +0,0 @@
|
||||||
value = get "list.xslx", "A1:A1"
|
|
||||||
|
|
||||||
set "list.xslx", "A1:A1", "value"
|
|
||||||
|
|
||||||
myVar = find "chamadosbug748.xlsx", "CHAMADO=" + "5521979047667-44129-10"
|
|
||||||
status="alterado"
|
|
||||||
set "chamadosbug748.xlsx", "E" + myVar.line + ":E" + myVar.line, status
|
|
||||||
res = get "chamadosbug748.xlsx", "E" + myVar.line + ":E" + myVar.line
|
|
||||||
talk "Obrigado e até a próxima e veja bem, o resultado é esse: " + res
|
|
|
@ -1,6 +0,0 @@
|
||||||
|
|
||||||
user = get "http://server/path"
|
|
||||||
|
|
||||||
user = post "http://server/path", "data"
|
|
||||||
|
|
||||||
Talk “ The user area is” + user.area, user.validuser, user.user
|
|
|
@ -1,26 +0,0 @@
|
||||||
talk "Qual seu pedido?"
|
|
||||||
hear pedido
|
|
||||||
talk "Qual seu e-mail?"
|
|
||||||
hear email
|
|
||||||
talk "Obrigado, seu pedido será processado e retornamos."
|
|
||||||
ask payment
|
|
||||||
|
|
||||||
|
|
||||||
talk "Qual seu pedido?"
|
|
||||||
hear pedido
|
|
||||||
talk "Obrigado. Agora informe seu nome:"
|
|
||||||
Hear nome
|
|
||||||
Talk "Obrigado" + nome + "! Agora falta saber onde vamos entregar. Qual seu endereço?"
|
|
||||||
Hear endereço
|
|
||||||
Save "BistroBot.gbdata\pedidos.xlsx", nome, pedido, endereço, phone
|
|
||||||
Talk "Aguarde, enquanto eu calculo o valor total do seu pedido. Volto em alguns minutos, aguarde!"
|
|
||||||
Total = Ask "+5521999995555", "Qual o valor para o pedido da(o)" + nome +"?"
|
|
||||||
ask payment Total
|
|
||||||
|
|
||||||
Talk "Qual seunome? "
|
|
||||||
Hear nome
|
|
||||||
Talk "Qual o valor pedido?"
|
|
||||||
Hear pedido
|
|
||||||
Save "Contoso.gbdata\ Aprovações.xlsx", nome, pedido, phone
|
|
||||||
Ask "+5521999995555", "Aprove por favor o pedido tal "
|
|
||||||
Talk "Sua aprovação foi enviada, aguarde."
|
|
|
@ -1,11 +0,0 @@
|
||||||
|
|
||||||
talk "O seu nome, por favor?"
|
|
||||||
hear nome
|
|
||||||
|
|
||||||
talk "Qual seu pedido?"
|
|
||||||
hear details
|
|
||||||
|
|
||||||
talk "Valeu " + nome + "! Agora falta saber onde vamos entregar. \nQual seu endereço?"
|
|
||||||
hear address
|
|
||||||
|
|
||||||
save "Pedidos.xlsx", id, nome, from, address, details, today
|
|
|
@ -1,37 +0,0 @@
|
||||||
' General Bots Copyright (c) pragmatismo.cloud. All rights reserved. Licensed under the AGPL-3.0.
|
|
||||||
|
|
||||||
talk "Please, tell me what is the Bot name?"
|
|
||||||
hear title
|
|
||||||
|
|
||||||
talk "If you tell me your username/password, I can show service subscription list to you."
|
|
||||||
talk "What is your Username (eg.: human@domain.bot)"
|
|
||||||
hear email
|
|
||||||
|
|
||||||
talk "What is your Password"
|
|
||||||
hear password
|
|
||||||
|
|
||||||
talk "Your password? (Will be discarded after sigining process)"
|
|
||||||
talk "Can you describe in a few words what the bot is about?"
|
|
||||||
hear description
|
|
||||||
|
|
||||||
talk "Please, paste the Subscription ID (Azure):"
|
|
||||||
hear subscriptionId
|
|
||||||
|
|
||||||
talk "Please, provide the cloud location just like 'westus'?"
|
|
||||||
hear location
|
|
||||||
|
|
||||||
talk "Please, provide the Authoring Key for NLP service (LUIS)?"
|
|
||||||
hear authoringKey
|
|
||||||
|
|
||||||
talk "Sorry, this part cannot be automated yet due to Microsoft schedule, please go to https://apps.dev.microsoft.com/portal/register-app to generate manually an App ID and App Secret."
|
|
||||||
wait 5
|
|
||||||
|
|
||||||
talk "Please, provide the App ID you just generated:"
|
|
||||||
hear appId
|
|
||||||
|
|
||||||
talk "Please, provide the Generated Password:"
|
|
||||||
hear appPassword
|
|
||||||
|
|
||||||
talk "Now, I am going to create a Bot farm... Wait 5 minutes or more..."
|
|
||||||
|
|
||||||
create a bot farm using title, email, password, location, authoringKey, appId, appPassword, subscriptionId
|
|
|
@ -1,25 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
talk "qual seu nome?"
|
|
||||||
hear nome
|
|
||||||
talk "qual seu e-mail?"
|
|
||||||
hear email
|
|
||||||
|
|
||||||
documento = "meutemplate.docx", nome, email,
|
|
||||||
|
|
||||||
send file documento
|
|
||||||
|
|
||||||
save file documento, "curriculos/nome" + ".docx"
|
|
||||||
|
|
||||||
' $name
|
|
||||||
|
|
||||||
'$trabalho
|
|
||||||
|
|
||||||
'Experiência
|
|
||||||
'$ano1
|
|
||||||
'$oquefoifeitoAno1
|
|
||||||
'$ano2
|
|
||||||
'$oquefoifeitoAno2
|
|
||||||
'$ano3
|
|
||||||
'$oquefoifeitoAno1
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
rem hi
|
|
||||||
|
|
||||||
talk "Qual seu nome?"
|
|
||||||
hear name
|
|
||||||
|
|
||||||
talk "Qual seu CPF?"
|
|
||||||
hear CPF
|
|
||||||
|
|
||||||
talk "Por que você abrirá este chamado?"
|
|
||||||
hear translated motivo
|
|
||||||
|
|
||||||
talk "Seu nome: " + name
|
|
||||||
talk "Você disse em Português " + motivo.
|
|
|
@ -1,3 +0,0 @@
|
||||||
Últimas notícias
|
|
||||||
Contato
|
|
||||||
Ofertas
|
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"botId":"pragmatismo-ai-prd",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Bot pragmatismo.",
|
|
||||||
"license": "Private"
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
{
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"title": "Bots & AI",
|
|
||||||
"description": "Bots & inteligência artificial.",
|
|
||||||
"id": "bots-ai",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"title": "General Bots",
|
|
||||||
"description": "Plataforma de bots da pragmatismo.cloud.",
|
|
||||||
"id": "general-bots"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Cortana Intelligence Suite",
|
|
||||||
"description": "Suite de Big Data da Microsoft.",
|
|
||||||
"id": "cortana"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Produtividade",
|
|
||||||
"description": "Artigos sobre sistemas Internos.",
|
|
||||||
"id": "produtividade",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"title": "Microsoft Project Online",
|
|
||||||
"description": "Artigos sobre o Microsoft Project Online.",
|
|
||||||
"id": "msproject"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "SharePoint",
|
|
||||||
"description": "SharePoint, sites e serviços.",
|
|
||||||
"id": "sharepoint"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Office 365",
|
|
||||||
"description": "Plataforma colaborativa moderna da Microsoft.",
|
|
||||||
"id": "office365"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Microsoft Dynamics",
|
|
||||||
"description": "Artigos sobre plataforma de CRM da Microsoft.",
|
|
||||||
"id": "msdynamics"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Power BI",
|
|
||||||
"description": "Dashboards modernos e intuitivos.",
|
|
||||||
"id": "powerbi"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Sobre",
|
|
||||||
"description": "Artigos sobre o Bot da pragmatismo.cloud",
|
|
||||||
"id": "sobre"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 2 KiB |
|
|
@ -1,171 +0,0 @@
|
||||||
body {
|
|
||||||
background-color: #dadada !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader {
|
|
||||||
opacity: 1 !important;
|
|
||||||
filter: opacity(100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.gb-quality-button-yes {
|
|
||||||
width: 54px;
|
|
||||||
text-decoration: none;
|
|
||||||
text-transform: uppercase;
|
|
||||||
background-color: green;
|
|
||||||
color: white;
|
|
||||||
padding: 2px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: 0.9s;
|
|
||||||
transition-delay: 0.3s;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gb-quality-button-no {
|
|
||||||
width: 54px;
|
|
||||||
text-decoration: none;
|
|
||||||
text-transform: uppercase;
|
|
||||||
background-color: red;
|
|
||||||
color: white;
|
|
||||||
padding: 2px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: 0.9s;
|
|
||||||
transition-delay: 0.3s;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gb-markdown-player-quality {
|
|
||||||
background-color: #f5e4a8;
|
|
||||||
padding: 4px;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 14px;
|
|
||||||
left: -9px;
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 5px;
|
|
||||||
color: #52514e;
|
|
||||||
border: 1px solid #b2a46e;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-player {
|
|
||||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-player-container {
|
|
||||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-player-link {
|
|
||||||
cursor: pointer !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gb-bullet-player {
|
|
||||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif !important;
|
|
||||||
background: white;
|
|
||||||
height: 95%;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gb-bullet-player-item {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gb-image-player-outter-div {}
|
|
||||||
|
|
||||||
.gb-image-player-img {}
|
|
||||||
|
|
||||||
.gb-bullet-player-outter-div {}
|
|
||||||
|
|
||||||
.gb-video-player-wrapper {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gb-video-react-player {
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App {
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App .body {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.body {
|
|
||||||
flex-basis: 12em;
|
|
||||||
/* Default value of the element before distribuing the remaing space */
|
|
||||||
flex-grow: 0;
|
|
||||||
/* Defined the ability to groe */
|
|
||||||
flex-shrink: 0;
|
|
||||||
/* Defines the ability to shrink */
|
|
||||||
max-width: 12em;
|
|
||||||
order: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-player-container {
|
|
||||||
overflow: auto;
|
|
||||||
max-height: 90%;
|
|
||||||
font-family: "Open Sans", sans-serif;
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-player-scroll {
|
|
||||||
height: 1500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 1000px) {
|
|
||||||
.media-player-scroll h1 {
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
.media-player-scroll p {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.media-player-scroll li {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 451px) {
|
|
||||||
.media-player {
|
|
||||||
position: relative;
|
|
||||||
zoom: 90%;
|
|
||||||
height: 94% !important;
|
|
||||||
width: 95% !important;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-right: -40px;
|
|
||||||
}
|
|
||||||
.gb-markdown-player-quality {
|
|
||||||
bottom: -1px;
|
|
||||||
left: -3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 451px) {
|
|
||||||
.media-player {
|
|
||||||
position: relative;
|
|
||||||
zoom: 90%;
|
|
||||||
height: 100% !important;
|
|
||||||
width: 95% !important;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-left: 20px;
|
|
||||||
margin-right: -40px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
.webchat > div {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.webchat {
|
|
||||||
background-color: white !important;
|
|
||||||
left: 57%;
|
|
||||||
right: 0%;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
overflow: auto !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 1000px) {
|
|
||||||
.webchat {
|
|
||||||
display: inline-block !important;
|
|
||||||
width: 96% !important;
|
|
||||||
height: 57% !important;
|
|
||||||
font-family: 'Open Sans', sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
left: 50%;
|
|
||||||
top: 41%;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
margin-left: -48%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 1000px) {
|
|
||||||
.webchat {
|
|
||||||
display: inline-block !important;
|
|
||||||
width: 50% !important;
|
|
||||||
font-family: 'Open Sans', sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
top: 1% !important;
|
|
||||||
|
|
||||||
height: 96%;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
margin-left: -8%;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
border-bottom: 4px solid #4f4f4f;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
.body .container { padding: 1em;width: 100%;height: 100% }
|
|
||||||
|
|
||||||
.body .ms-Breadcrumb {
|
|
||||||
margin-bottom: 1em;
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.body .selection {
|
|
||||||
height: calc(100vh - 16.5em);
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.body .selection .selection-item {
|
|
||||||
display: flex;
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.body .selection .selection-item .name { margin-left: 1em; }
|
|
|
@ -1,8 +0,0 @@
|
||||||
.footer {
|
|
||||||
align-items: center;
|
|
||||||
background-color: #450a64;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-container { color: white; }
|
|
|
@ -1,31 +0,0 @@
|
||||||
@media screen and (max-width: 1000px) {
|
|
||||||
.player {
|
|
||||||
width: 93% !important;
|
|
||||||
height: 26% !important;
|
|
||||||
border: 7px solid #272727;
|
|
||||||
position: absolute;
|
|
||||||
top: 9%;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -48%;
|
|
||||||
background: url(../images/general-bot-background.jpg), WHITE;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: contain;
|
|
||||||
background-position: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 1000px) {
|
|
||||||
.player {
|
|
||||||
display: inline-block;
|
|
||||||
width: 46% !important;
|
|
||||||
height: 81% !important;
|
|
||||||
border: 7px solid #272727;
|
|
||||||
background: url(../images/general-bot-background.jpg), WHITE;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: contain;
|
|
||||||
background-position: center;
|
|
||||||
position: absolute;
|
|
||||||
left: 1%;
|
|
||||||
top: 15%;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
.media {
|
|
||||||
margin-top: 20px;
|
|
||||||
height: 280px !important;
|
|
||||||
width: 200px !important;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
.NavBar {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 0.2em 0.5em;
|
|
||||||
border-bottom-width: 1px;
|
|
||||||
color:black;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
.logo {
|
|
||||||
padding-top: 4em;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
.NavBar .searchbox { width: 20em; }
|
|
||||||
|
|
||||||
.NavBar .searchbox .ms-SearchBox {
|
|
||||||
background-color: white;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
|
@ -1,199 +0,0 @@
|
||||||
.ms-Nav {
|
|
||||||
background: #222;
|
|
||||||
color: white;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ms-Nav-link {
|
|
||||||
color: white !important;
|
|
||||||
background-color: #222222 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ms-Nav-link a:active {
|
|
||||||
border-right: 2px solid white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ms-Nav-compositeLink .ms-Nav-chevronButton.ms-Nav-chevronButton--link {
|
|
||||||
background: #222222 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ms-Nav-compositeLink.is-selected .ms-Nav-chevronButton,
|
|
||||||
.ms-Nav-compositeLink.is-selected a {
|
|
||||||
padding-left: 70px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[dir="ltr"] .ms-Nav-compositeLink.is-selected .ms-Nav-chevronButton:after,
|
|
||||||
html[dir="ltr"] .ms-Nav-compositeLink.is-selected a:after {
|
|
||||||
border-left: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 419px) {
|
|
||||||
.sidebar {
|
|
||||||
display: inline-block !important;
|
|
||||||
background-color: #3f3f3f !important;
|
|
||||||
height: 8%;
|
|
||||||
width: 100% !important;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tittleSideBarMenu {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconMenu {
|
|
||||||
color: #d1d1d1;
|
|
||||||
font-size: 13px;
|
|
||||||
display: inline;
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
.iconMenu:hover {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.IconsMenu {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
margin-top: -23px;
|
|
||||||
height: 22px;
|
|
||||||
width: 300px;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -150px;
|
|
||||||
text-align: center;
|
|
||||||
font-family: "Open Sans", sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconText {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 520px) and (max-width:1000px) {
|
|
||||||
.tittleSideBarMenu {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.sidebar {
|
|
||||||
display: inline-block !important;
|
|
||||||
background-color: #3f3f3f !important;
|
|
||||||
height: 8%;
|
|
||||||
width: 100% !important;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
background-image: url(../images/bot-logo.png);
|
|
||||||
background-position: 2px 2px;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: contain;
|
|
||||||
}
|
|
||||||
.IconsMenu {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
margin-top: -11px;
|
|
||||||
height: 22px;
|
|
||||||
width: 416px;
|
|
||||||
left: 100px !important;
|
|
||||||
margin-left: 0px !important;
|
|
||||||
text-align: center;
|
|
||||||
font-family: "Open Sans", sans-serif;
|
|
||||||
}
|
|
||||||
.iconMenu {
|
|
||||||
color: #d1d1d1;
|
|
||||||
}
|
|
||||||
.iconMenu:hover {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 420px) and (max-width: 1000px) {
|
|
||||||
.sidebar {
|
|
||||||
display: inline-block !important;
|
|
||||||
background-color: #3f3f3f !important;
|
|
||||||
height: 8%;
|
|
||||||
width: 100% !important;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
.tittleSideBarMenu {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconMenu {
|
|
||||||
color: #d1d1d1;
|
|
||||||
font-size: 14px;
|
|
||||||
display: inline;
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
.iconMenu:hover {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.IconsMenu {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
margin-top: -11px;
|
|
||||||
height: 22px;
|
|
||||||
width: 416px;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -208px;
|
|
||||||
text-align: center;
|
|
||||||
font-family: "Open Sans", sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconText {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media screen and (min-width: 1000px) {
|
|
||||||
.sidebar {
|
|
||||||
display: inline-block !important;
|
|
||||||
background-color: #3f3f3f !important;
|
|
||||||
height: 15%;
|
|
||||||
position: absolute;
|
|
||||||
top: 1%;
|
|
||||||
left: 1%;
|
|
||||||
width: 46% !important;
|
|
||||||
border-right: 14px solid #3f3f3f !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tittleSideBarMenu {
|
|
||||||
color: white;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconMenu {
|
|
||||||
color: #d1d1d1;
|
|
||||||
font-size: 14px;
|
|
||||||
text-align: center;
|
|
||||||
margin-right: 20px;
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
.iconMenu:hover {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.IconsMenu {
|
|
||||||
width: 520px;
|
|
||||||
display: inline-flex;
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -249px;
|
|
||||||
bottom: 10px;
|
|
||||||
height: 22px;
|
|
||||||
font-family: "Open Sans", sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconText {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.iconText:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
body {
|
|
||||||
font-family: 'Open Sans', sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Main Layout rules */
|
|
||||||
|
|
||||||
.App { min-height: 100vh; }
|
|
||||||
|
|
||||||
.App {
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App .body {
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.body .sidebar { order: -1; }
|
|
||||||
|
|
||||||
.body .content { flex: 1; }
|
|
||||||
|
|
||||||
.body .sidebar {
|
|
||||||
flex: 0 0 12em;
|
|
||||||
max-width: 12em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App .header { height: 4em; }
|
|
||||||
|
|
||||||
.App .footer { height: 4em; }
|
|
||||||
|
|
||||||
/** Text */
|
|
||||||
|
|
||||||
.text-red { color: red; }
|
|
|
@ -1,50 +0,0 @@
|
||||||
{
|
|
||||||
"accent": "Red",
|
|
||||||
"avatarSize": 40,
|
|
||||||
|
|
||||||
"backgroundColor": "White",
|
|
||||||
|
|
||||||
"bubbleBackground": "White",
|
|
||||||
"bubbleBorder": "solid 1px #E6E6E6",
|
|
||||||
"bubbleBorderRadius": 2,
|
|
||||||
"bubbleFromUserBackground": "White",
|
|
||||||
"bubbleFromUserBorder": "solid 1px #E6E6E6",
|
|
||||||
"bubbleFromUserBorderRadius": 2,
|
|
||||||
"bubbleFromUserTextColor": "Black",
|
|
||||||
"bubbleImageHeight": 240,
|
|
||||||
"bubbleMaxWidth": 480,
|
|
||||||
"bubbleMinHeight": 40,
|
|
||||||
"bubbleMinWidth": 250,
|
|
||||||
"bubbleTextColor": "Black",
|
|
||||||
|
|
||||||
"hideSendBox": false,
|
|
||||||
|
|
||||||
"microphoneButtonColorOnDictate": "#F33",
|
|
||||||
|
|
||||||
"paddingRegular": 10,
|
|
||||||
"paddingWide": 20,
|
|
||||||
|
|
||||||
"sendBoxButtonColor": "#999",
|
|
||||||
"sendBoxButtonColorOnDisabled": "#CCC",
|
|
||||||
"sendBoxButtonColorOnFocus": "#333",
|
|
||||||
"sendBoxButtonColorOnHover": "#333",
|
|
||||||
|
|
||||||
"sendBoxHeight": 40,
|
|
||||||
|
|
||||||
"showSpokenText": false,
|
|
||||||
|
|
||||||
"suggestedActionBackground": "White",
|
|
||||||
"suggestedActionBorder": "solid 2px",
|
|
||||||
"suggestedActionBorderRadius": 0,
|
|
||||||
"suggestedActionDisabledBackground": "White",
|
|
||||||
"suggestedActionDisabledBorder": "solid 2px #E6E6E6",
|
|
||||||
"suggestedActionHeight": 40,
|
|
||||||
"transcriptOverlayButtonBackground": "rgba(0, 0, 0, .6)",
|
|
||||||
"transcriptOverlayButtonBackgroundOnFocus": "rgba(0, 0, 0, .8)",
|
|
||||||
"transcriptOverlayButtonBackgroundOnHover": "rgba(0, 0, 0, .8)",
|
|
||||||
"transcriptOverlayButtonColor": "White",
|
|
||||||
"transcriptOverlayButtonColorOnFocus": "White",
|
|
||||||
"transcriptOverlayButtonColorOnHover": "White",
|
|
||||||
|
|
||||||
"videoHeight": 270
|
|
||||||
}
|
|
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 958 B |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 247 KiB |
Before Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 1.7 KiB |
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Default General Bots theme.",
|
|
||||||
"authors": "pragmatismo.cloud",
|
|
||||||
"license": "AGPL-3.0"
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,11 +1,10 @@
|
||||||
<!--
|
<!--
|
||||||
| ( )_ _ |
|
/*****************************************************************************\
|
||||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) |
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| | | ( )_) | |
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
| (_) \___/' |
|
|
||||||
| |
|
| |
|
||||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
| Licensed under the AGPL-3.0. |
|
| Licensed under the AGPL-3.0. |
|
||||||
|
@ -19,7 +18,7 @@
|
||||||
| in the LICENSE file you have received along with this program. |
|
| in the LICENSE file you have received along with this program. |
|
||||||
| |
|
| |
|
||||||
| This program is distributed in the hope that it will be useful, |
|
| This program is distributed in the hope that it will be useful, |
|
||||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
| GNU Affero General Public License for more details. |
|
| GNU Affero General Public License for more details. |
|
||||||
| |
|
| |
|
||||||
|
@ -28,6 +27,7 @@
|
||||||
| trademark license. Therefore any rights, title and interest in |
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
| our trademarks remain entirely with us. |
|
| our trademarks remain entirely with us. |
|
||||||
| |
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
<link rel="stylesheet" type="text/css" href="/themes/{theme}/css/App.css" />
|
<link rel="stylesheet" type="text/css" href="/themes/{theme}/css/App.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="/themes/{theme}/css/SideBarMenu.css" />
|
<link rel="stylesheet" type="text/css" href="/themes/{theme}/css/SideBarMenu.css" />
|
||||||
|
|
||||||
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
|
<script src="./js/webchat.js"></script>
|
||||||
<title>{title} - General Bots Community Edition</title>
|
<title>{title} - General Bots Community Edition</title>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
2
packages/default.gbui/public/js/webchat.js
Normal file
|
@ -168,9 +168,18 @@ class GBUIApp extends React.Component {
|
||||||
let _this_ = this;
|
let _this_ = this;
|
||||||
window['botchatDebug'] = true;
|
window['botchatDebug'] = true;
|
||||||
|
|
||||||
const line = new DirectLine({
|
const line = instanceClient.webchatToken ?
|
||||||
|
new DirectLine({
|
||||||
token: instanceClient.webchatToken
|
token: instanceClient.webchatToken
|
||||||
|
}):
|
||||||
|
new DirectLine({
|
||||||
|
domain: instanceClient.domain,
|
||||||
|
secret: null,
|
||||||
|
token: null,
|
||||||
|
webSocket: false // defaults to true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
;
|
||||||
_this_.setState({ line: line });
|
_this_.setState({ line: line });
|
||||||
|
|
||||||
line.connectionStatus$.subscribe(connectionStatus => {
|
line.connectionStatus$.subscribe(connectionStatus => {
|
||||||
|
|
|
@ -36,6 +36,7 @@ class ChatPane extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Chat
|
<Chat
|
||||||
|
|
||||||
ref={(chat) => { this.chat = chat; }}
|
ref={(chat) => { this.chat = chat; }}
|
||||||
botConnection={this.props.botConnection}
|
botConnection={this.props.botConnection}
|
||||||
user={{ id: "webUser@gb", name: "You" }}
|
user={{ id: "webUser@gb", name: "You" }}
|
||||||
|
|
|
@ -49,7 +49,7 @@ class SideBarMenu extends React.Component {
|
||||||
<div className="tittleSideBarMenu">
|
<div className="tittleSideBarMenu">
|
||||||
<img
|
<img
|
||||||
className="pragmatismoLogo"
|
className="pragmatismoLogo"
|
||||||
src={this.props.instance.botId + "/cache/" + this.props.instance.logo}
|
src={this.props.instance.logo}
|
||||||
alt="General Bots Logo" />
|
alt="General Bots Logo" />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -36,6 +36,7 @@ import { GBLog, GBMinInstance, GBService } from 'botlib';
|
||||||
import { GBServer } from '../../../src/app.js';
|
import { GBServer } from '../../../src/app.js';
|
||||||
import { SecService } from '../../security.gbapp/services/SecService.js';
|
import { SecService } from '../../security.gbapp/services/SecService.js';
|
||||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||||
|
import { GBUtil } from '../../../src/util.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support for Google Chat.
|
* Support for Google Chat.
|
||||||
|
@ -90,10 +91,7 @@ export class GoogleChatDirectLine extends GBService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setup (setUrl) {
|
public async setup (setUrl) {
|
||||||
this.directLineClient = new Swagger({
|
this.directLineClient = await GBUtil.getDirectLineClient(this.min);
|
||||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
||||||
usePromise: true
|
|
||||||
});
|
|
||||||
const client = await this.directLineClient;
|
const client = await this.directLineClient;
|
||||||
|
|
||||||
client.clientAuthorizations.add(
|
client.clientAuthorizations.add(
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| ( )_ _ |
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__,\| (˅) |( (_) ) |
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
| | | ( )_) | |
|
|
||||||
| (_) \___/' |
|
|
||||||
| |
|
| |
|
||||||
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
| Licensed under the AGPL-3.0. |
|
| Licensed under the AGPL-3.0. |
|
||||||
| |
|
| |
|
||||||
| According to our dual licensing model,this program can be used either |
|
| According to our dual licensing model, this program can be used either |
|
||||||
| under the terms of the GNU Affero General Public License,version 3, |
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
| or under a proprietary license. |
|
| or under a proprietary license. |
|
||||||
| |
|
| |
|
||||||
| The texts of the GNU Affero General Public License with an additional |
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
@ -19,13 +17,13 @@
|
||||||
| in the LICENSE file you have received along with this program. |
|
| in the LICENSE file you have received along with this program. |
|
||||||
| |
|
| |
|
||||||
| This program is distributed in the hope that it will be useful, |
|
| This program is distributed in the hope that it will be useful, |
|
||||||
| but WITHOUT ANY WARRANTY,without even the implied warranty of |
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
| GNU Affero General Public License for more details. |
|
| GNU Affero General Public License for more details. |
|
||||||
| |
|
| |
|
||||||
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
| The licensing of the program under the AGPLv3 does not imply a |
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
| trademark license. Therefore any rights,title and interest in |
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
| our trademarks remain entirely with us. |
|
| our trademarks remain entirely with us. |
|
||||||
| |
|
| |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
@ -33,7 +31,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { GBMinInstance } from 'botlib';
|
import { GBMinInstance } from 'botlib';
|
||||||
import { OpenAIClient } from '@azure/openai';
|
import OpenAI from 'openai';
|
||||||
|
|
||||||
import { AzureKeyCredential } from '@azure/core-auth';
|
import { AzureKeyCredential } from '@azure/core-auth';
|
||||||
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords';
|
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords';
|
||||||
import Path from 'path';
|
import Path from 'path';
|
||||||
|
@ -47,7 +46,6 @@ import { GBLogEx } from '../../core.gbapp/services/GBLogEx';
|
||||||
* Image processing services of conversation to be called by BASIC.
|
* Image processing services of conversation to be called by BASIC.
|
||||||
*/
|
*/
|
||||||
export class ImageServices {
|
export class ImageServices {
|
||||||
|
|
||||||
public async getImageFromPrompt({ pid, prompt }) {
|
public async getImageFromPrompt({ pid, prompt }) {
|
||||||
const { min, user, params } = await DialogKeywords.getProcessInfo(pid);
|
const { min, user, params } = await DialogKeywords.getProcessInfo(pid);
|
||||||
|
|
||||||
|
@ -57,11 +55,12 @@ export class ImageServices {
|
||||||
|
|
||||||
if (azureOpenAIKey) {
|
if (azureOpenAIKey) {
|
||||||
// Initialize the Azure OpenAI client
|
// Initialize the Azure OpenAI client
|
||||||
const client = new OpenAIClient(azureOpenAIEndpoint, new AzureKeyCredential(azureOpenAIKey));
|
|
||||||
|
const client = new OpenAI({ apiKey: azureOpenAIKey, baseURL: azureOpenAIEndpoint });
|
||||||
|
|
||||||
// Make a request to the image generation endpoint
|
// Make a request to the image generation endpoint
|
||||||
|
|
||||||
const response = await client.getImageGeneration(azureOpenAIImageModel, {
|
const response = await client.images.generate({
|
||||||
prompt: prompt,
|
prompt: prompt,
|
||||||
n: 1,
|
n: 1,
|
||||||
size: '1024x1024'
|
size: '1024x1024'
|
||||||
|
@ -77,7 +76,7 @@ export class ImageServices {
|
||||||
|
|
||||||
GBLogEx.info(min, `BASIC: DALL-E image generated at ${url}.`);
|
GBLogEx.info(min, `BASIC: DALL-E image generated at ${url}.`);
|
||||||
|
|
||||||
return {localName, url};
|
return { localName, url };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -746,7 +746,7 @@ export class KBService implements IGBKBService {
|
||||||
let doc = await loader.load();
|
let doc = await loader.load();
|
||||||
let content = doc[0].pageContent;
|
let content = doc[0].pageContent;
|
||||||
|
|
||||||
if (file.name.endsWith('zap.docx')){
|
if (file.name.endsWith('zap.docx')) {
|
||||||
await min.whatsAppDirectLine.createOrUpdateTemplate(min, file.name, content);
|
await min.whatsAppDirectLine.createOrUpdateTemplate(min, file.name, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1218,7 +1218,7 @@ export class KBService implements IGBKBService {
|
||||||
instance: IGBInstance
|
instance: IGBInstance
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
let subjectsLoaded;
|
let subjectsLoaded;
|
||||||
if (menuFile) {
|
if (Fs.existsSync(menuFile)) {
|
||||||
// Loads menu.xlsx and finds worksheet.
|
// Loads menu.xlsx and finds worksheet.
|
||||||
|
|
||||||
const workbook = new Excel.Workbook();
|
const workbook = new Excel.Workbook();
|
||||||
|
@ -1369,10 +1369,12 @@ export class KBService implements IGBKBService {
|
||||||
const p = await deployer.deployPackageToStorage(instance.instanceId, packageName);
|
const p = await deployer.deployPackageToStorage(instance.instanceId, packageName);
|
||||||
await this.importKbPackage(min, localPath, p, instance);
|
await this.importKbPackage(min, localPath, p, instance);
|
||||||
GBDeployer.mountGBKBAssets(packageName, min.botId, localPath);
|
GBDeployer.mountGBKBAssets(packageName, min.botId, localPath);
|
||||||
|
|
||||||
|
if (GBConfigService.get('STORAGE_NAME')) {
|
||||||
const service = await AzureDeployerService.createInstance(deployer);
|
const service = await AzureDeployerService.createInstance(deployer);
|
||||||
const searchIndex = instance.searchIndex ? instance.searchIndex : GBServer.globals.minBoot.instance.searchIndex;
|
const searchIndex = instance.searchIndex ? instance.searchIndex : GBServer.globals.minBoot.instance.searchIndex;
|
||||||
await deployer.rebuildIndex(instance, service.getKBSearchSchema(searchIndex));
|
await deployer.rebuildIndex(instance, service.getKBSearchSchema(searchIndex));
|
||||||
|
}
|
||||||
min['groupCache'] = await KBService.getGroupReplies(instance.instanceId);
|
min['groupCache'] = await KBService.getGroupReplies(instance.instanceId);
|
||||||
await KBService.RefreshNER(min);
|
await KBService.RefreshNER(min);
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import * as Fs from 'fs';
|
||||||
import mkdirp from 'mkdirp';
|
import mkdirp from 'mkdirp';
|
||||||
import urlJoin from 'url-join';
|
import urlJoin from 'url-join';
|
||||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||||
|
import { GBServer } from '../../../src/app.js';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,8 +53,11 @@ export class SecService extends GBService {
|
||||||
user.displayName = displayName;
|
user.displayName = displayName;
|
||||||
user.email = email;
|
user.email = email;
|
||||||
user.defaultChannel = channelName;
|
user.defaultChannel = channelName;
|
||||||
|
GBServer.globals.users [user.userId] = user;
|
||||||
return await user.save();
|
if(user.changed()){
|
||||||
|
await user.save();
|
||||||
|
}
|
||||||
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,6 +78,7 @@ export class SecService extends GBService {
|
||||||
const user = await GuaribasUser.findOne(options);
|
const user = await GuaribasUser.findOne(options);
|
||||||
|
|
||||||
user.conversationReference = conversationReference;
|
user.conversationReference = conversationReference;
|
||||||
|
GBServer.globals.users [user.userId] = user;
|
||||||
await user.save();
|
await user.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +87,7 @@ export class SecService extends GBService {
|
||||||
const user = await GuaribasUser.findOne(options);
|
const user = await GuaribasUser.findOne(options);
|
||||||
|
|
||||||
user.conversationReference = conversationReference;
|
user.conversationReference = conversationReference;
|
||||||
|
GBServer.globals.users [user.userId] = user;
|
||||||
await user.save();
|
await user.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +98,7 @@ export class SecService extends GBService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
user.locale = locale;
|
user.locale = locale;
|
||||||
|
GBServer.globals.users [user.userId] = user;
|
||||||
return await user.save();
|
return await user.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +109,7 @@ export class SecService extends GBService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
user.hearOnDialog = dialogName;
|
user.hearOnDialog = dialogName;
|
||||||
|
GBServer.globals.users [user.userId] = user;
|
||||||
return await user.save();
|
return await user.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +120,7 @@ export class SecService extends GBService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
user.instanceId = instanceId;
|
user.instanceId = instanceId;
|
||||||
|
GBServer.globals.users [user.userId] = user;
|
||||||
return await user.save();
|
return await user.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,9 +166,11 @@ export class SecService extends GBService {
|
||||||
agent.instanceId = user.instanceId;
|
agent.instanceId = user.instanceId;
|
||||||
agent.agentMode = 'self';
|
agent.agentMode = 'self';
|
||||||
agent.agentSystemId = null;
|
agent.agentSystemId = null;
|
||||||
|
GBServer.globals.users [agent.userId] = user;
|
||||||
await agent.save();
|
await agent.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GBServer.globals.users [user.userId] = user;
|
||||||
await user.save();
|
await user.save();
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
|
@ -306,6 +314,7 @@ export class SecService extends GBService {
|
||||||
}
|
}
|
||||||
obj[name] = value;
|
obj[name] = value;
|
||||||
user.params = JSON.stringify(obj);
|
user.params = JSON.stringify(obj);
|
||||||
|
GBServer.globals.users [userId] = user;
|
||||||
return await user.save();
|
return await user.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -30,7 +30,6 @@
|
||||||
|
|
||||||
import mime from 'mime-types';
|
import mime from 'mime-types';
|
||||||
import urlJoin from 'url-join';
|
import urlJoin from 'url-join';
|
||||||
import SwaggerClient from 'swagger-client';
|
|
||||||
import Path from 'path';
|
import Path from 'path';
|
||||||
import Fs from 'fs';
|
import Fs from 'fs';
|
||||||
import { GBLog, GBMinInstance, GBService, IGBPackage } from 'botlib';
|
import { GBLog, GBMinInstance, GBService, IGBPackage } from 'botlib';
|
||||||
|
@ -46,7 +45,7 @@ import qrcode from 'qrcode-terminal';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { GBSSR } from '../../core.gbapp/services/GBSSR.js';
|
import { GBSSR } from '../../core.gbapp/services/GBSSR.js';
|
||||||
import pkg from 'whatsapp-web.js';
|
import pkg from 'whatsapp-web.js';
|
||||||
import fetch, { Response } from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js';
|
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js';
|
||||||
import { ChatServices } from '../../gpt.gblib/services/ChatServices.js';
|
import { ChatServices } from '../../gpt.gblib/services/ChatServices.js';
|
||||||
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
||||||
|
@ -85,12 +84,10 @@ export class WhatsappDirectLine extends GBService {
|
||||||
public botId: string;
|
public botId: string;
|
||||||
public botNumber: string;
|
public botNumber: string;
|
||||||
public min: GBMinInstance;
|
public min: GBMinInstance;
|
||||||
private directLineSecret: string;
|
|
||||||
private locale: string = 'pt-BR';
|
private locale: string = 'pt-BR';
|
||||||
provider: any;
|
provider: any;
|
||||||
INSTANCE_URL = 'https://api.maytapi.com/api';
|
INSTANCE_URL = 'https://api.maytapi.com/api';
|
||||||
private customClient: any;
|
private customClient: any;
|
||||||
private groupId;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
min: GBMinInstance,
|
min: GBMinInstance,
|
||||||
|
@ -105,12 +102,11 @@ export class WhatsappDirectLine extends GBService {
|
||||||
|
|
||||||
this.min = min;
|
this.min = min;
|
||||||
this.botId = botId;
|
this.botId = botId;
|
||||||
this.directLineSecret = directLineSecret;
|
|
||||||
this.whatsappServiceKey = whatsappServiceKey;
|
this.whatsappServiceKey = whatsappServiceKey;
|
||||||
this.whatsappServiceNumber = whatsappServiceNumber;
|
this.whatsappServiceNumber = whatsappServiceNumber;
|
||||||
this.whatsappServiceUrl = whatsappServiceUrl;
|
this.whatsappServiceUrl = whatsappServiceUrl;
|
||||||
this.provider = whatsappServiceKey === 'internal' ? 'GeneralBots' : 'meta';
|
this.provider = whatsappServiceKey === 'internal' ? 'GeneralBots' : 'meta';
|
||||||
this.groupId = groupId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async asyncForEach(array, callback) {
|
public static async asyncForEach(array, callback) {
|
||||||
|
@ -120,18 +116,8 @@ export class WhatsappDirectLine extends GBService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setup(setUrl: boolean) {
|
public async setup(setUrl: boolean) {
|
||||||
const client = await new SwaggerClient({
|
|
||||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
||||||
requestInterceptor: req => {
|
|
||||||
req.headers['Authorization'] = `Bearer ${this.min.instance.webchatKey}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.directLineClient = client;
|
this.directLineClient = GBUtil.getDirectLineClient(this.min);
|
||||||
|
|
||||||
// Warms up MSBF.
|
|
||||||
|
|
||||||
await client.apis.Conversations.Conversations_StartConversation();
|
|
||||||
|
|
||||||
let url: string;
|
let url: string;
|
||||||
let options: any;
|
let options: any;
|
||||||
|
@ -822,29 +808,25 @@ export class WhatsappDirectLine extends GBService {
|
||||||
const templateExists = templates.data.find(template => template.name === name);
|
const templateExists = templates.data.find(template => template.name === name);
|
||||||
|
|
||||||
if (templateExists) {
|
if (templateExists) {
|
||||||
// Step 2: Update the template
|
// // Step 2: Update the template
|
||||||
const updateTemplateEndpoint = `${baseUrl}/${templateExists.id}`;
|
// const updateTemplateEndpoint = `${baseUrl}/${templateExists.id}`;
|
||||||
|
|
||||||
// Removes the first HEADER element.
|
// const updateResponse = await fetch(updateTemplateEndpoint, {
|
||||||
|
// method: 'POST',
|
||||||
|
// headers: {
|
||||||
|
// Authorization: `Bearer ${accessToken}`,
|
||||||
|
// 'Content-Type': 'application/json'
|
||||||
|
// },
|
||||||
|
// body: JSON.stringify({
|
||||||
|
// components: data.components
|
||||||
|
// })
|
||||||
|
// });
|
||||||
|
|
||||||
data.components.shift();
|
// if (!updateResponse.ok) {
|
||||||
|
// throw new Error(`Failed to update template: ${name} ${await updateResponse.text()}`);
|
||||||
|
// }
|
||||||
|
|
||||||
const updateResponse = await fetch(updateTemplateEndpoint, {
|
GBLogEx.info(min, `Template update skiped: ${name}`);
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${accessToken}`,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
components: data.components
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!updateResponse.ok) {
|
|
||||||
throw new Error(`Failed to update template: ${name} ${await updateResponse.text()}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
GBLogEx.info(min, `Template updated: ${name}`);
|
|
||||||
} else {
|
} else {
|
||||||
// Step 3: Create the template
|
// Step 3: Create the template
|
||||||
const createTemplateEndpoint = `${baseUrl}/${businessAccountId}/message_templates`;
|
const createTemplateEndpoint = `${baseUrl}/${businessAccountId}/message_templates`;
|
||||||
|
|
|
@ -58,10 +58,12 @@ export class RootData {
|
||||||
public debugConversationId: any; // Used to self-message during debug.
|
public debugConversationId: any; // Used to self-message during debug.
|
||||||
public debuggers: any[]; // Client of attached Debugger instances by botId.
|
public debuggers: any[]; // Client of attached Debugger instances by botId.
|
||||||
public chatGPT: any; // ChatGPT API handle (shared Browser).
|
public chatGPT: any; // ChatGPT API handle (shared Browser).
|
||||||
|
public users: any[]; // Loaded users.
|
||||||
public dk;
|
public dk;
|
||||||
public wa;
|
public wa;
|
||||||
public sys;
|
public sys;
|
||||||
public dbg;
|
public dbg;
|
||||||
public img;
|
public img;
|
||||||
indexSemaphore: any;
|
indexSemaphore: any;
|
||||||
|
public webDavServer;
|
||||||
}
|
}
|
||||||
|
|
46
src/app.ts
|
@ -40,6 +40,7 @@ import bodyParser from 'body-parser';
|
||||||
import { GBLog, GBMinInstance, IGBCoreService, IGBInstance } from 'botlib';
|
import { GBLog, GBMinInstance, IGBCoreService, IGBInstance } from 'botlib';
|
||||||
import child_process from 'child_process';
|
import child_process from 'child_process';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
|
import { v2 as webdav } from 'webdav-server';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import httpProxy from 'http-proxy';
|
import httpProxy from 'http-proxy';
|
||||||
|
@ -89,6 +90,7 @@ export class GBServer {
|
||||||
this.initEndpointsDocs(server);
|
this.initEndpointsDocs(server);
|
||||||
|
|
||||||
GBServer.globals.server = server;
|
GBServer.globals.server = server;
|
||||||
|
|
||||||
GBServer.globals.httpsServer = null;
|
GBServer.globals.httpsServer = null;
|
||||||
GBServer.globals.webSessions = {};
|
GBServer.globals.webSessions = {};
|
||||||
GBServer.globals.processes = {};
|
GBServer.globals.processes = {};
|
||||||
|
@ -100,7 +102,10 @@ export class GBServer {
|
||||||
GBServer.globals.wwwroot = null;
|
GBServer.globals.wwwroot = null;
|
||||||
GBServer.globals.entryPointDialog = null;
|
GBServer.globals.entryPointDialog = null;
|
||||||
GBServer.globals.debuggers = [];
|
GBServer.globals.debuggers = [];
|
||||||
|
GBServer.globals.users = [];
|
||||||
GBServer.globals.indexSemaphore = new Mutex();
|
GBServer.globals.indexSemaphore = new Mutex();
|
||||||
|
GBServer.globals.webDavServer = new webdav.WebDAVServer();
|
||||||
|
GBServer.globals.webDavServer.start();
|
||||||
|
|
||||||
server.use(bodyParser.json());
|
server.use(bodyParser.json());
|
||||||
server.use(bodyParser.json({ limit: '1mb' }));
|
server.use(bodyParser.json({ limit: '1mb' }));
|
||||||
|
@ -117,21 +122,20 @@ export class GBServer {
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('uncaughtException', (err, p) => {
|
process.on('uncaughtException', (err, p) => {
|
||||||
GBLogEx.error(0, `GBEXCEPTION: ${GBUtil.toYAML(err)} ${GBUtil.toYAML(p)}`);
|
GBLogEx.error(0, `GBEXCEPTION: ${GBUtil.toYAML(err)}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('unhandledRejection', (err, p) => {
|
process.on('unhandledRejection', (err, p) => {
|
||||||
|
|
||||||
let bypass = false;
|
let bypass = false;
|
||||||
let res = err['response'];
|
let res = err['response'];
|
||||||
if (res) {
|
if (res) {
|
||||||
if (res?.body?.error?.message?.startsWith('Failed to send activity: bot timed out')){
|
if (res?.body?.error?.message?.startsWith('Failed to send activity: bot timed out')) {
|
||||||
bypass = true;
|
bypass = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!bypass){
|
if (!bypass) {
|
||||||
GBLogEx.error(0,`GBREJECTION: ${GBUtil.toYAML(err)} ${GBUtil.toYAML(p)}`);
|
GBLogEx.error(0, `GBREJECTION: ${GBUtil.toYAML(err)}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -147,6 +151,7 @@ export class GBServer {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
GBLogEx.info(0, `Now accepting connections on ${port}...`);
|
GBLogEx.info(0, `Now accepting connections on ${port}...`);
|
||||||
|
|
||||||
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
|
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
|
||||||
|
|
||||||
// Reads basic configuration, initialize minimal services.
|
// Reads basic configuration, initialize minimal services.
|
||||||
|
@ -175,12 +180,12 @@ export class GBServer {
|
||||||
|
|
||||||
// Creates a boot instance or load it from storage.
|
// Creates a boot instance or load it from storage.
|
||||||
|
|
||||||
let runOnce = false;
|
|
||||||
if (GBConfigService.get('STORAGE_SERVER')) {
|
if (GBConfigService.get('STORAGE_SERVER')) {
|
||||||
azureDeployer = await AzureDeployerService.createInstance(deployer);
|
azureDeployer = await AzureDeployerService.createInstance(deployer);
|
||||||
await core.initStorage();
|
await core.initStorage();
|
||||||
|
} else if (!GBConfigService.get('STORAGE_NAME')) {
|
||||||
|
await core.initStorage();
|
||||||
} else {
|
} else {
|
||||||
runOnce = true;
|
|
||||||
[GBServer.globals.bootInstance, azureDeployer] = await core['createBootInstanceEx'](
|
[GBServer.globals.bootInstance, azureDeployer] = await core['createBootInstanceEx'](
|
||||||
core,
|
core,
|
||||||
null,
|
null,
|
||||||
|
@ -188,10 +193,9 @@ export class GBServer {
|
||||||
deployer,
|
deployer,
|
||||||
GBConfigService.get('FREE_TIER')
|
GBConfigService.get('FREE_TIER')
|
||||||
);
|
);
|
||||||
|
await core.saveInstance(GBServer.globals.bootInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
core.ensureAdminIsSecured();
|
|
||||||
|
|
||||||
// Deploys system and user packages.
|
// Deploys system and user packages.
|
||||||
|
|
||||||
GBLogEx.info(0, `Deploying System packages...`);
|
GBLogEx.info(0, `Deploying System packages...`);
|
||||||
|
@ -201,10 +205,6 @@ export class GBServer {
|
||||||
await deployer.deployPackages(core, server, GBServer.globals.appPackages);
|
await deployer.deployPackages(core, server, GBServer.globals.appPackages);
|
||||||
await core.syncDatabaseStructure();
|
await core.syncDatabaseStructure();
|
||||||
|
|
||||||
if (runOnce) {
|
|
||||||
await core.saveInstance(GBServer.globals.bootInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deployment of local applications for the first time.
|
// Deployment of local applications for the first time.
|
||||||
|
|
||||||
if (GBConfigService.get('DISABLE_WEB') !== 'true') {
|
if (GBConfigService.get('DISABLE_WEB') !== 'true') {
|
||||||
|
@ -219,6 +219,7 @@ export class GBServer {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (instances.length === 0) {
|
if (instances.length === 0) {
|
||||||
|
if (GBConfigService.get('STORAGE_NAME')) {
|
||||||
const instance = await importer.importIfNotExistsBotPackage(
|
const instance = await importer.importIfNotExistsBotPackage(
|
||||||
GBConfigService.get('BOT_ID'),
|
GBConfigService.get('BOT_ID'),
|
||||||
'boot.gbot',
|
'boot.gbot',
|
||||||
|
@ -229,21 +230,28 @@ export class GBServer {
|
||||||
instances.push(instance);
|
instances.push(instance);
|
||||||
GBServer.globals.minBoot.instance = instances[0];
|
GBServer.globals.minBoot.instance = instances[0];
|
||||||
GBServer.globals.bootInstance = instances[0];
|
GBServer.globals.bootInstance = instances[0];
|
||||||
await deployer.deployBotFull(instance, GBServer.globals.publicAddress);
|
await deployer.deployBotOnAzure(instance, GBServer.globals.publicAddress);
|
||||||
|
|
||||||
// Runs the search even with empty content to create structure.
|
// Runs the search even with empty content to create structure.
|
||||||
|
|
||||||
await azureDeployer['runSearch'](instance);
|
await azureDeployer['runSearch'](instance);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
GBServer.globals.bootInstance = instances[0];
|
|
||||||
|
|
||||||
// Builds minimal service infrastructure.
|
|
||||||
|
|
||||||
const conversationalService: GBConversationalService = new GBConversationalService(core);
|
const conversationalService: GBConversationalService = new GBConversationalService(core);
|
||||||
const adminService: GBAdminService = new GBAdminService(core);
|
const adminService: GBAdminService = new GBAdminService(core);
|
||||||
const minService: GBMinService = new GBMinService(core, conversationalService, adminService, deployer);
|
const minService: GBMinService = new GBMinService(core, conversationalService, adminService, deployer);
|
||||||
GBServer.globals.minService = minService;
|
GBServer.globals.minService = minService;
|
||||||
|
|
||||||
|
// Just sync if not using LOAD_ONLY.
|
||||||
|
|
||||||
|
if (!GBConfigService.get('STORAGE_NAME') && !process.env.LOAD_ONLY) {
|
||||||
|
await core['ensureFolders'](instances, deployer);
|
||||||
|
}
|
||||||
|
GBServer.globals.bootInstance = instances[0];
|
||||||
|
|
||||||
|
// Builds minimal service infrastructure.
|
||||||
|
|
||||||
await minService.buildMin(instances);
|
await minService.buildMin(instances);
|
||||||
|
|
||||||
server.all('*', async (req, res, next) => {
|
server.all('*', async (req, res, next) => {
|
||||||
|
@ -279,6 +287,8 @@ export class GBServer {
|
||||||
|
|
||||||
GBLogEx.info(0, `The Bot Server is in RUNNING mode...`);
|
GBLogEx.info(0, `The Bot Server is in RUNNING mode...`);
|
||||||
|
|
||||||
|
await minService.startSimpleTest(GBServer.globals.minBoot);
|
||||||
|
|
||||||
// Opens Navigator.
|
// Opens Navigator.
|
||||||
|
|
||||||
if (process.env.DEV_OPEN_BROWSER) {
|
if (process.env.DEV_OPEN_BROWSER) {
|
||||||
|
|
80
src/util.ts
|
@ -34,6 +34,10 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
import * as YAML from 'yaml';
|
import * as YAML from 'yaml';
|
||||||
|
import SwaggerClient from 'swagger-client';
|
||||||
|
import Fs from 'fs';
|
||||||
|
import { GBConfigService } from '../packages/core.gbapp/services/GBConfigService.js';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
export class GBUtil {
|
export class GBUtil {
|
||||||
public static repeat(chr, count) {
|
public static repeat(chr, count) {
|
||||||
|
@ -64,10 +68,36 @@ export class GBUtil {
|
||||||
return (value + GBUtil.repeat(pad, length)).substr(0, width);
|
return (value + GBUtil.repeat(pad, length)).substr(0, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static toYAML(json) {
|
public static async getDirectLineClient(min) {
|
||||||
const doc = new YAML.Document();
|
|
||||||
doc.contents = json;
|
let config = {
|
||||||
return doc.toString();
|
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
||||||
|
requestInterceptor: req => {
|
||||||
|
req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!GBConfigService.get('STORAGE_NAME')) {
|
||||||
|
config['spec'].url = `http://127.0.0.1:${GBConfigService.getServerPort()}/api/messages/${min.botId}`,
|
||||||
|
config['spec'].servers = [{ url: `http://127.0.0.1:${GBConfigService.getServerPort()}/api/messages/${min.botId}` }];
|
||||||
|
config['spec'].openapi = '3.0.0';
|
||||||
|
delete config['spec'].host;
|
||||||
|
delete config['spec'].swagger;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await new SwaggerClient(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static toYAML(data) {
|
||||||
|
const extractProps = obj => {
|
||||||
|
return Object.getOwnPropertyNames(obj).reduce((acc, key) => {
|
||||||
|
const value = obj[key];
|
||||||
|
acc[key] = value && typeof value === 'object' && !Array.isArray(value) ? extractProps(value) : value;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const extractedError = extractProps(data);
|
||||||
|
return YAML.stringify(extractedError);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static sleep(ms) {
|
public static sleep(ms) {
|
||||||
|
@ -94,4 +124,46 @@ export class GBUtil {
|
||||||
return createCaseInsensitiveProxy(listOrRow);
|
return createCaseInsensitiveProxy(listOrRow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static copyIfNewerRecursive(src, dest) {
|
||||||
|
if (!Fs.existsSync(src)) {
|
||||||
|
console.error(`Source path "${src}" does not exist.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the source is a directory
|
||||||
|
if (Fs.statSync(src).isDirectory()) {
|
||||||
|
// Create the destination directory if it doesn't exist
|
||||||
|
if (!Fs.existsSync(dest)) {
|
||||||
|
Fs.mkdirSync(dest, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read all files and directories in the source directory
|
||||||
|
const entries = Fs.readdirSync(src);
|
||||||
|
|
||||||
|
for (let entry of entries) {
|
||||||
|
const srcEntry = path.join(src, entry);
|
||||||
|
const destEntry = path.join(dest, entry);
|
||||||
|
|
||||||
|
// Recursively copy each entry
|
||||||
|
this.copyIfNewerRecursive(srcEntry, destEntry);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Source is a file, check if we need to copy it
|
||||||
|
if (Fs.existsSync(dest)) {
|
||||||
|
const srcStat = Fs.statSync(src);
|
||||||
|
const destStat = Fs.statSync(dest);
|
||||||
|
|
||||||
|
// Copy only if the source file is newer than the destination file
|
||||||
|
if (srcStat.mtime > destStat.mtime) {
|
||||||
|
Fs.cpSync(src, dest, { force: true });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Destination file doesn't exist, so copy it
|
||||||
|
Fs.cpSync(src, dest, { force: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
21
src/webapp.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { GBConfigService } from "../packages/core.gbapp/services/GBConfigService";
|
||||||
|
import { app, BrowserWindow } from 'electron';
|
||||||
|
import path from 'path';
|
||||||
|
import url from 'url';
|
||||||
|
|
||||||
|
export function runUI() {
|
||||||
|
|
||||||
|
// Create the browser window.
|
||||||
|
const win = new BrowserWindow({ width: 800, height: 600, title: 'General Bots Studio' });
|
||||||
|
|
||||||
|
// and load the index.html of the app.
|
||||||
|
win.loadURL(
|
||||||
|
url.format({
|
||||||
|
pathname: path.join(__dirname, `http://localhost:${GBConfigService.get('PORT')}`),
|
||||||
|
protocol: 'file:',
|
||||||
|
slashes: true
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.on('ready', runUI);
|
121
templates/api-client.gbai/api-client.gbdialog/partner-center.vbs
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
REM SET SCHEDULE "1 * * * * *"
|
||||||
|
|
||||||
|
REM Obtém token do Partner Center via token do AD.
|
||||||
|
|
||||||
|
SET HEADER "return-client-request-id" AS "true"
|
||||||
|
SET HEADER "Content-Type" As "application/x-www-form-urlencoded; charset=utf-8"
|
||||||
|
|
||||||
|
pcToken = POST "https://login.microsoftonline.com/" + tenantId + "/oauth2/token", "resource=https%3A%2F%2Fgraph.windows.net&client_id=" + clientId + "&client_secret=" + clientSecret + "&grant_type=client_credentials"
|
||||||
|
|
||||||
|
REM repara chamada de Billing.
|
||||||
|
|
||||||
|
SET HEADER "Authorization" AS "Bearer " + pcToken.access_token
|
||||||
|
SET HEADER "MS-Contract-Version" AS "v1"
|
||||||
|
SET HEADER "MS-CorrelationId" AS uuid()
|
||||||
|
SET HEADER "MS-RequestId" AS uuid()
|
||||||
|
SET HEADER "MS-PartnerCenter-Application" AS "General Bots"
|
||||||
|
SET HEADER "X-Locale" AS "en-US"
|
||||||
|
|
||||||
|
REM Sincroniza Customers e Subscriptions
|
||||||
|
|
||||||
|
SET PAGE MODE "none"
|
||||||
|
list = GET host + "/v1/customers?size=20000"
|
||||||
|
MERGE "Customers" WITH list.items BY "Id"
|
||||||
|
|
||||||
|
FOR EACH item IN list
|
||||||
|
subs = GET host + "/v1/customers/" + item.id + "/subscriptions"
|
||||||
|
MERGE "Subscriptions" WITH subs.items BY "Id"
|
||||||
|
END FOR
|
||||||
|
|
||||||
|
|
||||||
|
REM Determina período.
|
||||||
|
|
||||||
|
IF today = dueDay THEN
|
||||||
|
IF period = "previous" AND NOT CONTINUATION TOKEN THEN
|
||||||
|
period = "current"
|
||||||
|
ELSE
|
||||||
|
period = "previous"
|
||||||
|
END IF
|
||||||
|
ELSE
|
||||||
|
period = "current"
|
||||||
|
END IF
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
REM Perform the call and loop through the billing items.
|
||||||
|
|
||||||
|
SET PAGE MODE "auto"
|
||||||
|
list = GET host + "/v1/invoices/unbilled/lineitems?provider=onetime&invoicelineitemtype=usagelineitems¤cycode=" + currency + "&period=previous&idparceiro=" + idparceiro
|
||||||
|
FOR EACH item IN list
|
||||||
|
SAVE "Billing", item.alternateId, item.availabilityId, item.billableQuantity, item.billingFrequency, item.chargeEndDate, item.chargeStartDate, item.chargeType, item.currency, item.customerCountry, item.customerDomainName, item.customerId, item.customerName, item.effectiveUnitPrice, item.invoiceNumber, item.meterDescription, item.mpnId, item.orderDate, item.orderId, item.partnerId, item.pCToBCExchangeRate, item.pCToBCExchangeRateDate, item.priceAdjustmentDescription, item.pricingCurrency, item.productId, item.productName, item.publisherId, item.publisherName, item.quantity, item.resellerMpnId, item.reservationOrderId, item.skuId, item.skuName, item.subscriptionDescription, item.subscriptionId, item.subtotal, item.taxTotal, item.termAndBillingCycle, item.totalForCustomer, item.unitPrice, item.unitType
|
||||||
|
END FOR
|
||||||
|
|
||||||
|
|
||||||
|
TABLE Billing
|
||||||
|
CustomerId Customers
|
||||||
|
ResourceGroup string(200)
|
||||||
|
ResourceUri string(1000)
|
||||||
|
Tags string(max)
|
||||||
|
AdditionalInfo string(max)
|
||||||
|
ServiceInfo1 string(max)
|
||||||
|
ServiceInfo2 string(max)
|
||||||
|
CustomerCountry string(6)
|
||||||
|
MpnId string(50)
|
||||||
|
ResellerMpnId string(50)
|
||||||
|
ChargeType string(200)
|
||||||
|
UnitPrice* double
|
||||||
|
Quantity* double
|
||||||
|
UnitType string(max)
|
||||||
|
BillingPreTaxTotal double
|
||||||
|
BillingCurrency string(6)
|
||||||
|
PricingPreTaxTotal double
|
||||||
|
PricingCurrency string(6)
|
||||||
|
EntitlementId string(50)
|
||||||
|
EntitlementDescription string(400)
|
||||||
|
PCToBCExchangeRate double
|
||||||
|
PCToBCExchangeRateDate date
|
||||||
|
EffectiveUnitPrice* double
|
||||||
|
RateOfPartnerEarnedCredit double
|
||||||
|
ConsumedService string(200)
|
||||||
|
ResourceLocation string(100)
|
||||||
|
MeterRegion string(100)
|
||||||
|
PartnerId string(50)
|
||||||
|
PartnerName string(400)
|
||||||
|
CustomerName string(400)
|
||||||
|
CustomerDomainName string(400)
|
||||||
|
InvoiceNumber string(400)
|
||||||
|
ProductId string(50)
|
||||||
|
SkuId string(50)
|
||||||
|
AvailabilityId string(50)
|
||||||
|
SkuName string(200)
|
||||||
|
ProductName string(400)
|
||||||
|
PublisherName string(200)
|
||||||
|
PublisherId string(200)
|
||||||
|
SubscriptionId string(50)
|
||||||
|
SubscriptionDescription string(400)
|
||||||
|
ChargeStartDate* date
|
||||||
|
ChargeEndDate* date
|
||||||
|
UsageDate date
|
||||||
|
MeterType string(400)
|
||||||
|
MeterCategory string(100)
|
||||||
|
MeterId string(50)
|
||||||
|
MeterSubCategory string(100)
|
||||||
|
MeterName string(200)
|
||||||
|
UnitOfMeasure string(100)
|
||||||
|
Reprocess boolean
|
||||||
|
END TABLE
|
||||||
|
|
||||||
|
|
||||||
|
TABLE Customers
|
||||||
|
TenantId guid
|
||||||
|
CompanyName string(100)
|
||||||
|
Id guid
|
||||||
|
END TABLE
|
||||||
|
|
||||||
|
|
||||||
|
TABLE Subscriptions
|
||||||
|
CustomerId Customers
|
||||||
|
Id guid
|
||||||
|
OfferName string(50)
|
||||||
|
END TABLE
|
||||||
|
|
79
templates/api-server.gbai/api.gbdialog/start.bas
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
REM 302 / 1234
|
||||||
|
PARAM barraca AS number LIKE Código da barraca
|
||||||
|
PARAM operador AS number LIKE Código do operador
|
||||||
|
DESCRIPTION Esta função (tool) nunca é chamada pelo GPT. É um WebService do GB.
|
||||||
|
|
||||||
|
REM Login como Garçom
|
||||||
|
data = NEW OBJECT
|
||||||
|
data.IdentificadorOperador = operador
|
||||||
|
data.BarracaId = barraca
|
||||||
|
login = POST "https://api.server.com.br/api/Operadores/Login", data
|
||||||
|
SET HEADER "Authorization" AS login.accessToken
|
||||||
|
|
||||||
|
REM Obter o cardápio da Barraca - Utilizar o token recuperado acima.
|
||||||
|
data = GET "https://api.server.com.br/api/Item/Barraca/${barraca}/Cliente"
|
||||||
|
produtos = NEW ARRAY
|
||||||
|
|
||||||
|
FOR EACH item IN data[0].itens
|
||||||
|
IF item.statusItem = "Ativo" THEN
|
||||||
|
produto = NEW OBJECT
|
||||||
|
produto.id = item.id
|
||||||
|
produto.valor = item.valor
|
||||||
|
produto.nome = item.produto.nome
|
||||||
|
produto.detalhe = item.detalhe
|
||||||
|
produto.acompanhamentos = item.gruposAcompanhamento
|
||||||
|
|
||||||
|
produtos.push(produto)
|
||||||
|
END IF
|
||||||
|
NEXT
|
||||||
|
|
||||||
|
BEGIN SYSTEM PROMPT
|
||||||
|
Você deve atuar como um chatbot que irá auxiliar o atendente de uma loja respeitando as seguintes regras:
|
||||||
|
Sempre que o atendente fizer um pedido e deve incluir a mesa e o nome do cliente. Exemplo: Uma caipirinha de 400ml de Abacaxi para Rafael na mesa 10.
|
||||||
|
Os pedidos são feitos com base nos produtos e acompanhamentos deste cardápio de produtos:
|
||||||
|
${JSON.stringify (produtos)}.
|
||||||
|
A cada pedido realizado, retorne JSON contendo o nome do produto, a mesa e uma lista de acompanhamentos com seus respectivos ids.
|
||||||
|
Mantenha itensPedido com apenas um item e mantenha itemsAcompanhamento apenas com os acompanhamentos que foram especificados.
|
||||||
|
ItensAcompanhamento deve conter a coleção de itens de acompanhamento do pedido, que é solicitado quando o pedido é feito, por exemplo: Caipirinha de Morango com Gelo, Açúcar e Limão, gerariam três elementos neste nó.
|
||||||
|
|
||||||
|
Segue o exemplo do JSON do Pedido, apague os itens e mande um com o pedido feito pela pessoa, é apenas um exemplo:
|
||||||
|
{
|
||||||
|
itensPedido: [
|
||||||
|
{
|
||||||
|
item: {
|
||||||
|
id: 23872,
|
||||||
|
valor: 20,
|
||||||
|
nome: Caipirinha Limão
|
||||||
|
},
|
||||||
|
itensAcompanhamento: [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
valor: 0,
|
||||||
|
quantidade: 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
quantidade: 1,
|
||||||
|
observacao: a
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: {
|
||||||
|
id: 25510,
|
||||||
|
valor: 12,
|
||||||
|
nome: Heineken Lata 350ml
|
||||||
|
},
|
||||||
|
itensAcompanhamento: [],
|
||||||
|
quantidade: 1,
|
||||||
|
observacao: nenhuma
|
||||||
|
}
|
||||||
|
],
|
||||||
|
barracaId: ${barraca},
|
||||||
|
usuarioId: ${operador},
|
||||||
|
identificadorConta: Rafael,
|
||||||
|
tipoEntregaId: 2,
|
||||||
|
camposTipoEntrega: {
|
||||||
|
Mesa: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
END SYSTEM PROMPT
|
|
@ -0,0 +1,19 @@
|
||||||
|
list = DIR "QCARobot.gbdrive"
|
||||||
|
|
||||||
|
FOR EACH item IN list
|
||||||
|
TALK "Verificando: " + item.name
|
||||||
|
DEBUG item
|
||||||
|
oldDays = DATEDIFF date, item.modified, "day"
|
||||||
|
|
||||||
|
IF oldDays > 3 THEN
|
||||||
|
TALK "O arquivo ${item.name} será arquivado, pois está expirado."
|
||||||
|
blob = UPLOAD item
|
||||||
|
TALK Upload para o Azure realizado.
|
||||||
|
|
||||||
|
SAVE "log.xlsx", "archived",today,now, item.path, item.name, item.size, item.modified, blob.md5
|
||||||
|
REM DELETE item
|
||||||
|
REM TALK Arquivo removido do SharePoint.
|
||||||
|
ELSE
|
||||||
|
TALK "O arquivo ${item.name} não precisa de arquivamento."
|
||||||
|
END IF
|
||||||
|
NEXT
|