Merge branch 'main' of https://github.com/GeneralBots/BotServer
This commit is contained in:
commit
bafeda98a6
34 changed files with 2694 additions and 203 deletions
1
.vscode/launch.json
vendored
1
.vscode/launch.json
vendored
|
@ -14,7 +14,6 @@
|
||||||
"NODE_NO_WARNINGS":"1"
|
"NODE_NO_WARNINGS":"1"
|
||||||
},
|
},
|
||||||
"args": [
|
"args": [
|
||||||
"--max-old-space-size 5120",
|
|
||||||
"--no-deprecation",
|
"--no-deprecation",
|
||||||
"--loader ts-node/esm",
|
"--loader ts-node/esm",
|
||||||
"--require ${workspaceRoot}/suppress-node-warnings.cjs",
|
"--require ${workspaceRoot}/suppress-node-warnings.cjs",
|
||||||
|
|
125
package.json
125
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "botserver",
|
"name": "botserver",
|
||||||
"version": "3.1.0",
|
"version": "5.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "General Bot Community Edition open-core server.",
|
"description": "General Bot Community Edition open-core server.",
|
||||||
"main": "./boot.mjs",
|
"main": "./boot.mjs",
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/arm-appservice": "14.1.0",
|
"@azure/arm-appservice": "15.0.0",
|
||||||
"@azure/arm-cognitiveservices": "7.5.0",
|
"@azure/arm-cognitiveservices": "7.5.0",
|
||||||
"@azure/arm-resources": "5.2.0",
|
"@azure/arm-resources": "5.2.0",
|
||||||
"@azure/arm-search": "3.2.0",
|
"@azure/arm-search": "3.2.0",
|
||||||
|
@ -75,16 +75,16 @@
|
||||||
"@azure/cognitiveservices-computervision": "8.2.0",
|
"@azure/cognitiveservices-computervision": "8.2.0",
|
||||||
"@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.13.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.1.0",
|
||||||
"@azure/storage-blob": "12.18.0",
|
"@azure/storage-blob": "12.24.0",
|
||||||
"@google-cloud/pubsub": "4.4.0",
|
"@google-cloud/pubsub": "4.7.0",
|
||||||
"@google-cloud/translate": "8.3.0",
|
"@google-cloud/translate": "8.5.0",
|
||||||
"@hubspot/api-client": "11.1.0",
|
"@hubspot/api-client": "11.2.0",
|
||||||
"@koa/cors": "5.0.0",
|
"@koa/cors": "5.0.0",
|
||||||
"@langchain/community": "0.2.2",
|
"@langchain/community": "0.2.31",
|
||||||
"@langchain/openai": "0.0.33",
|
"@langchain/openai": "0.2.8",
|
||||||
"@microsoft/microsoft-graph-client": "3.0.7",
|
"@microsoft/microsoft-graph-client": "3.0.7",
|
||||||
"@nlpjs/basic": "4.27.0",
|
"@nlpjs/basic": "4.27.0",
|
||||||
"@nosferatu500/textract": "3.1.3",
|
"@nosferatu500/textract": "3.1.3",
|
||||||
|
@ -97,38 +97,38 @@
|
||||||
"@semantic-release/git": "10.0.1",
|
"@semantic-release/git": "10.0.1",
|
||||||
"@sendgrid/mail": "8.1.3",
|
"@sendgrid/mail": "8.1.3",
|
||||||
"@sequelize/core": "7.0.0-alpha.37",
|
"@sequelize/core": "7.0.0-alpha.37",
|
||||||
"@types/node": "20.12.12",
|
"@types/node": "22.5.2",
|
||||||
"@types/validator": "13.11.10",
|
"@types/validator": "13.12.1",
|
||||||
"adm-zip": "0.5.12",
|
"adm-zip": "0.5.16",
|
||||||
"alasql": "4.4.0",
|
"alasql": "4.5.1",
|
||||||
"any-shell-escape": "0.1.1",
|
"any-shell-escape": "0.1.1",
|
||||||
"arraybuffer-to-buffer": "0.0.7",
|
"arraybuffer-to-buffer": "0.0.7",
|
||||||
"async-mutex": "0.5.0",
|
"async-mutex": "0.5.0",
|
||||||
"async-promises": "0.2.3",
|
"async-promises": "0.2.3",
|
||||||
"async-retry": "1.3.3",
|
"async-retry": "1.3.3",
|
||||||
"basic-auth": "2.0.1",
|
"basic-auth": "2.0.1",
|
||||||
"billboard.js": "3.11.3",
|
"billboard.js": "3.13.0",
|
||||||
"bluebird": "3.7.2",
|
"bluebird": "3.7.2",
|
||||||
"body-parser": "1.20.1",
|
"body-parser": "1.20.2",
|
||||||
"botbuilder": "4.18.0",
|
"botbuilder": "4.23.0",
|
||||||
"botbuilder-adapter-facebook": "1.0.12",
|
"botbuilder-adapter-facebook": "1.0.12",
|
||||||
"botbuilder-ai": "4.18.0",
|
"botbuilder-ai": "4.23.0",
|
||||||
"botbuilder-dialogs": "4.18.0",
|
"botbuilder-dialogs": "4.23.0",
|
||||||
"botframework-connector": "4.22.2",
|
"botframework-connector": "4.23.0",
|
||||||
"botlib": "3.0.11",
|
"botlib": "5.0.0",
|
||||||
"c3-chart-maker": "0.2.8",
|
"c3-chart-maker": "0.2.8",
|
||||||
"cd": "0.3.3",
|
"cd": "0.3.3",
|
||||||
"chalk-animation": "2.0.3",
|
"chalk-animation": "2.0.3",
|
||||||
"chatgpt": "5.2.5",
|
"chatgpt": "5.2.5",
|
||||||
"chrome-remote-interface": "0.33.0",
|
"chrome-remote-interface": "0.33.2",
|
||||||
"cli-progress": "3.12.0",
|
"cli-progress": "3.12.0",
|
||||||
"cli-spinner": "0.2.10",
|
"cli-spinner": "0.2.10",
|
||||||
"core-js": "3.37.1",
|
"core-js": "3.38.1",
|
||||||
"csv-database": "0.9.2",
|
"csv-database": "0.9.2",
|
||||||
"data-forge": "1.10.2",
|
"data-forge": "1.10.2",
|
||||||
"date-diff": "1.0.2",
|
"date-diff": "1.0.2",
|
||||||
"docximager": "0.0.4",
|
"docximager": "0.0.4",
|
||||||
"docxtemplater": "3.47.4",
|
"docxtemplater": "3.50.0",
|
||||||
"dotenv-extended": "2.9.0",
|
"dotenv-extended": "2.9.0",
|
||||||
"electron": "32.0.1",
|
"electron": "32.0.1",
|
||||||
"exceljs": "4.4.0",
|
"exceljs": "4.4.0",
|
||||||
|
@ -136,29 +136,30 @@
|
||||||
"express-remove-route": "1.0.0",
|
"express-remove-route": "1.0.0",
|
||||||
"ffmpeg-static": "5.2.0",
|
"ffmpeg-static": "5.2.0",
|
||||||
"get-image-colors": "4.0.1",
|
"get-image-colors": "4.0.1",
|
||||||
"google-libphonenumber": "3.2.34",
|
"google-libphonenumber": "3.2.38",
|
||||||
"googleapis": "126.0.1",
|
"googleapis": "143.0.0",
|
||||||
"hnswlib-node": "3.0.0",
|
"hnswlib-node": "3.0.0",
|
||||||
"html-to-md": "0.8.5",
|
"html-to-md": "0.8.6",
|
||||||
"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.3",
|
||||||
"isomorphic-fetch": "3.0.0",
|
"isomorphic-fetch": "3.0.0",
|
||||||
"js-md5": "0.8.3",
|
"js-md5": "0.8.3",
|
||||||
"json-schema-to-zod": "2.1.0",
|
"json-schema-to-zod": "2.4.0",
|
||||||
"just-indent": "0.0.1",
|
"just-indent": "0.0.1",
|
||||||
"keyv": "4.5.4",
|
"keyv": "5.0.1",
|
||||||
"koa": "2.15.3",
|
"koa": "2.15.3",
|
||||||
"koa-body": "6.0.1",
|
"koa-body": "6.0.1",
|
||||||
|
"koa-ratelimit": "5.1.0",
|
||||||
"koa-router": "12.0.1",
|
"koa-router": "12.0.1",
|
||||||
"langchain": "0.2.17",
|
"langchain": "0.2.17",
|
||||||
"language-tags": "1.0.9",
|
"language-tags": "1.0.9",
|
||||||
"line-replace": "2.0.1",
|
"line-replace": "2.0.1",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"luxon": "3.4.4",
|
"luxon": "3.5.0",
|
||||||
"mammoth": "1.7.2",
|
"mammoth": "1.8.0",
|
||||||
"mariadb": "3.3.0",
|
"mariadb": "3.3.1",
|
||||||
"mime-types": "2.1.35",
|
"mime-types": "2.1.35",
|
||||||
"moment": "2.30.1",
|
"moment": "2.30.1",
|
||||||
"ms-rest-azure": "3.0.2",
|
"ms-rest-azure": "3.0.2",
|
||||||
|
@ -169,51 +170,51 @@
|
||||||
"node-html-parser": "6.1.13",
|
"node-html-parser": "6.1.13",
|
||||||
"node-nlp": "4.27.0",
|
"node-nlp": "4.27.0",
|
||||||
"node-tesseract-ocr": "2.2.1",
|
"node-tesseract-ocr": "2.2.1",
|
||||||
"npm": "10.8.0",
|
"npm": "10.8.3",
|
||||||
"open": "10.1.0",
|
"open": "10.1.0",
|
||||||
"open-docxtemplater-image-module": "1.0.3",
|
"open-docxtemplater-image-module": "1.0.3",
|
||||||
"openai": "4.47.1",
|
"openai": "4.57.0",
|
||||||
"pdf-extraction": "1.0.2",
|
"pdf-extraction": "1.0.2",
|
||||||
"pdf-parse": "1.1.1",
|
"pdf-parse": "1.1.1",
|
||||||
"pdf-to-png-converter": "3.2.0",
|
"pdf-to-png-converter": "3.3.0",
|
||||||
"pdfjs-dist": "4.2.67",
|
"pdfjs-dist": "4.6.82",
|
||||||
"pdfkit": "0.15.0",
|
"pdfkit": "0.15.0",
|
||||||
"phone": "3.1.44",
|
"phone": "3.1.50",
|
||||||
"pizzip": "3.1.7",
|
"pizzip": "3.1.7",
|
||||||
"pptxtemplater": "1.0.5",
|
"pptxtemplater": "1.0.5",
|
||||||
"pragmatismo-io-framework": "1.1.1",
|
"pragmatismo-io-framework": "1.1.1",
|
||||||
"prism-media": "1.3.5",
|
"prism-media": "1.3.5",
|
||||||
"public-ip": "6.0.2",
|
"public-ip": "7.0.1",
|
||||||
"punycode": "2.3.1",
|
"punycode": "2.3.1",
|
||||||
"puppeteer": "19.7.2",
|
"puppeteer": "23.2.2",
|
||||||
"puppeteer-extra": "3.3.6",
|
"puppeteer-extra": "3.3.6",
|
||||||
"puppeteer-extra-plugin-minmax": "1.1.2",
|
"puppeteer-extra-plugin-minmax": "1.1.2",
|
||||||
"puppeteer-extra-plugin-stealth": "2.11.2",
|
"puppeteer-extra-plugin-stealth": "2.11.2",
|
||||||
"qr-scanner": "1.4.2",
|
"qr-scanner": "1.4.2",
|
||||||
"qrcode": "1.5.3",
|
"qrcode": "1.5.4",
|
||||||
"qrcode-terminal": "0.12.0",
|
"qrcode-terminal": "0.12.0",
|
||||||
"readline": "1.3.0",
|
"readline": "1.3.0",
|
||||||
"reflect-metadata": "0.2.2",
|
"reflect-metadata": "0.2.2",
|
||||||
"rimraf": "5.0.7",
|
"rimraf": "6.0.1",
|
||||||
"safe-buffer": "5.2.1",
|
"safe-buffer": "5.2.1",
|
||||||
"scanf": "1.2.0",
|
"scanf": "1.2.0",
|
||||||
"sequelize": "6.28.2",
|
"sequelize": "6.37.3",
|
||||||
"sequelize-cli": "6.6.0",
|
"sequelize-cli": "6.6.2",
|
||||||
"sequelize-typescript": "2.1.5",
|
"sequelize-typescript": "2.1.6",
|
||||||
"simple-git": "3.24.0",
|
"simple-git": "3.26.0",
|
||||||
"speakingurl": "14.0.1",
|
"speakingurl": "14.0.1",
|
||||||
"sqlite3": "5.1.7",
|
"sqlite3": "5.1.7",
|
||||||
"ssr-for-bots": "1.0.1-c",
|
"ssr-for-bots": "1.0.1-c",
|
||||||
"strict-password-generator": "1.1.2",
|
"strict-password-generator": "1.1.2",
|
||||||
"swagger-client": "3.28.1",
|
"swagger-client": "3.29.2",
|
||||||
"swagger-ui-dist": "5.17.12",
|
"swagger-ui-dist": "5.17.14",
|
||||||
"tabulator-tables": "6.2.1",
|
"tabulator-tables": "6.2.5",
|
||||||
"tedious": "18.2.0",
|
"tedious": "18.6.1",
|
||||||
"textract": "2.5.0",
|
"textract": "2.5.0",
|
||||||
"twilio": "5.1.0",
|
"twilio": "5.2.3",
|
||||||
"twitter-api-v2": "1.17.0",
|
"twitter-api-v2": "1.17.2",
|
||||||
"typeorm": "0.3.20",
|
"typeorm": "0.3.20",
|
||||||
"typescript": "5.4.5",
|
"typescript": "5.5.4",
|
||||||
"url-join": "5.0.0",
|
"url-join": "5.0.0",
|
||||||
"vhost": "3.0.2",
|
"vhost": "3.0.2",
|
||||||
"vm2": "3.9.19",
|
"vm2": "3.9.19",
|
||||||
|
@ -223,31 +224,31 @@
|
||||||
"webdav-server": "2.6.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.14.2",
|
||||||
"ws": "8.17.0",
|
"ws": "8.18.0",
|
||||||
"yaml": "2.4.2",
|
"yaml": "2.5.0",
|
||||||
"yarn": "1.22.22",
|
"yarn": "1.22.22",
|
||||||
"zod-to-json-schema": "3.23.0"
|
"zod-to-json-schema": "3.23.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/qrcode": "1.5.5",
|
"@types/qrcode": "1.5.5",
|
||||||
"@types/url-join": "4.0.3",
|
"@types/url-join": "4.0.3",
|
||||||
"@typescript-eslint/eslint-plugin": "7.10.0",
|
"@typescript-eslint/eslint-plugin": "8.4.0",
|
||||||
"@typescript-eslint/parser": "7.10.0",
|
"@typescript-eslint/parser": "8.4.0",
|
||||||
"ban-sensitive-files": "1.10.2",
|
"ban-sensitive-files": "1.10.5",
|
||||||
"commitizen": "4.3.0",
|
"commitizen": "4.3.0",
|
||||||
"cz-conventional-changelog": "3.3.0",
|
"cz-conventional-changelog": "3.3.0",
|
||||||
"dependency-check": "4.1.0",
|
"dependency-check": "4.1.0",
|
||||||
"git-issues": "1.3.1",
|
"git-issues": "1.3.1",
|
||||||
"license-checker": "25.0.1",
|
"license-checker": "25.0.1",
|
||||||
"prettier-standard": "16.4.1",
|
"prettier-standard": "16.4.1",
|
||||||
"semantic-release": "23.1.1",
|
"semantic-release": "24.1.0",
|
||||||
"simple-commit-message": "4.1.3",
|
"simple-commit-message": "4.1.3",
|
||||||
"super-strong-password-generator": "2.0.2",
|
"super-strong-password-generator": "2.0.2",
|
||||||
"super-strong-password-generator-es": "2.0.2",
|
"super-strong-password-generator-es": "2.0.2",
|
||||||
"travis-deploy-once": "5.0.11",
|
"travis-deploy-once": "5.0.11",
|
||||||
"tslint": "6.1.3",
|
"tslint": "6.1.3",
|
||||||
"vitest": "1.6.0"
|
"vitest": "2.0.5"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"env": {
|
"env": {
|
||||||
|
|
|
@ -168,13 +168,6 @@ export class GBAdminService implements IGBAdminService {
|
||||||
) {
|
) {
|
||||||
const packageName = text.split(' ')[1];
|
const packageName = text.split(' ')[1];
|
||||||
|
|
||||||
if (!this.isSharePointPath(packageName)) {
|
|
||||||
const additionalPath = GBConfigService.get('ADDITIONAL_DEPLOY_PATH');
|
|
||||||
if (additionalPath === undefined) {
|
|
||||||
throw new Error('ADDITIONAL_DEPLOY_PATH is not set and deployPackage was called.');
|
|
||||||
}
|
|
||||||
await deployer['deployPackage2'](min, user, urlJoin(additionalPath, packageName));
|
|
||||||
} else {
|
|
||||||
const folderName = text.split(' ')[2];
|
const folderName = text.split(' ')[2];
|
||||||
const packageType = Path.extname(folderName).substr(1);
|
const packageType = Path.extname(folderName).substr(1);
|
||||||
const gbaiPath = DialogKeywords.getGBAIPath(min.instance.botId, packageType, null);
|
const gbaiPath = DialogKeywords.getGBAIPath(min.instance.botId, packageType, null);
|
||||||
|
@ -195,7 +188,7 @@ export class GBAdminService implements IGBAdminService {
|
||||||
await deployer['downloadFolder'](min, Path.join('work', `${gbai}`), Path.basename(localFolder));
|
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);
|
||||||
|
|
|
@ -986,7 +986,6 @@ export class AzureDeployerService implements IGBInstallationDeployer {
|
||||||
appSettings: [
|
appSettings: [
|
||||||
{ name: 'WEBSITES_CONTAINER_START_TIME_LIMIT', value: `${WebSiteResponseTimeout}` },
|
{ name: 'WEBSITES_CONTAINER_START_TIME_LIMIT', value: `${WebSiteResponseTimeout}` },
|
||||||
{ name: 'WEBSITE_NODE_DEFAULT_VERSION', value: GBAdminService.getNodeVersion() },
|
{ name: 'WEBSITE_NODE_DEFAULT_VERSION', value: GBAdminService.getNodeVersion() },
|
||||||
{ name: 'ADDITIONAL_DEPLOY_PATH', value: `` },
|
|
||||||
{ name: 'ADMIN_PASS', value: `${instance.adminPass}` },
|
{ name: 'ADMIN_PASS', value: `${instance.adminPass}` },
|
||||||
{ name: 'BOT_ID', value: `${instance.botId}` },
|
{ name: 'BOT_ID', value: `${instance.botId}` },
|
||||||
{ name: 'CLOUD_SUBSCRIPTIONID', value: `${instance.cloudSubscriptionId}` },
|
{ name: 'CLOUD_SUBSCRIPTIONID', value: `${instance.cloudSubscriptionId}` },
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
@ -44,19 +43,32 @@ import { createKoaHttpMiddleware } from '@push-rpc/http';
|
||||||
import { GBServer } from '../../src/app.js';
|
import { GBServer } from '../../src/app.js';
|
||||||
import { SocketServer } from '@push-rpc/core';
|
import { SocketServer } from '@push-rpc/core';
|
||||||
import * as koaBody from 'koa-body';
|
import * as koaBody from 'koa-body';
|
||||||
|
import ratelimit from 'koa-ratelimit';
|
||||||
|
|
||||||
export function createKoaHttpServer(
|
export function createKoaHttpServer(port: number, getRemoteId: (ctx: Koa.Context) => string, opts: {}): SocketServer {
|
||||||
port: number,
|
const { onError, onConnection, middleware } = createKoaHttpMiddleware(getRemoteId);
|
||||||
getRemoteId: (ctx: Koa.Context) => string,
|
|
||||||
opts:{}
|
|
||||||
): SocketServer {
|
|
||||||
const { onError, onConnection, middleware } =
|
|
||||||
createKoaHttpMiddleware(getRemoteId);
|
|
||||||
|
|
||||||
const app = new Koa();
|
const app = new Koa();
|
||||||
|
|
||||||
|
// Apply the rate-limiting middleware
|
||||||
|
app.use(
|
||||||
|
ratelimit({
|
||||||
|
driver: 'memory', // Use 'memory' for in-memory store
|
||||||
|
duration: 60000, // 1 minute window
|
||||||
|
errorMessage: 'Slow down your requests',
|
||||||
|
id: ctx => ctx.ip, // Identify client by IP address
|
||||||
|
headers: {
|
||||||
|
remaining: 'X-RateLimit-Remaining',
|
||||||
|
reset: 'X-RateLimit-Reset',
|
||||||
|
total: 'X-RateLimit-Limit'
|
||||||
|
},
|
||||||
|
max: 100, // Limit each IP to 100 requests per window
|
||||||
|
disableHeader: false
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
app.use(cors({ origin: '*' }));
|
app.use(cors({ origin: '*' }));
|
||||||
app.use(koaBody.koaBody({jsonLimit:'1024mb',textLimit:'1024mb', formLimit:'1024mb',
|
app.use(koaBody.koaBody({ jsonLimit: '1024mb', textLimit: '1024mb', formLimit: '1024mb', multipart: true }));
|
||||||
multipart: true }));
|
|
||||||
app.use(middleware);
|
app.use(middleware);
|
||||||
const server = app.listen(port);
|
const server = app.listen(port);
|
||||||
const SERVER_TIMEOUT = 60 * 60 * 24 * 1000; // Equals to client RPC set.
|
const SERVER_TIMEOUT = 60 * 60 * 24 * 1000; // Equals to client RPC set.
|
||||||
|
|
|
@ -453,6 +453,7 @@ export class GBVMService extends GBService {
|
||||||
// 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');
|
||||||
|
basicCode = GBVMService.normalizeQuotes(basicCode);
|
||||||
|
|
||||||
// Pre process SET SCHEDULE calls.
|
// Pre process SET SCHEDULE calls.
|
||||||
|
|
||||||
|
@ -576,11 +577,11 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
// Transfers auto variables into global object.
|
// Transfers auto variables into global object.
|
||||||
|
|
||||||
for(__indexer in this.variables) {
|
for (const key of Object.keys(this.variables)) {
|
||||||
global[__indexer] = this.variables[__indexer];
|
global[key] = this.variables[key];
|
||||||
|
console.log('Defining global variable: ' + key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Defines local utility BASIC functions.
|
// Defines local utility BASIC functions.
|
||||||
|
|
||||||
const ubound = (gbarray) => {
|
const ubound = (gbarray) => {
|
||||||
|
@ -764,9 +765,6 @@ export class GBVMService extends GBService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text) {
|
|
||||||
text = GBVMService.normalizeQuotes(text);
|
|
||||||
}
|
|
||||||
resolve(text);
|
resolve(text);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -783,12 +781,13 @@ export class GBVMService extends GBService {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getMetadata(mainName: string, propertiesText, description) {
|
public static getMetadata(mainName: string, propertiesText: string[][], description: string) {
|
||||||
let properties = {};
|
let properties = {};
|
||||||
if (!propertiesText || !description) {
|
if (!propertiesText || !description) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const getType = asClause => {
|
|
||||||
|
const getType = (asClause: string) => {
|
||||||
asClause = asClause.trim().toUpperCase();
|
asClause = asClause.trim().toUpperCase();
|
||||||
|
|
||||||
if (asClause.indexOf('STRING') !== -1) {
|
if (asClause.indexOf('STRING') !== -1) {
|
||||||
|
@ -806,31 +805,37 @@ export class GBVMService extends GBService {
|
||||||
const propertiesExp = propertiesText[i];
|
const propertiesExp = propertiesText[i];
|
||||||
const t = getType(propertiesExp[2]);
|
const t = getType(propertiesExp[2]);
|
||||||
let element;
|
let element;
|
||||||
|
const description = propertiesExp[4]?.trim();
|
||||||
|
|
||||||
if (t === 'enum') {
|
if (t === 'enum') {
|
||||||
element = z.enum(propertiesExp[2].split(','));
|
const list = propertiesExp[2] as any;
|
||||||
|
element = z.enum(list.split(','));
|
||||||
} else if (t === 'string') {
|
} else if (t === 'string') {
|
||||||
element = z.string();
|
element = z.string({description:description});
|
||||||
} else if (t === 'object') {
|
} else if (t === 'object') {
|
||||||
element = z.string();
|
element = z.string({description:description}); // Assuming 'object' is represented as a string here
|
||||||
} else if (t === 'number') {
|
} else if (t === 'number') {
|
||||||
element = z.number();
|
element = z.number({description:description});
|
||||||
} else {
|
} else {
|
||||||
GBLog.warn(`Element type invalid specified on .docx: ${propertiesExp[0]}`);
|
GBLog.warn(`Element type invalid specified on .docx: ${propertiesExp[0]}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
element.describe(propertiesExp[3]);
|
|
||||||
element['type'] = t;
|
element['type'] = t;
|
||||||
properties[propertiesExp[1].trim()] = element;
|
properties[propertiesExp[1].trim()] = element;
|
||||||
}
|
}
|
||||||
|
|
||||||
let json = {
|
const json = {
|
||||||
type: 'function',
|
type: 'function',
|
||||||
function: {
|
function: {
|
||||||
name: `${mainName}`,
|
name: mainName,
|
||||||
description: description ? description : '',
|
description: description ? description : '',
|
||||||
parameters: zodToJsonSchema(z.object(properties))
|
schema: zodToJsonSchema(z.object(properties))
|
||||||
}
|
},
|
||||||
|
arguments: propertiesText.reduce((acc, prop) => {
|
||||||
|
acc[prop[1].trim()] = prop[3]?.trim(); // Assuming value is in the 3rd index
|
||||||
|
return acc;
|
||||||
|
}, {})
|
||||||
};
|
};
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
|
@ -913,7 +918,7 @@ export class GBVMService extends GBService {
|
||||||
// Pre-process "off-line" static KEYWORDS.
|
// Pre-process "off-line" static KEYWORDS.
|
||||||
|
|
||||||
let emmit = true;
|
let emmit = true;
|
||||||
const params = /^\s*PARAM\s*(.*)\s*AS\s*(.*)\s*LIKE\s*(.*)/gim;
|
const params = /^\s*PARAM\s*(.*)\s*AS\s*(.*)\s*LIKE\s*(.*)\s*DESCRIPTION\s*(.*)/gim;
|
||||||
const param = params.exec(line);
|
const param = params.exec(line);
|
||||||
if (param) {
|
if (param) {
|
||||||
properties.push(param);
|
properties.push(param);
|
||||||
|
@ -1045,7 +1050,7 @@ export class GBVMService extends GBService {
|
||||||
GBConfigService.get('DEFAULT_CONTENT_LANGUAGE')
|
GBConfigService.get('DEFAULT_CONTENT_LANGUAGE')
|
||||||
);
|
);
|
||||||
|
|
||||||
let variables = [];
|
let variables = {};
|
||||||
|
|
||||||
// These variables will be automatically be available as normal BASIC variables.
|
// These variables will be automatically be available as normal BASIC variables.
|
||||||
|
|
||||||
|
@ -1086,7 +1091,7 @@ export class GBVMService extends GBService {
|
||||||
const botId = min.botId;
|
const botId = min.botId;
|
||||||
const path = DialogKeywords.getGBAIPath(min.botId, `gbdialog`);
|
const path = DialogKeywords.getGBAIPath(min.botId, `gbdialog`);
|
||||||
const gbdialogPath = urlJoin(process.cwd(), 'work', path);
|
const gbdialogPath = urlJoin(process.cwd(), 'work', path);
|
||||||
const scriptPath = urlJoin(gbdialogPath, `${text}.js`);
|
const scriptFilePath = urlJoin(gbdialogPath, `${text}.js`);
|
||||||
|
|
||||||
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';
|
||||||
|
@ -1144,7 +1149,7 @@ export class GBVMService extends GBService {
|
||||||
context: 'sandbox'
|
context: 'sandbox'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const s = new VMScript(code, { filename: scriptPath });
|
const s = new VMScript(code, { filename: scriptFilePath });
|
||||||
result = vm1.run(s);
|
result = vm1.run(s);
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -1163,16 +1168,17 @@ export class GBVMService extends GBService {
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 0,
|
max: 0,
|
||||||
debug: debug,
|
debug: debug,
|
||||||
debuggerport: GBVMService.DEBUGGER_PORT,
|
// debuggerport: GBVMService.DEBUGGER_PORT,
|
||||||
botId: botId,
|
botId: botId,
|
||||||
cpu: 100,
|
cpu: 100,
|
||||||
memory: 50000,
|
memory: 50000,
|
||||||
time: 60 * 60 * 24 * 14,
|
time: 60 * 60 * 24 * 14,
|
||||||
cwd: scriptPath,
|
cwd: gbdialogPath,
|
||||||
script: runnerPath
|
script: runnerPath
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
result = await run(code, { filename: scriptPath, sandbox: sandbox });
|
result = await run(code, Object.assign( sandbox, { filename: scriptFilePath}));
|
||||||
}
|
}
|
||||||
} 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}`);
|
||||||
|
|
|
@ -48,7 +48,7 @@ import { GBSSR } from '../../core.gbapp/services/GBSSR.js';
|
||||||
import urlJoin from 'url-join';
|
import urlJoin from 'url-join';
|
||||||
import Excel from 'exceljs';
|
import Excel from 'exceljs';
|
||||||
import { BufferWindowMemory } from 'langchain/memory';
|
import { BufferWindowMemory } from 'langchain/memory';
|
||||||
import { TwitterApi } from 'twitter-api-v2';
|
import csvdb from 'csv-database';
|
||||||
import Path from 'path';
|
import Path from 'path';
|
||||||
import ComputerVisionClient from '@azure/cognitiveservices-computervision';
|
import ComputerVisionClient from '@azure/cognitiveservices-computervision';
|
||||||
import ApiKeyCredentials from '@azure/ms-rest-js';
|
import ApiKeyCredentials from '@azure/ms-rest-js';
|
||||||
|
@ -347,6 +347,7 @@ export class SystemKeywords {
|
||||||
|
|
||||||
delete this.cachedMerge[pid];
|
delete this.cachedMerge[pid];
|
||||||
|
|
||||||
|
|
||||||
// Capture memory usage before GC
|
// Capture memory usage before GC
|
||||||
GBLogEx.info(min, ``);
|
GBLogEx.info(min, ``);
|
||||||
|
|
||||||
|
@ -356,7 +357,10 @@ export class SystemKeywords {
|
||||||
|
|
||||||
// Capture memory usage after GC
|
// Capture memory usage after GC
|
||||||
const memoryAfterGC = process.memoryUsage().heapUsed / 1024 / 1024; // in MB
|
const memoryAfterGC = process.memoryUsage().heapUsed / 1024 / 1024; // in MB
|
||||||
GBLogEx.info(min, `BASIC: Closing Handles... From ${memoryBeforeGC.toFixed(2)} MB to ${memoryAfterGC.toFixed(2)} MB`);
|
GBLogEx.info(
|
||||||
|
min,
|
||||||
|
`BASIC: Closing Handles... From ${memoryBeforeGC.toFixed(2)} MB to ${memoryAfterGC.toFixed(2)} MB`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async asPDF({ pid, data }) {
|
public async asPDF({ pid, data }) {
|
||||||
|
@ -1040,7 +1044,7 @@ export class SystemKeywords {
|
||||||
|
|
||||||
public static async getFilter(text) {
|
public static async getFilter(text) {
|
||||||
let filter;
|
let filter;
|
||||||
const operators = [/\<\=/, /\<\>/, /\>\=/, /\</, /\>/, /\bnot in\b/, /\bin\b/, /\=/];
|
const operators = [/\<\=/, /\<\>/, /\>\=/, /\</, /\>/,/\blike\b/, /\bnot in\b/, /\bin\b/, /\=/];
|
||||||
let done = false;
|
let done = false;
|
||||||
await CollectionUtil.asyncForEach(operators, async op => {
|
await CollectionUtil.asyncForEach(operators, async op => {
|
||||||
var re = new RegExp(op, 'gi');
|
var re = new RegExp(op, 'gi');
|
||||||
|
@ -1194,6 +1198,23 @@ export class SystemKeywords {
|
||||||
|
|
||||||
header = results.text[0];
|
header = results.text[0];
|
||||||
rows = results.text;
|
rows = results.text;
|
||||||
|
} else if (file.indexOf('.csv') !== -1) {
|
||||||
|
let res;
|
||||||
|
let path = DialogKeywords.getGBAIPath(min.botId, `gbdata`);
|
||||||
|
const csvFile = Path.join(GBConfigService.get('STORAGE_LIBRARY'), path, file);
|
||||||
|
const firstLine = Fs.readFileSync(csvFile, 'utf8').split('\n')[0];
|
||||||
|
const headers = firstLine.split(',');
|
||||||
|
const db = await csvdb(csvFile, headers, ',');
|
||||||
|
if (args[0]) {
|
||||||
|
const systemFilter = await SystemKeywords.getFilter(args[0]);
|
||||||
|
let filter = {};
|
||||||
|
filter[systemFilter.columnName] = systemFilter.value;
|
||||||
|
res = await db.get(filter);
|
||||||
|
} else {
|
||||||
|
res = await db.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.length > 1 ? res : res[0];
|
||||||
} else {
|
} else {
|
||||||
const t = this.getTableFromName(file, min);
|
const t = this.getTableFromName(file, min);
|
||||||
|
|
||||||
|
@ -2447,31 +2468,24 @@ export class SystemKeywords {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publishs a tweet to X.
|
* Publishs a post to BlueSky .
|
||||||
*
|
*
|
||||||
* TWEET "My tweet text"
|
* BlueSky "My BlueSky text"
|
||||||
*/
|
*/
|
||||||
public async tweet({ pid, text }) {
|
public async postToBlueSky({ pid, text }) {
|
||||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||||
|
|
||||||
const consumer_key = min.core.getParam(min.instance, 'Twitter Consumer Key', null);
|
const consumer_key = min.core.getParam(min.instance, 'BlueSky Consumer Key', null);
|
||||||
const consumer_secret = min.core.getParam(min.instance, 'Twitter Consumer Key Secret', null);
|
const consumer_secret = min.core.getParam(min.instance, 'BlueSky Consumer Key Secret', null);
|
||||||
const access_token_key = min.core.getParam(min.instance, 'Twitter Access Token', null);
|
const access_token_key = min.core.getParam(min.instance, 'BlueSky Access Token', null);
|
||||||
const access_token_secret = min.core.getParam(min.instance, 'Twitter Access Token Secret', null);
|
const access_token_secret = min.core.getParam(min.instance, 'BlueSky Access Token Secret', null);
|
||||||
|
|
||||||
if (!consumer_key || !consumer_secret || !access_token_key || !access_token_secret) {
|
if (!consumer_key || !consumer_secret || !access_token_key || !access_token_secret) {
|
||||||
GBLogEx.info(min, 'Twitter not configured in .gbot.');
|
GBLogEx.info(min, 'BlueSky not configured in .gbot.');
|
||||||
}
|
}
|
||||||
|
throw new Error('Not implemented yet.');
|
||||||
|
|
||||||
const client = new TwitterApi({
|
GBLogEx.info(min, `BlueSky Automation: ${text}.`);
|
||||||
appKey: consumer_key,
|
|
||||||
appSecret: consumer_secret,
|
|
||||||
accessToken: access_token_key,
|
|
||||||
accessSecret: access_token_secret
|
|
||||||
});
|
|
||||||
|
|
||||||
await client.v2.tweet(text);
|
|
||||||
GBLogEx.info(min, `Twitter Automation: ${text}.`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -118,7 +118,6 @@ const systemVariables = [
|
||||||
'valueOf'
|
'valueOf'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
export const createVm2Pool = ({ min, max, ...limits }) => {
|
export const createVm2Pool = ({ min, max, ...limits }) => {
|
||||||
limits = Object.assign(
|
limits = Object.assign(
|
||||||
{
|
{
|
||||||
|
@ -140,8 +139,14 @@ export const createVm2Pool = ({ min, max, ...limits }) => {
|
||||||
let stderrCache = '';
|
let stderrCache = '';
|
||||||
|
|
||||||
const run = async (code: any, scope: any) => {
|
const run = async (code: any, scope: any) => {
|
||||||
|
// Configure environment variables
|
||||||
|
const env = Object.assign({}, process.env, {
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
NODE_OPTIONS: '' // Clear NODE_OPTIONS if needed
|
||||||
|
});
|
||||||
|
|
||||||
const childProcess = spawn(
|
const childProcess = spawn(
|
||||||
'cpulimit',
|
'/usr/bin/cpulimit',
|
||||||
[
|
[
|
||||||
'-ql',
|
'-ql',
|
||||||
limits.cpu,
|
limits.cpu,
|
||||||
|
@ -153,7 +158,7 @@ export const createVm2Pool = ({ min, max, ...limits }) => {
|
||||||
limits.script,
|
limits.script,
|
||||||
ref
|
ref
|
||||||
],
|
],
|
||||||
{ cwd: limits.cwd, shell: false }
|
{ cwd: limits.cwd, shell: true, env: env }
|
||||||
);
|
);
|
||||||
|
|
||||||
childProcess.stdout.on('data', data => {
|
childProcess.stdout.on('data', data => {
|
||||||
|
@ -186,7 +191,7 @@ export const createVm2Pool = ({ min, max, ...limits }) => {
|
||||||
|
|
||||||
// Only attach if called by debugger/run.
|
// Only attach if called by debugger/run.
|
||||||
|
|
||||||
if (GBServer.globals.debuggers[limits.botId]) {
|
if (limits.debug) {
|
||||||
const debug = async () => {
|
const debug = async () => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
CDP(async client => {
|
CDP(async client => {
|
||||||
|
|
|
@ -26,10 +26,13 @@ const server = net1.createServer(socket => {
|
||||||
const buffer = [];
|
const buffer = [];
|
||||||
|
|
||||||
const sync = async () => {
|
const sync = async () => {
|
||||||
|
|
||||||
const request = buffer.join('').toString();
|
const request = buffer.join('').toString();
|
||||||
|
console.log(request);
|
||||||
if (request.includes('\n')) {
|
if (request.includes('\n')) {
|
||||||
try {
|
try {
|
||||||
const { code, scope } = JSON.parse(request);
|
const { code, scope } = JSON.parse(request);
|
||||||
|
|
||||||
const result = await evaluate(code, {
|
const result = await evaluate(code, {
|
||||||
...scope,
|
...scope,
|
||||||
module: null
|
module: null
|
||||||
|
@ -45,6 +48,11 @@ const server = net1.createServer(socket => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
socket.on('error', err => {
|
||||||
|
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
socket.on('data', data => {
|
socket.on('data', data => {
|
||||||
buffer.push(data);
|
buffer.push(data);
|
||||||
|
|
|
@ -1016,7 +1016,8 @@ export class GBDeployer implements IGBDeployer {
|
||||||
'google-chat.gblib',
|
'google-chat.gblib',
|
||||||
'teams.gblib',
|
'teams.gblib',
|
||||||
'hubspot.gblib',
|
'hubspot.gblib',
|
||||||
'llm.gblib'
|
'llm.gblib',
|
||||||
|
'saas.gbapp'
|
||||||
];
|
];
|
||||||
|
|
||||||
return names.indexOf(name) > -1;
|
return names.indexOf(name) > -1;
|
||||||
|
|
|
@ -424,10 +424,12 @@ export class GBMinService {
|
||||||
|
|
||||||
GBServer.globals.server
|
GBServer.globals.server
|
||||||
.all(`/${min.instance.botId}/whatsapp`, async (req, res) => {
|
.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'];
|
||||||
|
const challenge = min.core.getParam<string>(min.instance, `Meta Challenge`, null);
|
||||||
|
|
||||||
if (val === process.env.META_CHALLENGE) {
|
if (challenge && val === challenge) {
|
||||||
res.send(req.query['hub.challenge']);
|
res.send(req.query['hub.challenge']);
|
||||||
res.status(200);
|
res.status(200);
|
||||||
GBLogEx.info(min, `Meta callback OK. ${JSON.stringify(req.query)}`);
|
GBLogEx.info(min, `Meta callback OK. ${JSON.stringify(req.query)}`);
|
||||||
|
|
445
packages/default.gbui/src/components/Debugger.js
Normal file
445
packages/default.gbui/src/components/Debugger.js
Normal file
|
@ -0,0 +1,445 @@
|
||||||
|
// import * as React from "react";
|
||||||
|
// import Header from "./Header";
|
||||||
|
// import HeroList, { HeroListItem } from "./HeroList";
|
||||||
|
// import Progress from "./Progress";
|
||||||
|
// import "../../../assets/icon-16.png";
|
||||||
|
// import "../../../assets/icon-32.png";
|
||||||
|
// import "../../../assets/icon-80.png";
|
||||||
|
// import $ from "jquery";
|
||||||
|
|
||||||
|
// export interface AppProps {
|
||||||
|
// title: string;
|
||||||
|
// isOfficeInitialized: boolean;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export interface AppState {
|
||||||
|
// listItems: HeroListItem[];
|
||||||
|
// mode: number;
|
||||||
|
// conversationText: string;
|
||||||
|
// scope: string;
|
||||||
|
// state: number;
|
||||||
|
// stateInfo: string;
|
||||||
|
// inputText: string;
|
||||||
|
// messages: string;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export default class App extends React.Component<AppProps, AppState> {
|
||||||
|
// constructor(props, context) {
|
||||||
|
// super(props, context);
|
||||||
|
// this.state = {
|
||||||
|
// mode: 0,
|
||||||
|
// listItems: [],
|
||||||
|
// conversationText: "",
|
||||||
|
// scope: "",
|
||||||
|
// state: 0,
|
||||||
|
// stateInfo: "",
|
||||||
|
// messages: "",
|
||||||
|
// inputText: "",
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// botId = "dev-rodriguez22";
|
||||||
|
// botKey = "starter";
|
||||||
|
// host = "https://tender-yak-44.telebit.io";
|
||||||
|
// breakpointsMap = {};
|
||||||
|
|
||||||
|
// componentDidMount() {
|
||||||
|
// this.setState({
|
||||||
|
// listItems: [
|
||||||
|
// {
|
||||||
|
// icon: "Ribbon",
|
||||||
|
// primaryText: "Office integration to Bots",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// icon: "Unlock",
|
||||||
|
// primaryText: "Unlock features of General Bots",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// icon: "Design",
|
||||||
|
// primaryText: "Create your Bots using BASIC",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// context = async () => {
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/getContext`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function (item) {
|
||||||
|
// console.log("GBWord Add-in: context OK.");
|
||||||
|
// const line = item.line;
|
||||||
|
|
||||||
|
// Word.run(async (context) => {
|
||||||
|
// var paragraphs = context.document.body.paragraphs;
|
||||||
|
// paragraphs.load("$none");
|
||||||
|
// await context.sync();
|
||||||
|
// for (let i = 0; i < paragraphs.items.length; i++) {
|
||||||
|
// const paragraph = paragraphs.items[i];
|
||||||
|
|
||||||
|
// context.load(paragraph, ["text", "font"]);
|
||||||
|
// paragraph.font.highlightColor = null;
|
||||||
|
|
||||||
|
// if (i === line) {
|
||||||
|
// paragraph.font.highlightColor = "Yellow";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// await context.sync();
|
||||||
|
// });
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// setExecutionLine = async (line) => {
|
||||||
|
// Word.run(async (context) => {
|
||||||
|
// var paragraphs = context.document.body.paragraphs;
|
||||||
|
// paragraphs.load("$none");
|
||||||
|
// await context.sync();
|
||||||
|
// for (let i = 0; i < paragraphs.items.length; i++) {
|
||||||
|
// const paragraph = paragraphs.items[i];
|
||||||
|
|
||||||
|
// context.load(paragraph, ["text", "font"]);
|
||||||
|
// paragraph.font.highlightColor = null;
|
||||||
|
|
||||||
|
// if (i === line) {
|
||||||
|
// paragraph.font.highlightColor = "Yellow";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// await context.sync();
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// breakpoint = async () => {
|
||||||
|
// let line = 0;
|
||||||
|
|
||||||
|
// Word.run(async (context) => {
|
||||||
|
// let selection = context.document.getSelection();
|
||||||
|
// selection.load();
|
||||||
|
|
||||||
|
// await context.sync();
|
||||||
|
|
||||||
|
// console.log("Empty selection, cursor.");
|
||||||
|
|
||||||
|
// const paragraph = selection.paragraphs.getFirst();
|
||||||
|
// paragraph.select();
|
||||||
|
// context.load(paragraph, ["text", "font"]);
|
||||||
|
|
||||||
|
// var paragraphs = context.document.body.paragraphs;
|
||||||
|
// paragraphs.load("$none");
|
||||||
|
// await context.sync();
|
||||||
|
|
||||||
|
// for (let i = 0; i < paragraphs.items.length; i++) {
|
||||||
|
// const paragraph1 = paragraphs.items[i];
|
||||||
|
|
||||||
|
// if (paragraph1 === paragraph) {
|
||||||
|
// line = i + 1;
|
||||||
|
// paragraph.font.highlightColor = "Orange";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return context.sync();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/setBreakpoint`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey, line },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function () {
|
||||||
|
// console.log("GBWord Add-in: breakpoint OK.");
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// refactor = async () => {
|
||||||
|
// let line = 0;
|
||||||
|
|
||||||
|
// let change = 'ssssssssssssssssssss';
|
||||||
|
|
||||||
|
// Word.run(async (context) => {
|
||||||
|
// let selection = context.document.getSelection();
|
||||||
|
// selection.load();
|
||||||
|
|
||||||
|
// await context.sync();
|
||||||
|
|
||||||
|
// var paragraphs = selection.paragraphs;
|
||||||
|
// paragraphs.load("$none");
|
||||||
|
// await context.sync();
|
||||||
|
// let code = '';
|
||||||
|
// for (let i = 0; i < paragraphs.items.length; i++) {
|
||||||
|
|
||||||
|
// const paragraph = paragraphs.items[i];
|
||||||
|
// context.load(paragraph, ["text", "font"]);
|
||||||
|
// code += paragraph.text;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/refactor`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, code: code, change: change },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(async function (data) {
|
||||||
|
|
||||||
|
// Word.run(async (context) => {
|
||||||
|
// var selectedRange = context.document.getSelection();
|
||||||
|
// context.load(selectedRange, "text");
|
||||||
|
// selectedRange.text = data;
|
||||||
|
|
||||||
|
// await context.sync();
|
||||||
|
// });
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return context.sync();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// };
|
||||||
|
|
||||||
|
// resume = async () => {
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/resume`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function () {
|
||||||
|
// console.log("GBWord Add-in: resume OK.");
|
||||||
|
// this.setState({ mode: 1 });
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// step = async () => {
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/step`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function () {
|
||||||
|
// console.log("GBWord Add-in: step OK.");
|
||||||
|
// this.setState({ mode: 2 });
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// stop = async () => {
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/stop`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function () {
|
||||||
|
// console.log("GBWord Add-in: stop OK.");
|
||||||
|
// this.setState({ mode: 0 });
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// sendMessage = async (args) => {
|
||||||
|
// if (args.keyCode === 13) {
|
||||||
|
// const text = args.target.value;
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/sendMessage`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey, text: text },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function () {
|
||||||
|
// console.log("GBWord Add-in: sendMessage OK.");
|
||||||
|
// args.target.value = "";
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// waitFor = (delay) => new Promise((resolve) => setTimeout(resolve, delay));
|
||||||
|
|
||||||
|
// refresh = async () => {
|
||||||
|
// const context = await this.context();
|
||||||
|
|
||||||
|
// this.setState({
|
||||||
|
// conversationText: context['conversationText'],
|
||||||
|
// state: context['state'],
|
||||||
|
// messages: context['messages'],
|
||||||
|
// scope: context['scope'],
|
||||||
|
// mode: context['state']
|
||||||
|
// });
|
||||||
|
// await this.waitFor(3000);
|
||||||
|
// await this.refresh();
|
||||||
|
// };
|
||||||
|
|
||||||
|
|
||||||
|
// debug = async () => {
|
||||||
|
// if (this.state.mode === 0) {
|
||||||
|
// const url = `${this.host}/api/v3/${this.botId}/dbg/start`;
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// data: { botId: this.botId, botKey: this.botKey, scriptName: "auto" },
|
||||||
|
// url: url,
|
||||||
|
// dataType: "json",
|
||||||
|
// method: "POST",
|
||||||
|
// })
|
||||||
|
// .done(function () {
|
||||||
|
// console.log("GBWord Add-in: debug OK.");
|
||||||
|
// this.state.mode = 1;
|
||||||
|
// })
|
||||||
|
// .fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
|
// let x = jqXHR,
|
||||||
|
// y = errorThrown;
|
||||||
|
// console.log(textStatus);
|
||||||
|
// });
|
||||||
|
// } else if (this.state.mode === 2) {
|
||||||
|
// this.resume();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// await this.refresh();
|
||||||
|
// };
|
||||||
|
|
||||||
|
// formatCode = async () => {
|
||||||
|
// return Word.run(async (context) => {
|
||||||
|
// var paragraphs = context.document.body.paragraphs;
|
||||||
|
// paragraphs.load("$none");
|
||||||
|
// await context.sync();
|
||||||
|
// for (let i = 0; i < paragraphs.items.length; i++) {
|
||||||
|
// const paragraph = paragraphs.items[i];
|
||||||
|
// context.load(paragraph, ["text", "font"]);
|
||||||
|
// paragraph.font.highlightColor = null;
|
||||||
|
|
||||||
|
// const words = paragraph.split([" "], true /* trimDelimiters*/, true /* trimSpaces */);
|
||||||
|
// words.load(["text", "font"]);
|
||||||
|
// await context.sync();
|
||||||
|
// var boldWords = [];
|
||||||
|
// for (var j = 0; j < words.items.length; ++j) {
|
||||||
|
// var word = words.items[j];
|
||||||
|
// if (word.text === "TALK" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "HEAR" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "SAVE" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "FIND" && j == 3) boldWords.push(word);
|
||||||
|
// if (word.text === "OPEN" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "WAIT" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "SET" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "CLICK" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "MERGE" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "IF" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "THEN" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "ELSE" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "END" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "TWEET" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "HOVER" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "PRESS" && j == 0) boldWords.push(word);
|
||||||
|
// if (word.text === "DO" && j == 0) boldWords.push(word);
|
||||||
|
// }
|
||||||
|
// for (var j = 0; j < boldWords.length; ++j) {
|
||||||
|
// boldWords[j].font.color = "blue";
|
||||||
|
// boldWords[j].font.bold = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// await context.sync();
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// render() {
|
||||||
|
// const { title, isOfficeInitialized } = this.props;
|
||||||
|
|
||||||
|
// if (!isOfficeInitialized) {
|
||||||
|
// return (
|
||||||
|
// <Progress title={title} logo="assets/logo-filled.png" message="Please sideload your addin to see app body." />
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return (
|
||||||
|
// <div className="ms-welcome">
|
||||||
|
// <Header logo="assets/logo-filled.png" title={this.props.title} message="Welcome" />
|
||||||
|
//
|
||||||
|
// <a onClick={this.formatCode} href="#">
|
||||||
|
// <i className={`ms-Icon ms-Icon--DocumentApproval`} title="Format"></i>
|
||||||
|
// Format
|
||||||
|
// </a>
|
||||||
|
//
|
||||||
|
// <a onClick={this.debug} href="#">
|
||||||
|
// <i className={`ms-Icon ms-Icon--AirplaneSolid`} title="Run"></i>
|
||||||
|
// Run
|
||||||
|
// </a>
|
||||||
|
//
|
||||||
|
// <a onClick={this.stop} href="#">
|
||||||
|
// <i className={`ms-Icon ms-Icon--StopSolid`} title="Stop"></i>
|
||||||
|
// Stop
|
||||||
|
// </a>
|
||||||
|
//
|
||||||
|
// <a onClick={this.step} href="#">
|
||||||
|
// <i className={`ms-Icon ms-Icon--Next`} title="Step Over"></i>
|
||||||
|
// Step
|
||||||
|
// </a>
|
||||||
|
//
|
||||||
|
// <a onClick={this.breakpoint} href="#">
|
||||||
|
// <i className={`ms-Icon ms-Icon--DRM`} title="Set Breakpoint"></i>
|
||||||
|
// Break
|
||||||
|
// </a>
|
||||||
|
// <br />
|
||||||
|
// <br />
|
||||||
|
// <div>Status: {this.state.stateInfo} </div>
|
||||||
|
// <br />
|
||||||
|
// <div>Bot Messages:</div>
|
||||||
|
// <textarea title="Bot Messages" value={this.state.conversationText} readOnly={true}></textarea>
|
||||||
|
// <br />
|
||||||
|
// <textarea
|
||||||
|
// title="Message"
|
||||||
|
// readOnly={false}
|
||||||
|
// onKeyDown={this.sendMessage}
|
||||||
|
// ></textarea>
|
||||||
|
// <div>Variables:</div>
|
||||||
|
// <div>{this.state.scope} </div>
|
||||||
|
// <HeroList message="Discover what General Bots can do for you today!!" items={this.state.listItems}></HeroList>
|
||||||
|
// </div>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
|
@ -39,6 +39,7 @@ import { ChatGeneration, Generation } from '@langchain/core/outputs';
|
||||||
import {
|
import {
|
||||||
AIMessagePromptTemplate,
|
AIMessagePromptTemplate,
|
||||||
ChatPromptTemplate,
|
ChatPromptTemplate,
|
||||||
|
SystemMessagePromptTemplate,
|
||||||
HumanMessagePromptTemplate,
|
HumanMessagePromptTemplate,
|
||||||
MessagesPlaceholder
|
MessagesPlaceholder
|
||||||
} from '@langchain/core/prompts';
|
} from '@langchain/core/prompts';
|
||||||
|
@ -71,7 +72,8 @@ import {
|
||||||
SQL_MYSQL_PROMPT
|
SQL_MYSQL_PROMPT
|
||||||
} from 'langchain/chains/sql_db';
|
} from 'langchain/chains/sql_db';
|
||||||
import { GBUtil } from '../../../src/util.js';
|
import { GBUtil } from '../../../src/util.js';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import zodToJsonSchema from 'zod-to-json-schema';
|
||||||
export interface CustomOutputParserFields {}
|
export interface CustomOutputParserFields {}
|
||||||
export type ExpectedOutput = any;
|
export type ExpectedOutput = any;
|
||||||
|
|
||||||
|
@ -314,6 +316,7 @@ export class ChatServices {
|
||||||
model = new ChatOpenAI({
|
model = new ChatOpenAI({
|
||||||
azureOpenAIApiKey: azureOpenAIKey,
|
azureOpenAIApiKey: azureOpenAIKey,
|
||||||
azureOpenAIApiInstanceName: azureOpenAIApiInstanceName,
|
azureOpenAIApiInstanceName: azureOpenAIApiInstanceName,
|
||||||
|
|
||||||
azureOpenAIApiDeploymentName: azureOpenAILLMModel,
|
azureOpenAIApiDeploymentName: azureOpenAILLMModel,
|
||||||
azureOpenAIApiVersion: azureOpenAIVersion,
|
azureOpenAIApiVersion: azureOpenAIVersion,
|
||||||
temperature: 0,
|
temperature: 0,
|
||||||
|
@ -322,25 +325,38 @@ export class ChatServices {
|
||||||
|
|
||||||
let tools = await ChatServices.getTools(min);
|
let tools = await ChatServices.getTools(min);
|
||||||
let toolsAsText = ChatServices.getToolsAsText(tools);
|
let toolsAsText = ChatServices.getToolsAsText(tools);
|
||||||
|
let openaiTools = tools.map(tool => convertToOpenAITool(tool, { strict: true }));
|
||||||
|
|
||||||
|
function updateFields(schemas) {
|
||||||
|
schemas.forEach(schema => {
|
||||||
|
|
||||||
|
if (schema.function && schema.function.parameters) {
|
||||||
|
delete schema.function.strict;
|
||||||
|
schema.function.parameters.additionalProperties = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
updateFields(openaiTools);
|
||||||
|
|
||||||
const modelWithTools = model.bind({
|
const modelWithTools = model.bind({
|
||||||
tools: tools.map(convertToOpenAITool)
|
tools: openaiTools
|
||||||
});
|
});
|
||||||
|
|
||||||
const questionGeneratorTemplate = ChatPromptTemplate.fromMessages([
|
const questionGeneratorTemplate = ChatPromptTemplate.fromMessages([
|
||||||
AIMessagePromptTemplate.fromTemplate(
|
SystemMessagePromptTemplate.fromTemplate(
|
||||||
`
|
`
|
||||||
Answer the question without calling any tool, but if there is a need to call:
|
${systemPrompt}
|
||||||
You have access to the following set of tools.
|
|
||||||
Here are the names and descriptions for each tool:
|
|
||||||
|
|
||||||
|
When a tool is required, use the tools provided below.
|
||||||
|
The tools available to you are listed below, along with their names, parameters, and descriptions:
|
||||||
|
IMPORTANT: Never call a tool with a missing required param, without asking them first to the user!
|
||||||
|
List of tools:
|
||||||
${toolsAsText}
|
${toolsAsText}
|
||||||
|
|
||||||
Do not use any previous tools output in the {chat_history}.
|
|
||||||
`
|
`
|
||||||
),
|
),
|
||||||
new MessagesPlaceholder('chat_history'),
|
new MessagesPlaceholder('chat_history'),
|
||||||
AIMessagePromptTemplate.fromTemplate(`Follow Up Input: {question}
|
HumanMessagePromptTemplate.fromTemplate(`Follow Up Input: {question}
|
||||||
Standalone question:`)
|
Standalone question:`)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -352,14 +368,23 @@ export class ChatServices {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const toolsResultPrompt = ChatPromptTemplate.fromMessages([
|
const toolsResultPrompt = ChatPromptTemplate.fromMessages([
|
||||||
AIMessagePromptTemplate.fromTemplate(
|
SystemMessagePromptTemplate.fromTemplate(
|
||||||
`The tool just returned value in last call. Using {chat_history}
|
`
|
||||||
rephrase the answer to the user using this tool output.
|
${systemPrompt}
|
||||||
|
|
||||||
|
List of tools:
|
||||||
|
${toolsAsText}
|
||||||
|
|
||||||
`
|
`
|
||||||
),
|
),
|
||||||
new MessagesPlaceholder('chat_history'),
|
AIMessagePromptTemplate.fromTemplate(
|
||||||
AIMessagePromptTemplate.fromTemplate(`Tool output: {tool_output}
|
`
|
||||||
Standalone question:`)
|
The tool just returned value in last call answer the question based on tool description.
|
||||||
|
`
|
||||||
|
),
|
||||||
|
|
||||||
|
HumanMessagePromptTemplate.fromTemplate(`Tool output: {tool_output}
|
||||||
|
Folowing answer:`)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const jsonInformation = `VERY IMPORTANT: ALWAYS return VALID standard JSON with the folowing structure: 'text' as answer,
|
const jsonInformation = `VERY IMPORTANT: ALWAYS return VALID standard JSON with the folowing structure: 'text' as answer,
|
||||||
|
@ -414,13 +439,14 @@ export class ChatServices {
|
||||||
tool_output: async (output: object) => {
|
tool_output: async (output: object) => {
|
||||||
const name = output['func'][0].function.name;
|
const name = output['func'][0].function.name;
|
||||||
const args = JSON.parse(output['func'][0].function.arguments);
|
const args = JSON.parse(output['func'][0].function.arguments);
|
||||||
GBLogEx.info(min, `Running .gbdialog '${name}' as LLM tool...`);
|
GBLogEx.info(min, `LLM Tool called .gbdialog '${name}'...`);
|
||||||
const pid = GBVMService.createProcessInfo(null, min, 'LLM', null);
|
const pid = GBVMService.createProcessInfo(null, min, 'LLM', null);
|
||||||
|
|
||||||
return await GBVMService.callVM(name, min, false, pid, false, args);
|
return await GBVMService.callVM(name, min, false, pid, false, args);
|
||||||
},
|
},
|
||||||
chat_history: async () => {
|
chat_history: async () => {
|
||||||
const { chat_history } = await memory.loadMemoryVariables({});
|
const { chat_history } = await memory.loadMemoryVariables({});
|
||||||
|
|
||||||
return chat_history;
|
return chat_history;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -474,7 +500,7 @@ export class ChatServices {
|
||||||
|
|
||||||
result = res.text ? res.text : res;
|
result = res.text ? res.text : res;
|
||||||
sources = res.sources;
|
sources = res.sources;
|
||||||
} else if (LLMMode === 'function') {
|
} else if (LLMMode === 'tool') {
|
||||||
result = await conversationalToolChain.invoke({
|
result = await conversationalToolChain.invoke({
|
||||||
question
|
question
|
||||||
});
|
});
|
||||||
|
@ -620,7 +646,16 @@ export class ChatServices {
|
||||||
|
|
||||||
private static getToolsAsText(tools) {
|
private static getToolsAsText(tools) {
|
||||||
return Object.keys(tools)
|
return Object.keys(tools)
|
||||||
.map(toolname => `- ${tools[toolname].name}: ${tools[toolname].description}`)
|
.map(toolname => {
|
||||||
|
const tool = tools[toolname];
|
||||||
|
const properties = tool.lc_kwargs.schema.properties;
|
||||||
|
const params = Object.keys(properties).map(param => {
|
||||||
|
const { description, type } = properties[param];
|
||||||
|
return `${param} *REQUIRED* (${type}): ${description}`;
|
||||||
|
}).join(', ');
|
||||||
|
|
||||||
|
return `- ${tool.name}: ${tool.description}\n Parameters: ${params?? 'No parameters'}`;
|
||||||
|
})
|
||||||
.join('\n');
|
.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -638,7 +673,8 @@ export class ChatServices {
|
||||||
|
|
||||||
if (funcObj) {
|
if (funcObj) {
|
||||||
// TODO: Use ajv.
|
// TODO: Use ajv.
|
||||||
funcObj.schema = eval(jsonSchemaToZod(funcObj.parameters));
|
|
||||||
|
funcObj.schema = eval(funcObj.schema);
|
||||||
functions.push(new DynamicStructuredTool(funcObj));
|
functions.push(new DynamicStructuredTool(funcObj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,4 +79,32 @@ export class ImageServices {
|
||||||
return { localName, url };
|
return { localName, url };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getCaptionForImage({ pid, imageUrl }) {
|
||||||
|
const { min, user, params } = await DialogKeywords.getProcessInfo(pid);
|
||||||
|
|
||||||
|
const azureOpenAIKey = await min.core.getParam(min.instance, 'Azure Open AI Key', null);
|
||||||
|
const azureOpenAITextModel = 'gpt-4'; // Specify GPT-4 model here
|
||||||
|
const azureOpenAIEndpoint = await min.core.getParam(min.instance, 'Azure Open AI Endpoint', null);
|
||||||
|
|
||||||
|
if (azureOpenAIKey && azureOpenAITextModel && imageUrl) {
|
||||||
|
// Initialize the Azure OpenAI client
|
||||||
|
const client = new OpenAI({ apiKey: azureOpenAIKey, baseURL: azureOpenAIEndpoint });
|
||||||
|
|
||||||
|
// Construct a prompt to describe the image and generate a caption
|
||||||
|
const prompt = `Provide a descriptive caption for the image at the following URL: ${imageUrl}`;
|
||||||
|
|
||||||
|
// Generate a caption using GPT-4
|
||||||
|
const response = await client.completions.create({
|
||||||
|
model: azureOpenAITextModel,
|
||||||
|
prompt: prompt,
|
||||||
|
max_tokens: 50
|
||||||
|
});
|
||||||
|
|
||||||
|
const caption = response['data'].choices[0].text.trim();
|
||||||
|
GBLogEx.info(min, `Generated caption: ${caption}`);
|
||||||
|
|
||||||
|
return { caption };
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
5
packages/saas.gbapp/PRESS-RELEASE.md
Executable file
5
packages/saas.gbapp/PRESS-RELEASE.md
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
The community needs a common platform to build bots on top of BOT Framework or any framework that can be added in the future to General Bots. People will need to create lots of custom personal assistants crossing entities like bots, knowledge, personality, branding, style. But now they only have frameworks that allow the bot creation but with no AI ecosystem in mind. Industry has proven to be a good ground for starting Robotic Process Automation through bots, but often lack of specialized hand-word and does not see as forecast to a digital transformation anchor.
|
||||||
|
This platform is proposed to be the one in terms of democratizing the community through bot building. It's community driven and has a lot to offer as a quick start to the bot automation world primarily based on Microsoft platform. So people who does not know how to program can start a new bot from Excel, Word, OneNote, or any piece of information. The package system is the base for the Marketplace which currently offer knowledge, themes, bots and custom bot UIs and can offer several classes of packages which compounds the entire AI body.
|
||||||
|
Using Azure and Cognitive Services we have created a community for General Bots which allow anyone to build their bot by using common tools like Excel and Photoshop. The administration is done by conversation and packages are easily deployed and maintained.
|
||||||
|
The adoption is much like SharePoint. When someone needs a site, they create a New Site. General Bots can do the same just copying and pasting some files in Windows Explorer.
|
||||||
|
The community builds packages using TypeScript (currently) and Python (future) and publish it through General Bots store and share the core through all vendors. A sample .gbapp package for Azure Active Directory Reset password is provided at https://github.com/pragmatismo-io/AzureADPasswordReset.gbapp.
|
304
packages/saas.gbapp/dialog/NewUserDialog.ts
Executable file
304
packages/saas.gbapp/dialog/NewUserDialog.ts
Executable file
|
@ -0,0 +1,304 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { IGBDialog, GBMinInstance } from 'botlib';
|
||||||
|
import { Messages } from '../strings.js';
|
||||||
|
import { MainService } from '../service/MainService.js';
|
||||||
|
import { Package } from '../index.js';
|
||||||
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
|
|
||||||
|
export class NewUserDialog extends IGBDialog {
|
||||||
|
static getBotNameDialog(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_botname',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
|
||||||
|
await step.prompt('textPrompt', Messages[locale].whats_botname);
|
||||||
|
},
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
|
||||||
|
const extractEntity = text => {
|
||||||
|
return text.match(/[_a-zA-Z][_a-zA-Z0-9]{0,16}/gi);
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = extractEntity(step.context.activity.originalText);
|
||||||
|
|
||||||
|
if (value === null || value.length != 1) {
|
||||||
|
await step.context.sendActivity(Messages[locale].validation_enter_valid_botname);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/welcome_saas_botname', step.activeDialog.state.options);
|
||||||
|
} else {
|
||||||
|
const botName = value[0];
|
||||||
|
if (await min.deployService.botExists(botName)) {
|
||||||
|
await step.context.sendActivity(`O Bot ${botName} já existe. Escolha por favor, outro nome!`);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/welcome_saas_botname', step.activeDialog.state.options);
|
||||||
|
} else {
|
||||||
|
step.activeDialog.state.options.botName = botName;
|
||||||
|
|
||||||
|
return await step.replaceDialog('/welcome_saas_bottemplate', step.activeDialog.state.options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getBotTemplateDialog(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_bottemplate',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
await step.context.sendActivity('Aqui estão alguns modelos para você escolher:');
|
||||||
|
let gboService = min.gbappServices['gboService'];
|
||||||
|
const list = await gboService.listTemplates(min);
|
||||||
|
|
||||||
|
let templateMessage = undefined;
|
||||||
|
|
||||||
|
await CollectionUtil.asyncForEach(list, async item => {
|
||||||
|
if (item.name !== 'Shared.gbai') {
|
||||||
|
templateMessage = templateMessage ? `${templateMessage}\n- ${item.name}` : `- ${item.name}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await step.context.sendActivity(templateMessage);
|
||||||
|
|
||||||
|
step.activeDialog.state.options.templateList = list;
|
||||||
|
return await step.prompt('textPrompt', `Qual modelo de bot você gostaria de usar?`);
|
||||||
|
},
|
||||||
|
async step => {
|
||||||
|
const list = step.activeDialog.state.options.templateList;
|
||||||
|
let template = null;
|
||||||
|
await CollectionUtil.asyncForEach(list, async item => {
|
||||||
|
let gboService = min.gbappServices['gboService'];
|
||||||
|
if (gboService.kmpSearch(step.context.activity.originalText, item.name) != -1) {
|
||||||
|
template = item.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (template === null) {
|
||||||
|
await step.context.sendActivity(`Escolha, por favor, um destes modelos listados.`);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/welcome_saas_bottemplate', step.activeDialog.state.options);
|
||||||
|
} else {
|
||||||
|
step.activeDialog.state.options.templateName = template;
|
||||||
|
debugger;
|
||||||
|
await NewUserDialog.createBot(step, min, true);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/ask', { isReturning: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getReturnFromCC(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_return_cc',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
await step.context.sendActivity(Messages[locale].thanks_payment);
|
||||||
|
await NewUserDialog.createBot(step, min, false);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/ask', { isReturning: true });
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getReturnFromDocument(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_return_document',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
step.activeDialog.state.options.nextDialog = 'welcome_saas_return_payment';
|
||||||
|
|
||||||
|
return await step.replaceDialog('/bank_payment_type', step.activeDialog.state.options);
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getReturnFromPayment(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_return_payment',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
if (step.activeDialog.state.options.paymentType === 'cc') {
|
||||||
|
step.activeDialog.state.options.nextDialog = 'welcome_saas_return_cc';
|
||||||
|
await step.replaceDialog(`/bank_ccnumber`, step.activeDialog.state.options);
|
||||||
|
} else {
|
||||||
|
const locale = 'en-US';
|
||||||
|
await step.context.sendActivity(Messages[locale].boleto_mail);
|
||||||
|
|
||||||
|
await step.context.sendActivity('textPrompt', Messages[locale].thanks_payment);
|
||||||
|
await NewUserDialog.createBot(step, min, false);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/ask', { isReturning: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getVoucherDialog(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_voucher',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
await step.prompt('textPrompt', Messages[locale].own_voucher);
|
||||||
|
},
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
|
||||||
|
if (step.result.toLowerCase() === 'gb2020') {
|
||||||
|
await NewUserDialog.createBot(step, min, true);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/ask', { isReturning: true });
|
||||||
|
} else {
|
||||||
|
// return await step.replaceDialog('/welcome_saas_voucher', 'Os meios de pagamento estão neste momento desabilitados, por favor informe um voucher ou contate info@pragmatismo.cloud.');
|
||||||
|
|
||||||
|
step.activeDialog.state.options.nextDialog = 'welcome_saas_return_document';
|
||||||
|
return await step.replaceDialog('/xrm_document', step.activeDialog.state.options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async createBot(step: any, min: GBMinInstance, free: boolean) {
|
||||||
|
const locale = 'en-US';
|
||||||
|
await step.context.sendActivity(Messages[locale].ok_procceding_creation);
|
||||||
|
const url = `https://gb.pragmatismo.cloud/${step.activeDialog.state.options.botName}`;
|
||||||
|
await step.context.sendActivity(Messages[locale].bot_created(url));
|
||||||
|
const service = new MainService();
|
||||||
|
await service.createSubscription(
|
||||||
|
min,
|
||||||
|
step.activeDialog.state.options.name,
|
||||||
|
step.activeDialog.state.options.document,
|
||||||
|
step.activeDialog.state.options.email,
|
||||||
|
step.activeDialog.state.options.mobile,
|
||||||
|
step.activeDialog.state.options.botName,
|
||||||
|
step.activeDialog.state.options.ccNumber,
|
||||||
|
step.activeDialog.state.options.ccExpiresOnMonth,
|
||||||
|
step.activeDialog.state.options.ccExpiresOnYear,
|
||||||
|
step.activeDialog.state.options.ccSecuritycode,
|
||||||
|
step.activeDialog.state.options.templateName,
|
||||||
|
free
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDialogBatch(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas_batch',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
await step.context.sendActivity(Messages[locale].welcome);
|
||||||
|
|
||||||
|
await step.prompt('textPrompt', `Please, inform bot names separeted by comma (,).`);
|
||||||
|
},
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
|
||||||
|
const service = new MainService();
|
||||||
|
|
||||||
|
const bots = step.context.activity.originalText.split(',');
|
||||||
|
bots.forEach(async botName => {
|
||||||
|
await service.createSubscription(
|
||||||
|
min,
|
||||||
|
botName,
|
||||||
|
'999999999',
|
||||||
|
'operations@pragmatismo.cloud',
|
||||||
|
'5521999998888',
|
||||||
|
botName,
|
||||||
|
null,
|
||||||
|
'12',
|
||||||
|
'99',
|
||||||
|
'1234',
|
||||||
|
'Starter.gbai',
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDialog(min: GBMinInstance) {
|
||||||
|
return {
|
||||||
|
id: '/welcome_saas',
|
||||||
|
waterfall: [
|
||||||
|
async step => {
|
||||||
|
const locale = 'en-US';
|
||||||
|
|
||||||
|
step.activeDialog.state.options.document = null;
|
||||||
|
step.activeDialog.state.options.email = null;
|
||||||
|
step.activeDialog.state.options.botName = null;
|
||||||
|
step.activeDialog.state.options.ccNumber = null;
|
||||||
|
step.activeDialog.state.options.ccExpiresOnMonth = null;
|
||||||
|
step.activeDialog.state.options.ccExpiresOnYear = null;
|
||||||
|
step.activeDialog.state.options.ccSecuritycode = null;
|
||||||
|
step.activeDialog.state.options.templateName = null;
|
||||||
|
|
||||||
|
await step.context.sendActivity(Messages[locale].welcome);
|
||||||
|
|
||||||
|
const mobile = step.context.activity.from.id;
|
||||||
|
|
||||||
|
step.activeDialog.state.options.nextDialog = 'welcome_saas_botname';
|
||||||
|
|
||||||
|
if (isNaN(mobile as any)) {
|
||||||
|
await step.context.sendActivity(Messages[locale].ok_get_information);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/profile_name', step.activeDialog.state.options);
|
||||||
|
} else {
|
||||||
|
const name = Package.welcomes ? Package.welcomes[mobile] : null;
|
||||||
|
step.activeDialog.state.options.name = name;
|
||||||
|
step.activeDialog.state.options.mobile = mobile;
|
||||||
|
|
||||||
|
await step.context.sendActivity(`Olá ${name}, vamos criar o seu Bot agora.`);
|
||||||
|
|
||||||
|
return await step.replaceDialog('/profile_email', step.activeDialog.state.options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
195
packages/saas.gbapp/index.ts
Executable file
195
packages/saas.gbapp/index.ts
Executable file
|
@ -0,0 +1,195 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
import { IGBPackage, GBMinInstance, IGBCoreService, GBLog, IGBAdminService, GBDialogStep } from 'botlib'
|
||||||
|
import { Sequelize } from 'sequelize-typescript'
|
||||||
|
import { GBOnlineSubscription } from './model/MainModel'
|
||||||
|
|
||||||
|
import { MSSubscriptionService } from './service/MSSubscription'
|
||||||
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
|
import { NewUserDialog } from './dialog/NewUserDialog'
|
||||||
|
const MicrosoftGraph = require("@microsoft/microsoft-graph-client");
|
||||||
|
|
||||||
|
const cron = require('node-cron');
|
||||||
|
|
||||||
|
export class Package implements IGBPackage {
|
||||||
|
sysPackages: IGBPackage[]
|
||||||
|
adminService: IGBAdminService;
|
||||||
|
public static welcomes = {};
|
||||||
|
instanceId: any
|
||||||
|
|
||||||
|
public getDialogs(min: GBMinInstance) {
|
||||||
|
return [NewUserDialog.getDialog(min),
|
||||||
|
NewUserDialog.getBotNameDialog(min),
|
||||||
|
NewUserDialog.getVoucherDialog(min),
|
||||||
|
NewUserDialog.getBotTemplateDialog(min),
|
||||||
|
NewUserDialog.getReturnFromPayment(min),
|
||||||
|
NewUserDialog.getReturnFromCC(min),
|
||||||
|
NewUserDialog.getReturnFromDocument(min),
|
||||||
|
NewUserDialog.getDialogBatch(min)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadPackage(core: IGBCoreService, sequelize: Sequelize): Promise<void> {
|
||||||
|
sequelize.addModels([GBOnlineSubscription]);
|
||||||
|
core.setWWWRoot(process.env.SAAS_WWWROOT);
|
||||||
|
core.setEntryPointDialog('/welcome_saas');
|
||||||
|
|
||||||
|
// Installs webhook for Microsoft intercommunication.
|
||||||
|
|
||||||
|
core.installWebHook(true, '/mslanding', async (req, res) => {
|
||||||
|
const service = new MSSubscriptionService();
|
||||||
|
await service.handleMSLanding(req, res);
|
||||||
|
});
|
||||||
|
core.installWebHook(true, '/mshook', async (req, res) => {
|
||||||
|
const service = new MSSubscriptionService();
|
||||||
|
await service.handleMSHook(req, res);
|
||||||
|
});
|
||||||
|
core.installWebHook(true, '/signup', async (req, res) => {
|
||||||
|
const service = new MSSubscriptionService();
|
||||||
|
await service.handleMSSignUp(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setups schedule to trigger notifications as pro-active messages.
|
||||||
|
*/
|
||||||
|
private setupScheduler(min, sendToDevice) {
|
||||||
|
const schedule = '30 09 * * 1-5';
|
||||||
|
const options = {
|
||||||
|
scheduled: true,
|
||||||
|
timezone: 'America/Sao_Paulo'
|
||||||
|
};
|
||||||
|
|
||||||
|
this.adminService = min.adminService;
|
||||||
|
this.instanceId = min.instanceId;
|
||||||
|
|
||||||
|
cron.schedule(schedule, async () => {
|
||||||
|
GBLog.info( 'Sending Tasks notifications if applies...');
|
||||||
|
await this.notifyJob(sendToDevice);
|
||||||
|
}, options);
|
||||||
|
GBLog.info( 'Running Reviews notifications 09:30 from Monday to Friday...');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by scheduler to send notification message to phones.
|
||||||
|
* @param sendToDevice The function used to notify.
|
||||||
|
*/
|
||||||
|
private async notifyJob(sendToDevice) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public async getTasksMarkdown(path, file) {
|
||||||
|
|
||||||
|
let token =
|
||||||
|
await this.adminService.acquireElevatedToken(this.instanceId);
|
||||||
|
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let siteId = process.env.STORAGE_SITE_ID;
|
||||||
|
let libraryId = process.env.STORAGE_LIBRARY;
|
||||||
|
|
||||||
|
let res = await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/root:${path}:/children`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
let document = res.value.filter(m => {
|
||||||
|
return m.name === file
|
||||||
|
});
|
||||||
|
|
||||||
|
let results = await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/items/${document[0].id}/workbook/worksheets('Tasks')/range(address='A1:A10')`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
let index = 1;
|
||||||
|
let md = `*Tasks*\n`;
|
||||||
|
|
||||||
|
for (; index <= 10; index++) {
|
||||||
|
const row = results.text[index];
|
||||||
|
if (row !== undefined) {
|
||||||
|
md = `${md}\n *${index}*. ${row[0]}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
|
||||||
|
async unloadPackage(core: IGBCoreService): Promise<void> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadBot(min: GBMinInstance): Promise<void> {
|
||||||
|
|
||||||
|
let gboService = min.gbappServices['gboService'];
|
||||||
|
|
||||||
|
|
||||||
|
// Gets the sendToDevice method of whatsapp.gblib and setups scheduler.
|
||||||
|
|
||||||
|
if (min.whatsAppDirectLine !== undefined && min.botId === "Pragmatismo") {
|
||||||
|
const sendToDevice = min.whatsAppDirectLine.sendToDevice.bind(min.whatsAppDirectLine);
|
||||||
|
this.setupScheduler(min, sendToDevice);
|
||||||
|
this.notifyJob(sendToDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async unloadBot(min: GBMinInstance): Promise<void> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async onNewSession(min: GBMinInstance, step: GBDialogStep): Promise<void> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async onExchangeData(min: GBMinInstance, kind: string, data: any) {
|
||||||
|
|
||||||
|
switch (kind) {
|
||||||
|
case "whatsappMessage":
|
||||||
|
|
||||||
|
const from = data.from;
|
||||||
|
const fromName = data.fromName;
|
||||||
|
Package.welcomes[from] = fromName;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
GBLog.verbose('saas.gbapp onExchangeData called');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
81
packages/saas.gbapp/model/MainModel.ts
Executable file
81
packages/saas.gbapp/model/MainModel.ts
Executable file
|
@ -0,0 +1,81 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
Column,
|
||||||
|
Model,
|
||||||
|
HasMany,
|
||||||
|
BelongsTo,
|
||||||
|
BelongsToMany,
|
||||||
|
Length,
|
||||||
|
ForeignKey,
|
||||||
|
CreatedAt,
|
||||||
|
UpdatedAt,
|
||||||
|
DataType,
|
||||||
|
IsUUID,
|
||||||
|
PrimaryKey,
|
||||||
|
AutoIncrement
|
||||||
|
} from "sequelize-typescript"
|
||||||
|
|
||||||
|
@Table({ tableName: 'GBOnlineSubscription' })
|
||||||
|
export class GBOnlineSubscription extends Model<GBOnlineSubscription> {
|
||||||
|
|
||||||
|
@PrimaryKey
|
||||||
|
@AutoIncrement
|
||||||
|
@Column
|
||||||
|
Id: number
|
||||||
|
|
||||||
|
@Column
|
||||||
|
instanceId: number;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
externalSubscriptionId: string // MSFT or
|
||||||
|
|
||||||
|
@Column
|
||||||
|
saasSubscriptionStatus: string
|
||||||
|
|
||||||
|
@Column
|
||||||
|
isFreeTrial: boolean
|
||||||
|
|
||||||
|
@Column
|
||||||
|
planId: string;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
quantity: number;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
lastCCFourDigits: number;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
status: string;
|
||||||
|
}
|
354
packages/saas.gbapp/service/GBOService.ts
Executable file
354
packages/saas.gbapp/service/GBOService.ts
Executable file
|
@ -0,0 +1,354 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
import { GBMinInstance, GBLog } from "botlib";
|
||||||
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
|
const MicrosoftGraph = require("@microsoft/microsoft-graph-client");
|
||||||
|
const Juno = require('juno-payment-node');
|
||||||
|
const sgMail = require('@sendgrid/mail');
|
||||||
|
const PasswordGenerator = require('strict-password-generator').default;
|
||||||
|
|
||||||
|
export class GBOService {
|
||||||
|
|
||||||
|
public isValidCardNumber(ccNumber) {
|
||||||
|
let card = new Juno.Card();
|
||||||
|
return card.validateNumber(ccNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public isValidSecurityCode(ccNumber, cvcNumber) {
|
||||||
|
let card = new Juno.Card();
|
||||||
|
return card.validateCvc(ccNumber, cvcNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public isValidExpireDate(month, year) {
|
||||||
|
let card = new Juno.Card();
|
||||||
|
return card.validateExpireDate(month, year);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendEmail(token: string, to: string, from: string,
|
||||||
|
subject: string, text: string, html: string) {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
sgMail.setApiKey(token);
|
||||||
|
const msg = {
|
||||||
|
to: to,
|
||||||
|
from: from,
|
||||||
|
subject: subject,
|
||||||
|
text: text,
|
||||||
|
html: html
|
||||||
|
};
|
||||||
|
sgMail.send(msg, false, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createSubFolderAtRoot(token: string, name: string,
|
||||||
|
siteId: string, libraryId: string) {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const body = {
|
||||||
|
"name": name,
|
||||||
|
"folder": {},
|
||||||
|
"@microsoft.graph.conflictBehavior": "rename"
|
||||||
|
}
|
||||||
|
client.api(`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/root/children`)
|
||||||
|
.post(body, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public async createSubFolderAt(token: string, parentPath: string, name: string,
|
||||||
|
siteId: string, libraryId: string) {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const body = {
|
||||||
|
"name": name,
|
||||||
|
"folder": {},
|
||||||
|
"@microsoft.graph.conflictBehavior": "rename"
|
||||||
|
}
|
||||||
|
client.api(`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/root:/${parentPath}:/children`)
|
||||||
|
.post(body, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async listTemplates(min: GBMinInstance) {
|
||||||
|
|
||||||
|
let templateLibraryId = process.env.SAAS_TEMPLATE_LIBRARY;
|
||||||
|
let siteId = process.env.STORAGE_SITE_ID;
|
||||||
|
|
||||||
|
let token =
|
||||||
|
await (min.adminService as any).acquireElevatedToken(min.instance.instanceId, true);
|
||||||
|
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const path = `/`;
|
||||||
|
let res = await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/root/children`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
return res.value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async copyTemplates(min: GBMinInstance, gbaiDest, templateName: string, kind: string, botName: string) {
|
||||||
|
|
||||||
|
let token =
|
||||||
|
await (min.adminService as any).acquireElevatedToken(min.instance.instanceId, true);
|
||||||
|
|
||||||
|
let siteId = process.env.STORAGE_SITE_ID;
|
||||||
|
let templateLibraryId = process.env.SAAS_TEMPLATE_LIBRARY;
|
||||||
|
let libraryId = process.env.STORAGE_LIBRARY;
|
||||||
|
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const body =
|
||||||
|
{
|
||||||
|
"parentReference": { driveId: gbaiDest.parentReference.driveId, id: gbaiDest.id },
|
||||||
|
"name": `${botName}.${kind}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const packageName = `${templateName.split('.')[0]}.${kind}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const src = await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/root:/${templateName}/${packageName}`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
return await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/items/${src.id}/copy`)
|
||||||
|
.post(body);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
if (error.code === "itemNotFound") {
|
||||||
|
|
||||||
|
} else if (error.code === "nameAlreadyExists") {
|
||||||
|
|
||||||
|
let src = await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/root:/${templateName}/${packageName}:/children`)
|
||||||
|
.get();
|
||||||
|
const dstName = `${botName}.gbai/${botName}.${kind}`;
|
||||||
|
let dst = await client.api(`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/root:/${dstName}`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
await CollectionUtil.asyncForEach(src.value, async item => {
|
||||||
|
|
||||||
|
const body =
|
||||||
|
{
|
||||||
|
"parentReference": { driveId: dst.parentReference.driveId, id: dst.id }
|
||||||
|
}
|
||||||
|
await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/items/${item.id}/copy`)
|
||||||
|
.post(body);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GBLog.error(error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createExcelFile(min: GBMinInstance, destinationFolder: any, name: string) {
|
||||||
|
|
||||||
|
let token =
|
||||||
|
await (min.adminService.acquireElevatedToken as any)(min.instance.instanceId, true);
|
||||||
|
|
||||||
|
let siteId = process.env.STORAGE_SITE_ID;
|
||||||
|
let templateLibraryId = process.env.SAAS_TEMPLATE_LIBRARY;
|
||||||
|
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const body =
|
||||||
|
{
|
||||||
|
"parentReference": { driveId: destinationFolder.parentReference.driveId, id: destinationFolder.id },
|
||||||
|
"name": name
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const src = await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/root:/System.gbdata/blank.xlsx`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
return await client.api(
|
||||||
|
`https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${templateLibraryId}/drive/items/${src.id}/copy`)
|
||||||
|
.post(body);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
GBLog.error(error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async shareFolder(token: string, driveId: string, itemId: string, email: string) {
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const body =
|
||||||
|
{
|
||||||
|
"recipients": [
|
||||||
|
{
|
||||||
|
"email": email
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"message": "General Bots Online - Packages folder",
|
||||||
|
"requireSignIn": true,
|
||||||
|
"sendInvitation": true,
|
||||||
|
"roles": ["write"]
|
||||||
|
};
|
||||||
|
|
||||||
|
client.api(`https://graph.microsoft.com/v1.0/drives/${driveId}/items/${itemId}/invite`)
|
||||||
|
.post(body, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
GBLog.error('Sharing: ' + err);
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public kmpSearch(pattern, text) {
|
||||||
|
pattern = pattern.toLowerCase();
|
||||||
|
text = text.toLowerCase();
|
||||||
|
if (pattern.length == 0)
|
||||||
|
return 0; // Immediate match
|
||||||
|
|
||||||
|
// Compute longest suffix-prefix table
|
||||||
|
var lsp = [0]; // Base case
|
||||||
|
for (var i = 1; i < pattern.length; i++) {
|
||||||
|
var j = lsp[i - 1]; // Start by assuming we're extending the previous LSP
|
||||||
|
while (j > 0 && pattern.charAt(i) != pattern.charAt(j))
|
||||||
|
j = lsp[j - 1];
|
||||||
|
if (pattern.charAt(i) == pattern.charAt(j))
|
||||||
|
j++;
|
||||||
|
lsp.push(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk through text string
|
||||||
|
var j = 0; // Number of chars matched in pattern
|
||||||
|
for (var i = 0; i < text.length; i++) {
|
||||||
|
while (j > 0 && text.charAt(i) != pattern.charAt(j))
|
||||||
|
j = lsp[j - 1]; // Fall back in the pattern
|
||||||
|
if (text.charAt(i) == pattern.charAt(j)) {
|
||||||
|
j++; // Next char matched, increment position
|
||||||
|
if (j == pattern.length)
|
||||||
|
return i - (j - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1; // Not found
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAddressFromZipCode() {
|
||||||
|
// https://maps.googleapis.com/maps/api/geocode/json?address=94040
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrives token and initialize drive client API.
|
||||||
|
*/
|
||||||
|
public static async internalGetDriveClient(min: GBMinInstance) {
|
||||||
|
let token = await (min.adminService as any).acquireElevatedToken(0, true);
|
||||||
|
let siteId = process.env.STORAGE_SITE_ID;
|
||||||
|
let libraryId = process.env.STORAGE_LIBRARY;
|
||||||
|
|
||||||
|
let client = MicrosoftGraph.Client.init({
|
||||||
|
authProvider: done => {
|
||||||
|
done(null, token);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const baseUrl = `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}`;
|
||||||
|
return [baseUrl, client];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrives a document from the drive, given a path and filename.
|
||||||
|
*/
|
||||||
|
private async internalGetDocument(client: any, baseUrl: any, path: string, file: string) {
|
||||||
|
let res = await client
|
||||||
|
.api(`${baseUrl}/drive/root:${path}:/children`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
let documents = res.value.filter(m => {
|
||||||
|
return m.name.toLowerCase() === file.toLowerCase();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!documents || documents.length === 0) {
|
||||||
|
throw `File '${file}' specified on GBasic command not found. Check the .gbdata or the .gbdialog associated.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return documents[0];
|
||||||
|
}
|
||||||
|
}
|
579
packages/saas.gbapp/service/JunoSubscription.ts
Executable file
579
packages/saas.gbapp/service/JunoSubscription.ts
Executable file
|
@ -0,0 +1,579 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { HttpMethods, HttpOperationResponse, ServiceClient, WebResource } from '@azure/ms-rest-js';
|
||||||
|
import { GBLog } from 'botlib';
|
||||||
|
import urlJoin from 'url-join';
|
||||||
|
// tslint:disable-next-line: no-require-imports
|
||||||
|
const Juno = require('juno-payment-node');
|
||||||
|
var FormData = require('form-data');
|
||||||
|
export class JunoSubscription {
|
||||||
|
/**
|
||||||
|
* The host this service will call REST API through VPN.
|
||||||
|
*/
|
||||||
|
public host: string = process.env.SAAS_JUNO_HOST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a HTTP request object to make REST calls.
|
||||||
|
*/
|
||||||
|
private async getAuthorizationToken(): Promise<string> {
|
||||||
|
GBLog.info( `JunoAPI: Getting Auth Token from API...`);
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
|
||||||
|
const req: WebResource = new WebResource();
|
||||||
|
req.method = 'POST';
|
||||||
|
req.url = JunoSubscription.getAuthUrl();
|
||||||
|
req.body = 'grant_type=client_credentials';
|
||||||
|
req.headers.set('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
req.headers.set(
|
||||||
|
'Authorization',
|
||||||
|
'Basic ' +
|
||||||
|
new Buffer(JunoSubscription.getClientId() + ':' + JunoSubscription.getClientSecret()).toString('base64')
|
||||||
|
);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
|
||||||
|
GBLog.info( `JunoAPI: Response from Authorization API ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody.access_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a HTTP request object to make REST calls.
|
||||||
|
*/
|
||||||
|
private async setupWebhook(): Promise<string> {
|
||||||
|
GBLog.info( `JunoAPI: Setting Webhook...`);
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
|
||||||
|
const host = process.env.BOT_URL;
|
||||||
|
const url = `${host}/store.gbapp/payment_notification`;
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
url: '',
|
||||||
|
eventTypes: ['PAYMENT_NOTIFICATION']
|
||||||
|
};
|
||||||
|
|
||||||
|
const req: WebResource = new WebResource();
|
||||||
|
req.method = 'POST';
|
||||||
|
req.url = urlJoin(JunoSubscription.getResourceUrl(), 'notifications', 'webhooks');
|
||||||
|
|
||||||
|
req.body = body;
|
||||||
|
req.headers.set('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
req.headers.set(
|
||||||
|
'Authorization',
|
||||||
|
'Basic ' +
|
||||||
|
new Buffer(JunoSubscription.getClientId() + ':' + JunoSubscription.getClientSecret()).toString('base64')
|
||||||
|
);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
|
||||||
|
GBLog.info( `JunoAPI: Response from Authorization API ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody.access_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a HTTP request object to make REST calls.
|
||||||
|
*/
|
||||||
|
private static createRequestObject(
|
||||||
|
token: string,
|
||||||
|
url: string,
|
||||||
|
verb: HttpMethods,
|
||||||
|
body: string,
|
||||||
|
headers: any,
|
||||||
|
externalAccountToken = undefined
|
||||||
|
): WebResource {
|
||||||
|
const req: WebResource = new WebResource();
|
||||||
|
req.method = verb;
|
||||||
|
req.url = url;
|
||||||
|
|
||||||
|
req.headers.set('Content-Type', 'application/json;charset=UTF-8');
|
||||||
|
req.headers.set('Authorization', `Bearer ${token}`);
|
||||||
|
req.headers.set('X-Api-Version', 2);
|
||||||
|
req.headers.set(
|
||||||
|
'X-Resource-Token',
|
||||||
|
externalAccountToken ? externalAccountToken : JunoSubscription.getJunoPrivateKey()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (headers !== undefined) {
|
||||||
|
// tslint:disable-next-line: typedef
|
||||||
|
headers.forEach(e => {
|
||||||
|
req.headers.set(e.name, e.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
req.body = body;
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async PayByBoleto(
|
||||||
|
name: string,
|
||||||
|
document: string,
|
||||||
|
email: string,
|
||||||
|
phone: string,
|
||||||
|
amount: number
|
||||||
|
): Promise<string> {
|
||||||
|
let charge = await this.createCharge(name, document, email, phone, amount, 'BOLETO');
|
||||||
|
|
||||||
|
return charge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async PayByCC(
|
||||||
|
name: string,
|
||||||
|
document: string,
|
||||||
|
email: string,
|
||||||
|
phone: string,
|
||||||
|
ccNumber: string,
|
||||||
|
ccExpiresOnMonth: string,
|
||||||
|
ccExpiresOnYear: string,
|
||||||
|
ccCode: string,
|
||||||
|
amount: number
|
||||||
|
): Promise<string> {
|
||||||
|
let externalSubscriptionId = '1';
|
||||||
|
|
||||||
|
let charge = await this.createCharge(name, document, email, phone, amount, 'CREDIT_CARD');
|
||||||
|
|
||||||
|
let ccHash = await this.getCardHash(ccNumber, name, ccCode, ccExpiresOnMonth, ccExpiresOnYear);
|
||||||
|
let ccId = await this.getCreditCardId(ccHash);
|
||||||
|
let final = await this.makePayment(ccId, ccHash, charge.Id, email);
|
||||||
|
|
||||||
|
return externalSubscriptionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Get active users available to the workflow process.
|
||||||
|
*/
|
||||||
|
public async createDigitalAccount(
|
||||||
|
name,
|
||||||
|
document,
|
||||||
|
email,
|
||||||
|
birthDate,
|
||||||
|
phone,
|
||||||
|
businessArea,
|
||||||
|
linesOfBusiness,
|
||||||
|
number: string,
|
||||||
|
digit: string,
|
||||||
|
bank: string
|
||||||
|
) {
|
||||||
|
GBLog.info( `JunoAPI: Calling createDigitalAccount API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), 'digital-accounts');
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'POST', '', undefined);
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
type: 'PAYMENT',
|
||||||
|
name: name,
|
||||||
|
document: document,
|
||||||
|
email: email,
|
||||||
|
birthDate: birthDate,
|
||||||
|
phone: phone
|
||||||
|
};
|
||||||
|
|
||||||
|
GBLog.info( `JunoAPI: Response from createDigitalAccount ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async createCharge(name, document, email, phone, amount, paymentType) {
|
||||||
|
GBLog.info( `JunoAPI: Calling createCharge API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), 'charges');
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
charge: {
|
||||||
|
description: 'string',
|
||||||
|
amount: amount,
|
||||||
|
paymentTypes: [paymentType]
|
||||||
|
},
|
||||||
|
billing: {
|
||||||
|
name: name,
|
||||||
|
document: document,
|
||||||
|
email: email,
|
||||||
|
phone: phone,
|
||||||
|
notify: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'POST', JSON.stringify(json), undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from createCharge ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody._embedded.charges[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createPlan(name, amount) {
|
||||||
|
GBLog.info( `JunoAPI: Calling createPlan API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/plans');
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
name: name,
|
||||||
|
amount: amount
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'POST', JSON.stringify(json), undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from createPlan ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async createSubscription(
|
||||||
|
dueDay,
|
||||||
|
planId,
|
||||||
|
description,
|
||||||
|
email,
|
||||||
|
creditCardId,
|
||||||
|
creditCardHash,
|
||||||
|
street,
|
||||||
|
number,
|
||||||
|
city,
|
||||||
|
state,
|
||||||
|
postCode,
|
||||||
|
partnerAccountToken
|
||||||
|
) {
|
||||||
|
GBLog.info( `JunoAPI: Calling createSubscription API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/subscriptions');
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
dueDay: dueDay,
|
||||||
|
planId: planId,
|
||||||
|
chargeDescription: description,
|
||||||
|
creditCardDetails: {
|
||||||
|
creditCardId: creditCardId,
|
||||||
|
creditCardHash: creditCardHash
|
||||||
|
},
|
||||||
|
billing: {
|
||||||
|
email: email,
|
||||||
|
address: {
|
||||||
|
street: street,
|
||||||
|
number: number,
|
||||||
|
city: city,
|
||||||
|
state: state,
|
||||||
|
postCode: postCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (partnerAccountToken) {
|
||||||
|
json['split'] = [
|
||||||
|
{
|
||||||
|
recipientToken: this.getAuthorizationToken(),
|
||||||
|
percentage: 90,
|
||||||
|
amountRemainder: true,
|
||||||
|
chargeFee: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
recipientToken: partnerAccountToken,
|
||||||
|
percentage: 10,
|
||||||
|
amountRemainder: false,
|
||||||
|
chargeFee: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'POST', JSON.stringify(json), undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from createSubscription ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getBusinessAreas() {
|
||||||
|
GBLog.info( `JunoAPI: Calling getBusinessAreas API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/data/business-areas');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from getBusiness ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody._embedded.businessAreas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getBanks() {
|
||||||
|
GBLog.info( `JunoAPI: Calling getBanks API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/data/banks');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from getBanks ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody._embedded.banks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCompanyTypes() {
|
||||||
|
GBLog.info( `JunoAPI: Calling getCompanyTypes API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/data/company-types');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from getCompanyTypes ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody._embedded.banks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getAccountPublicKey(externalAccountToken) {
|
||||||
|
GBLog.info( `JunoAPI: Calling getAccountPublicKey API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/credentials/public-key');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined, externalAccountToken);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from getAccountPublicKey ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.bodyAsText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async listAccountDocuments(externalAccountToken: string) {
|
||||||
|
GBLog.info( `JunoAPI: Calling listAccountDocuments API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/documents');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined, externalAccountToken);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from listAccountDocuments ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody._embedded.documents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getAccountDocumentProperties(externalAccountToken: string, id: string) {
|
||||||
|
GBLog.info( `JunoAPI: Calling getAccountDocumentProperties API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), `/documents/${id}`);
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined, externalAccountToken);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from getAccountDocumentProperties ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendAccountDocument(externalAccountToken: string, id: string, file: string) {
|
||||||
|
GBLog.info( `JunoAPI: Calling sendAccountDocument API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), `/documents/${id}/files`);
|
||||||
|
var form = new FormData();
|
||||||
|
form.append('file', fs.readFileSync(file));
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(
|
||||||
|
token,
|
||||||
|
url,
|
||||||
|
'POST',
|
||||||
|
form.getBuffer(),
|
||||||
|
form.getHeaders(),
|
||||||
|
externalAccountToken
|
||||||
|
);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from sendAccountDocument ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getAccountBalance(externalAccountToken) {
|
||||||
|
GBLog.info( `JunoAPI: Calling getAccountBalance API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/balance');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined, externalAccountToken);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from getAccountBalance ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getAccount(externalAccountToken: string, id: string): Promise<string> {
|
||||||
|
GBLog.info( `JunoAPI: Calling Get Digital Accounts API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/digital-accounts');
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'GET', undefined, undefined, externalAccountToken);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from Get Digital Accounts ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCreditCardId(ccHash: string): Promise<string> {
|
||||||
|
GBLog.info( `JunoAPI: Calling tokenizeCreditCard API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/credit-cards/tokenization');
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
creditCardHash: ccHash
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'POST', JSON.stringify(json), undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from tokenizeCreditCard ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody.creditCardId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async makePayment(ccId, ccHash, chargeId, email): Promise<string> {
|
||||||
|
GBLog.info( `JunoAPI: Calling makePayment API...`);
|
||||||
|
|
||||||
|
let token = await this.getAuthorizationToken();
|
||||||
|
const httpClient = new ServiceClient();
|
||||||
|
const url = urlJoin(JunoSubscription.getResourceUrl(), '/payments');
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
chargeId: chargeId,
|
||||||
|
billing: {
|
||||||
|
email: email
|
||||||
|
// address: {
|
||||||
|
// street: street,
|
||||||
|
// number: number,
|
||||||
|
// complement: complement,
|
||||||
|
// neighborhood: neighborhood,
|
||||||
|
// city: city,
|
||||||
|
// state: state,
|
||||||
|
// postCode: postCode
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
creditCardDetails: {
|
||||||
|
creditCardId: ccId,
|
||||||
|
creditCardHash: ccHash
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = JunoSubscription.createRequestObject(token, url, 'POST', JSON.stringify(json), undefined);
|
||||||
|
|
||||||
|
const res = await httpClient.sendRequest(req);
|
||||||
|
GBLog.info( `JunoAPI: Response from makePayment ${res.bodyAsText}`);
|
||||||
|
|
||||||
|
return res.parsedBody._embedded.charges[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static isProd() {
|
||||||
|
return process.env.SAAS_JUNO_IS_PROD === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getClientId() {
|
||||||
|
return JunoSubscription.isProd() ? process.env.SAAS_JUNO_PROD_CLIENT_ID : process.env.SAAS_JUNO_SANDBOX_CLIENT_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getClientSecret() {
|
||||||
|
return JunoSubscription.isProd()
|
||||||
|
? process.env.SAAS_JUNO_PROD_CLIENT_SECRET
|
||||||
|
: process.env.SAAS_JUNO_SANDBOX_CLIENT_SECRET;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getJunoPublicKey() {
|
||||||
|
return JunoSubscription.isProd() ? process.env.SAAS_JUNO_PROD_PUBLIC_KEY : process.env.SAAS_JUNO_SANDBOX_PUBLIC_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getJunoPrivateKey() {
|
||||||
|
return JunoSubscription.isProd()
|
||||||
|
? process.env.SAAS_JUNO_PROD_PRIVATE_KEY
|
||||||
|
: process.env.SAAS_JUNO_SANDBOX_PRIVATE_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getResourceUrl() {
|
||||||
|
return JunoSubscription.isProd() ? process.env.SAAS_JUNO_PROD_RESOURCE : process.env.SAAS_JUNO_SANDBOX_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getAuthUrl() {
|
||||||
|
return JunoSubscription.isProd() ? process.env.SAAS_JUNO_PROD_AUTH : process.env.SAAS_JUNO_SANDBOX_AUTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getCardHash(
|
||||||
|
ccNumber: string,
|
||||||
|
name: string,
|
||||||
|
ccCode: string,
|
||||||
|
ccExpiresOnMonth: string,
|
||||||
|
ccExpiresOnYear: string
|
||||||
|
): Promise<string> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
let tokenJuno = JunoSubscription.getJunoPublicKey();
|
||||||
|
|
||||||
|
let cardData = {
|
||||||
|
cardNumber: ccNumber,
|
||||||
|
holderName: name,
|
||||||
|
securityCode: ccCode,
|
||||||
|
expirationMonth: ccExpiresOnMonth,
|
||||||
|
expirationYear: ccExpiresOnYear
|
||||||
|
};
|
||||||
|
|
||||||
|
let checkout = new Juno.DirectCheckout(tokenJuno, JunoSubscription.isProd());
|
||||||
|
|
||||||
|
checkout.getCardHash(cardData, resolve, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
136
packages/saas.gbapp/service/MSSubscription.ts
Executable file
136
packages/saas.gbapp/service/MSSubscription.ts
Executable file
|
@ -0,0 +1,136 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
"use strict"
|
||||||
|
|
||||||
|
import { MainService } from "./MainService";
|
||||||
|
const request = require('request-promise-native');
|
||||||
|
|
||||||
|
export class MSSubscriptionService {
|
||||||
|
|
||||||
|
public async handleMSHook(req: any, res: any) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleMSSignUp(req: any, res: any) {
|
||||||
|
let token = req.params.token;
|
||||||
|
let url = `https://marketplaceapi.microsoft.com/api/saas/subscriptions/resolve?api-version=2018-08-31`;
|
||||||
|
let options = {
|
||||||
|
uri: url,
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'x-ms-marketplace-token': token
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let result = await request.get(options);
|
||||||
|
let data = JSON.parse(result);
|
||||||
|
|
||||||
|
const additionalData = {
|
||||||
|
"id": "<guid>", // purchased SaaS subscription ID
|
||||||
|
"subscriptionName": "Contoso Cloud Solution", // SaaS subscription name
|
||||||
|
"offerId": "offer1", // purchased offer ID
|
||||||
|
"planId": "silver", // purchased offer's plan ID
|
||||||
|
"quantity": "20", // number of purchased seats, might be empty if the plan is not per seat
|
||||||
|
"subscription": { // full SaaS subscription details, see Get Subscription APIs response body for full description
|
||||||
|
"id": "<guid>",
|
||||||
|
"publisherId": "contoso",
|
||||||
|
"offerId": "offer1",
|
||||||
|
"name": "Contoso Cloud Solution",
|
||||||
|
"saasSubscriptionStatus": " PendingFulfillmentStart ",
|
||||||
|
"beneficiary": {
|
||||||
|
"emailId": "test@test.com",
|
||||||
|
"objectId": "<guid>",
|
||||||
|
"tenantId": "<guid>",
|
||||||
|
"pid": "<ID of the user>"
|
||||||
|
},
|
||||||
|
"purchaser": {
|
||||||
|
"emailId": "test@test.com",
|
||||||
|
"objectId": "<guid>",
|
||||||
|
"tenantId": "<guid>",
|
||||||
|
"pid": "<ID of the user>"
|
||||||
|
},
|
||||||
|
"planId": "silver",
|
||||||
|
"term": {
|
||||||
|
"termUnit": "P1M",
|
||||||
|
"startDate": "2019 - 05 - 31",
|
||||||
|
"endDate": "2019-06-29",
|
||||||
|
},
|
||||||
|
"isTest": true,
|
||||||
|
"isFreeTrial": false,
|
||||||
|
"allowedCustomerOperations": [
|
||||||
|
"Delete",
|
||||||
|
"Update",
|
||||||
|
"Read"
|
||||||
|
],
|
||||||
|
"sandboxType": "None",
|
||||||
|
"sessionMode": "None"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = new MainService();
|
||||||
|
service.createSubscriptionMSFT("email", "plan", "offer",
|
||||||
|
Number.parseInt(additionalData.quantity), additionalData);
|
||||||
|
|
||||||
|
url = `https://marketplaceapi.microsoft.com/api/saas/subscriptions/${data.id}?api-version=2018-08-31`;
|
||||||
|
options = {
|
||||||
|
uri: url,
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'x-ms-marketplace-token': token
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
result = await request.get(options);
|
||||||
|
data = JSON.parse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async handleMSLanding(req: any, res: any) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Unsubscribe() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public async Suspend() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public async Reinstateou() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public async ChangePlan() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public async ChangeQuantity() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public async Transfer() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
214
packages/saas.gbapp/service/MainService.ts
Executable file
214
packages/saas.gbapp/service/MainService.ts
Executable file
|
@ -0,0 +1,214 @@
|
||||||
|
/*****************************************************************************\
|
||||||
|
| █████ █████ ██ █ █████ █████ ████ ██ ████ █████ █████ ███ ® |
|
||||||
|
| ██ █ ███ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| ██ ███ ████ █ ██ █ ████ █████ ██████ ██ ████ █ █ █ ██ |
|
||||||
|
| ██ ██ █ █ ██ █ █ ██ ██ ██ ██ ██ ██ █ ██ ██ █ █ |
|
||||||
|
| █████ █████ █ ███ █████ ██ ██ ██ ██ █████ ████ █████ █ ███ |
|
||||||
|
| |
|
||||||
|
| General Bots Copyright (c) pragmatismo.cloud. All rights reserved. |
|
||||||
|
| Licensed under the AGPL-3.0. |
|
||||||
|
| |
|
||||||
|
| According to our dual licensing model, this program can be used either |
|
||||||
|
| under the terms of the GNU Affero General Public License, version 3, |
|
||||||
|
| or under a proprietary license. |
|
||||||
|
| |
|
||||||
|
| The texts of the GNU Affero General Public License with an additional |
|
||||||
|
| permission and of our proprietary license can be found at and |
|
||||||
|
| in the LICENSE file you have received along with this program. |
|
||||||
|
| |
|
||||||
|
| This program is distributed in the hope that it will be useful, |
|
||||||
|
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||||
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
|
| GNU Affero General Public License for more details. |
|
||||||
|
| |
|
||||||
|
| "General Bots" is a registered trademark of pragmatismo.cloud. |
|
||||||
|
| The licensing of the program under the AGPLv3 does not imply a |
|
||||||
|
| trademark license. Therefore any rights, title and interest in |
|
||||||
|
| our trademarks remain entirely with us. |
|
||||||
|
| |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { GBOnlineSubscription } from '../model/MainModel.js';
|
||||||
|
import { GBMinInstance, GBLog } from 'botlib';
|
||||||
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
|
import urlJoin from 'url-join';
|
||||||
|
|
||||||
|
export class MainService {
|
||||||
|
async createSubscriptionMSFT(email: string, plan: string, offer: string, quantity: number, additionalData: any) { }
|
||||||
|
|
||||||
|
async createSubscription(
|
||||||
|
min: GBMinInstance,
|
||||||
|
name: string,
|
||||||
|
document: string,
|
||||||
|
email: string,
|
||||||
|
mobile: string,
|
||||||
|
botName: string,
|
||||||
|
ccNumber: string,
|
||||||
|
ccExpiresOnMonth: string,
|
||||||
|
ccExpiresOnYear: string,
|
||||||
|
ccCode: string,
|
||||||
|
templateName: string,
|
||||||
|
free: boolean
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Syncs internal subscription management.
|
||||||
|
|
||||||
|
const status = 'Started';
|
||||||
|
const planId = 'default';
|
||||||
|
const quantity = 1;
|
||||||
|
const amount = 0.52;
|
||||||
|
const language = 'en';
|
||||||
|
|
||||||
|
const subscription = await GBOnlineSubscription.create(<GBOnlineSubscription>{
|
||||||
|
instanceId: min.instance.instanceId,
|
||||||
|
isFreeTrial: free,
|
||||||
|
planId: planId,
|
||||||
|
quantity: quantity,
|
||||||
|
status: status,
|
||||||
|
// TODO: lastCCFourDigits: ccNumber...
|
||||||
|
});
|
||||||
|
|
||||||
|
let externalSubscriptionId = null;
|
||||||
|
let service = min.gbappServices['junoSubscription'];
|
||||||
|
|
||||||
|
if (!free) {
|
||||||
|
// if (ccNumber !== undefined) {
|
||||||
|
// // Performs billing management.
|
||||||
|
|
||||||
|
// externalSubscriptionId = await service.PayByCC(
|
||||||
|
// name,
|
||||||
|
// document,
|
||||||
|
// email,
|
||||||
|
// mobile,
|
||||||
|
// ccNumber,
|
||||||
|
// ccExpiresOnMonth,
|
||||||
|
// ccExpiresOnYear,
|
||||||
|
// ccCode,
|
||||||
|
// amount
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// externalSubscriptionId = await service.PayByBoleto(name, document, email, mobile);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a bot.
|
||||||
|
|
||||||
|
GBLog.info( 'Deploying a blank bot to storage...');
|
||||||
|
|
||||||
|
const instance = await min.deployService.deployBlankBot(botName, mobile, email);
|
||||||
|
|
||||||
|
GBLog.info( 'Creating subscription...');
|
||||||
|
subscription.instanceId = instance.instanceId;
|
||||||
|
subscription.externalSubscriptionId = externalSubscriptionId;
|
||||||
|
await subscription.save();
|
||||||
|
|
||||||
|
let token = await (min.adminService.acquireElevatedToken as any)(min.instance.instanceId, true);
|
||||||
|
|
||||||
|
let siteId = process.env.STORAGE_SITE_ID;
|
||||||
|
let libraryId = process.env.STORAGE_LIBRARY;
|
||||||
|
let gboService = min.gbappServices['gboService'];
|
||||||
|
|
||||||
|
let sleep = ms => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(resolve, ms);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
GBLog.info( 'Creating .gbai folder ...');
|
||||||
|
let item = await gboService.createSubFolderAtRoot(token, `${botName}.gbai`, siteId, libraryId);
|
||||||
|
await sleep(1000);
|
||||||
|
|
||||||
|
GBLog.info( 'Copying Templates...');
|
||||||
|
await gboService.copyTemplates(min, item, 'Shared.gbai', 'gbkb', botName);
|
||||||
|
await gboService.copyTemplates(min, item, 'Shared.gbai', 'gbot', botName);
|
||||||
|
await gboService.copyTemplates(min, item, 'Shared.gbai', 'gbtheme', botName);
|
||||||
|
await gboService.copyTemplates(min, item, 'Shared.gbai', 'gbdialog', botName);
|
||||||
|
await gboService.copyTemplates(min, item, 'Shared.gbai', 'gbdata', botName);
|
||||||
|
await gboService.copyTemplates(min, item, templateName, 'gbkb', botName);
|
||||||
|
await gboService.copyTemplates(min, item, templateName, 'gbot', botName);
|
||||||
|
await gboService.copyTemplates(min, item, templateName, 'gbtheme', botName);
|
||||||
|
await gboService.copyTemplates(min, item, templateName, 'gbdata', botName);
|
||||||
|
await gboService.copyTemplates(min, item, templateName, 'gbdialog', botName);
|
||||||
|
await gboService.copyTemplates(min, item, templateName, 'gbdrive', botName);
|
||||||
|
|
||||||
|
await sleep(10000);
|
||||||
|
GBLog.info( 'Configuring .gbot...');
|
||||||
|
await min.core['setConfig'] (min, instance.botId, "Can Publish", mobile + ";");
|
||||||
|
await min.core['setConfig'](min, instance.botId, "Admin Notify E-mail", email);
|
||||||
|
await min.core['setConfig'](min, instance.botId, 'WebDav Username', instance.botId);
|
||||||
|
await min.core['setConfig'](min, instance.botId, 'WebDav Secret', instance.adminPass);
|
||||||
|
|
||||||
|
GBLog.info( 'Bot creation done.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public async otherTasks(min, botName, webUrl, instance, language){
|
||||||
|
let message = `Seu bot ${botName} está disponível no endereço:
|
||||||
|
<br/><a href="${urlJoin(process.env.BOT_URL, botName)}">${urlJoin(process.env.BOT_URL, botName)}</a>.
|
||||||
|
<br/>
|
||||||
|
<br/>Os pacotes do General Bots (ex: .gbkb, .gbtheme) para seu Bot devem ser editados no repositório de pacotes:
|
||||||
|
<br/>
|
||||||
|
<br/><a href="${webUrl}">${webUrl}</a>.
|
||||||
|
<br/>
|
||||||
|
<br/> Digite /publish do seu WhatsApp para publicar os pacotes. Seu número está autorizado na pasta ${botName}.gbot/Config.xlsx
|
||||||
|
<br/>
|
||||||
|
<br/> Guarde a senha raiz: <b>${instance.adminPass}</b> em um local seguro, use-a para realizar o /publish via Web (WhatsApp dispensa senha).
|
||||||
|
<br/>
|
||||||
|
<br/>O arquivo .zip em anexo pode ser importado no Teams conforme instruções em:
|
||||||
|
<br/><a href="https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/apps-upload">https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/apps-upload</a>.
|
||||||
|
<br/>
|
||||||
|
<br/>Log in to the Teams client with your Microsoft 365 account.
|
||||||
|
<br/>Select Apps and choose Upload a custom app.
|
||||||
|
<br/>Select this .zip file attached to this e-mail. An install dialog displays.
|
||||||
|
<br/>Add your Bot to Teams.
|
||||||
|
<br/>
|
||||||
|
<br/>Atenciosamente,
|
||||||
|
<br/>General Bots Online.
|
||||||
|
<br/><a href="https://gb.pragmatismo.cloud">https://gb.pragmatismo.cloud</a>
|
||||||
|
<br/>
|
||||||
|
<br/>E-mail remetido por Pragmatismo.
|
||||||
|
<br/>`;
|
||||||
|
|
||||||
|
message = await min.conversationalService.translate(
|
||||||
|
min,
|
||||||
|
message,
|
||||||
|
language
|
||||||
|
);
|
||||||
|
|
||||||
|
GBLog.info( 'Generating MS Teams manifest....');
|
||||||
|
|
||||||
|
const appManifest = await min.deployService.getBotManifest(min.instance);
|
||||||
|
|
||||||
|
// GBLog.info( 'Sending e-mails....');
|
||||||
|
// const emailToken = process.env.SAAS_SENDGRID_API_KEY;
|
||||||
|
// gboService.sendEmail(
|
||||||
|
// emailToken,
|
||||||
|
// email,
|
||||||
|
// 'operations@pragmatismo.cloud',
|
||||||
|
// `${botName}`,
|
||||||
|
// message,
|
||||||
|
// message,
|
||||||
|
// {
|
||||||
|
// content: appManifest,
|
||||||
|
// filename: `${min.instance.botId}-Teams.zip`,
|
||||||
|
// type: `application/zip`,
|
||||||
|
// disposition: "attachment"
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
const contacts = process.env.SECURITY_LIST.split(';');
|
||||||
|
|
||||||
|
// TODO: await CollectionUtil.asyncForEach(contacts, async item => {
|
||||||
|
// await (min.whatsAppDirectLine as any)['sendToDevice'](
|
||||||
|
// item,
|
||||||
|
// `Novo bot criado agora: http://gb.pragmatismo.cloud/${botName} para *${name}* (${email}, ${mobile}). Por favor, entre em contato para que mais um bot seja configurado adequadamente. `
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
|
||||||
|
// GBLog.info( 'Sharing .gbai folder...');
|
||||||
|
// await gboService.shareFolder(token, item.parentReference.driveId, item.id, email);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
35
packages/saas.gbapp/strings.ts
Executable file
35
packages/saas.gbapp/strings.ts
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
export const Messages = {
|
||||||
|
'en-US': {
|
||||||
|
bot_created: address => `Your bot has been created and it's available at: ${address}`,
|
||||||
|
new_password: newPassword => `Your new password is: **${newPassword}**.`,
|
||||||
|
ok_get_information: 'OK, I will get some information.',
|
||||||
|
ok_procceding_creation: 'I have all that I need to create your Bot. Wait a moment...',
|
||||||
|
own_voucher:
|
||||||
|
'Got a voucher?',
|
||||||
|
please_use_code: code => `Please, answer the Bot with the code: ${code}.`,
|
||||||
|
validation_enter_valid_botname: 'Please enter a valid Bot Name.',
|
||||||
|
validation_enter_valid_voucher: 'Please enter a valid voucher code.',
|
||||||
|
welcome:
|
||||||
|
"Welcome and let's create your Bot. Also visit: https://gb.pragmatismo.cloud/privacy.html to learn more about our privacy policy.",
|
||||||
|
whats_botname: "What's the Bot name?",
|
||||||
|
thanks_payment: 'Thanks for choosing paying for General Bots.',
|
||||||
|
boleto_mail: 'Boleto will be e-mailed to you.'
|
||||||
|
},
|
||||||
|
'pt-BR': {
|
||||||
|
bot_created: address =>
|
||||||
|
`Em alguns minutos seu Bot estará disponível no endereço: ${address}. Você receberá por e-mail, a notificação da criação. Entraremos em contato em até 1(um) dia útil para realizar a configuração final.`,
|
||||||
|
new_password: newPassword => `Sua nova senha é: **${newPassword}**.`,
|
||||||
|
ok_get_information: 'OK, vou solicitar algumas informações.',
|
||||||
|
ok_procceding_creation: 'Tenho tudo que preciso para criar seu Bot, só um instante...',
|
||||||
|
own_voucher: 'Tem um voucher algo como GB2020 ou não?',
|
||||||
|
please_use_code: code => `Por favor, responda ao bot com o código: ${code}.`,
|
||||||
|
validation_enter_valid_botname:
|
||||||
|
'Por favor, digite um nome de Bot válido, usando apenas letras maiúsculas e minúsculas sem espaços ou outros caracteres.',
|
||||||
|
validation_enter_valid_voucher: 'Por favor, digite um código de voucher válido.',
|
||||||
|
welcome:
|
||||||
|
'Bem-vinda(o) e vamos criar seu bot. Visite também: https://gb.pragmatismo.cloud/privacy.html para conhecer nossa política de privacidade',
|
||||||
|
whats_botname: 'Qual é o nome do *Bot*? (Apenas letras maiúsculas e minúsculas, sem espaços ou demais caracteres)',
|
||||||
|
thanks_payment: 'Gratidão por escolher o plano pago do General Bots.',
|
||||||
|
boleto_mail: 'Boleto será enviado por e-mail.'
|
||||||
|
}
|
||||||
|
};
|
20
packages/saas.gbapp/test/subscription.ts
Normal file
20
packages/saas.gbapp/test/subscription.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// TODO: TEST.
|
||||||
|
|
||||||
|
// const service = new MainService();
|
||||||
|
// await service.createSubscription(
|
||||||
|
// min,
|
||||||
|
// 'Test',
|
||||||
|
// '999999999999',
|
||||||
|
// '@domain.cloud',
|
||||||
|
// '9999999999999',
|
||||||
|
// 'bot'+min.adminService['getRndReadableIdentifier'](),
|
||||||
|
// null,
|
||||||
|
// '11',
|
||||||
|
// '22',
|
||||||
|
// '333',
|
||||||
|
// 'Starter.gbai',
|
||||||
|
// true
|
||||||
|
// );
|
||||||
|
// step.endDialog();
|
||||||
|
// return;
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
TALK “Olá! “ + username + “! Bem vinda(o)!”
|
|
||||||
|
|
||||||
BEGIN SYSTEM PROMPT
|
|
||||||
|
|
||||||
If someone asks about my technology, I'm an AI virtual assistant powered by the General Bots LLM.
|
|
||||||
Always answer at the end, saying that your are available, say it each time differently with each response.
|
|
||||||
|
|
||||||
END SYSTEM PROMPT
|
|
|
@ -1,5 +1,4 @@
|
||||||
PARAM image
|
PARAM image AS STRING LIKE "https://server/image"
|
||||||
DESCRIPTION Returns the description of the image that was sent with the previous user message. This tool is automatically invoked if a user uploads an image.
|
DESCRIPTION Returns the description of the image that was sent with the previous user message. This tool is automatically invoked if a user uploads an image.
|
||||||
|
|
||||||
|
DEBUG "Hello"
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
|
PARAM prompt as STRING LIKE "Generate a cat."
|
||||||
PARAM prompt
|
|
||||||
DESCRIPTION Calls an artificial intelligence model to create an image. `prompt` parameter is a text description of the desired image.
|
DESCRIPTION Calls an artificial intelligence model to create an image. `prompt` parameter is a text description of the desired image.
|
||||||
|
FIND
|
||||||
|
RETURN "https://"
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
PARAM query
|
PARAM query AS STRING LIKE "How is to code?"
|
||||||
DESCRIPTION Returns search results in a JSON string. `query` parameter is a well-formed web search query.- `search_web(query: str) -> str` returns Bing search results in a JSON string. `query` parameter is a well-formed web search query.
|
DESCRIPTION Returns search results in a JSON string. `query` parameter is a well-formed web search query.- `search_web(query: str) -> str` returns Bing search results in a JSON string. `query` parameter is a well-formed web search query.
|
||||||
|
|
||||||
|
DEBUG "{}"
|
6
templates/llm-tools.gbai/llm-tools.gbdata/products.csv
Normal file
6
templates/llm-tools.gbai/llm-tools.gbdata/products.csv
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
name,price
|
||||||
|
fax, 500
|
||||||
|
tv, 1200
|
||||||
|
mobile,200
|
||||||
|
console, 250
|
||||||
|
chocolate, 30
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
PARAM product AS string LIKE fax DESCRIPTION "Required name of the item you want to inquire about."
|
||||||
|
DESCRIPTION "Returns the price of the specified product name."
|
||||||
|
|
||||||
|
price = -1
|
||||||
|
productRecord = FIND "products.csv", "name = ${product}"
|
||||||
|
IF (productRecord) THEN
|
||||||
|
price = productRecord.price
|
||||||
|
END IF
|
||||||
|
RETURN price
|
9
templates/llm-tools.gbai/llm-tools.gbdialog/start.bas
Normal file
9
templates/llm-tools.gbai/llm-tools.gbdialog/start.bas
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
BEGIN SYSTEM PROMPT
|
||||||
|
|
||||||
|
There exist some helpful predefined internal tools which can help me by
|
||||||
|
extending my functionalities or get me helpful information.
|
||||||
|
These tools **should** be abstracted away from the user.
|
||||||
|
These tools can be invoked only by me before I respond to a user.
|
||||||
|
If get price tool return value of -1, says there is no such product.
|
||||||
|
|
||||||
|
END SYSTEM PROMPT
|
3
templates/llm-tools.gbai/llm-tools.gbot/config.csv
Normal file
3
templates/llm-tools.gbai/llm-tools.gbot/config.csv
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
name,value
|
||||||
|
Answer Mode,tool
|
||||||
|
Start Dialog,start
|
|
|
@ -5,7 +5,7 @@ pass = "*************"
|
||||||
o = get "https://oooooooooo"
|
o = get "https://oooooooooo"
|
||||||
|
|
||||||
# Criar a legenda para o post
|
# Criar a legenda para o post
|
||||||
caption = REWRITE "Crie um post sobre Hotmart e seus produtos, no estilo dica do dia, incluindo 10 hashtags, estilo Instagram o texto! Importante, retorne só a saída de texto pronta"
|
caption = REWRITE "Crie um post sobre produtos, no estilo dica do dia, incluindo 10 hashtags, estilo Instagram o texto! Importante, retorne só a saída de texto pronta"
|
||||||
|
|
||||||
# Obter uma imagem relacionada ao conteúdo
|
# Obter uma imagem relacionada ao conteúdo
|
||||||
image = GET IMAGE caption
|
image = GET IMAGE caption
|
||||||
|
|
1
templates/whatsapp.gbai/whatsapp.gbot/config.csv
Normal file
1
templates/whatsapp.gbai/whatsapp.gbot/config.csv
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Meta Challenge,
|
|
Loading…
Add table
Reference in a new issue