new(basic.gblib): AS IMAGE, AS PDF, SET THEME and SQL new keywords.

This commit is contained in:
Rodrigo Rodriguez 2022-06-04 17:02:34 -03:00
parent 4125c510ca
commit 0e367f1a7f
7 changed files with 880 additions and 26 deletions

726
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -61,6 +61,7 @@
"@types/validator": "13.1.4",
"adal-node": "0.2.2",
"adm-zip": "0.5.6",
"alasql": "^1.7.3",
"any-shell-escape": "0.1.1",
"async-promises": "0.2.3",
"azure-arm-cognitiveservices": "3.0.0",
@ -102,6 +103,7 @@
"npm": "7.21.0",
"opn": "6.0.0",
"pdf-extraction": "1.0.2",
"pdfkit": "^0.13.0",
"phone": "2.4.21",
"pragmatismo-io-framework": "1.0.20",
"prism-media": "1.3.1",
@ -123,6 +125,7 @@
"ssr-for-bots": "1.0.1-c",
"strict-password-generator": "1.1.2",
"swagger-client": "2.1.18",
"tabulator-tables": "^5.2.6",
"tedious": "14.0.0",
"textract": "2.5.0",
"typescript": "3.6.4",

View file

@ -138,8 +138,6 @@ export class HearDialog {
const promises = step.context.activity.attachments.map(HearDialog.downloadAttachmentAndWrite);
const successfulSaves = await Promise.all(promises);
// Replies back to the user with information about where the attachment is stored on the bot's server,
// and what the name of the saved file is.
async function replyForReceivedAttachments(localAttachmentData) {
if (localAttachmentData) {
// Because the TurnContext was bound to this function, the bot can call

View file

@ -595,6 +595,19 @@ export class DialogKeywords {
this.user = user;
}
/**
* Defines the theme for assets generation.
*
* @example SET THEME "themename"
*
*/
public async setTheme(step, theme) {
const user = await this.min.userProfile.get(step.context, {});
user.basicOptions.theme = theme.trim();
await this.min.userProfile.set(step.context, user);
this.user = user;
}
/**
* Defines translator behaviour.
*
@ -789,13 +802,7 @@ export class DialogKeywords {
const url = urlJoin(
GBServer.globals.publicAddress,
'kb',
`${this.min.botId}.gbai`,
`${this.min.botId}.gbkb`,
'assets',
filename
);
await this.min.conversationalService.sendFile(this.min, step, mobile, url, caption);
`${this.min.botId}.gbaiurlonalService.sendFile(this.min, step, mobile, url, caption);
}
}
}

View file

@ -193,6 +193,14 @@ export class GBVMService extends GBService {
// Keywords from General Bots BASIC.
code = code.replace(/(\w+)\s*\=\s*SELECT\s*(.*)/gi, ($0, $1, $2) => {
let tableName = /\sFROM\s(\w+)/.exec($1)[0];
return `sys().executeSQL(${$2}, ${$1}, ${tableName})\n`;
});
code = code.replace(/(\w+)\s*\=\s*get html\s*(.*)/gi, ($0, $1, $2, $3) => {
return `${$1} = getPage(step, ${$2})\n`;
});
@ -251,7 +259,6 @@ export class GBVMService extends GBService {
return `${$1} = hear("menu", ${$2})`;
});
code = code.replace(/(hear)\s*(\w+)/gi, ($0, $1, $2) => {
return `${$2} = hear()`;
});
@ -374,6 +381,10 @@ export class GBVMService extends GBService {
return `setTranslatorOn (step, "${$3.toLowerCase()}")\n`;
});
code = code.replace(/(set theme)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `setTheme (step, "${$3.toLowerCase()}")\n`;
});
code = code.replace(/(set whole word)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `setWholeWord (step, "${$3.toLowerCase()}")\n`;
});
@ -442,6 +453,10 @@ export class GBVMService extends GBService {
return `sys().convert(${$3})\n`;
});
code = code.replace(/(\w+)\s*\=\s*(.*)\s*as image/gi, ($0, $1, $2) => {
return `sys().asImage(${$2}, ${$1})\n`;
});
code = code.replace(/save\s(.*)\sas\s(.*)/gi, ($0, $1, $2, $3) => {
return `sys().saveFile(${$2}, ${$1})\n`;
});
@ -645,6 +660,10 @@ export class GBVMService extends GBService {
code = code.replace(/("[^"]*"|'[^']*')|\bsetTranslatorOn\b/gi, ($0, $1) => {
return $1 === undefined ? 'this.setTranslatorOn' : $1;
});
code = code.replace(/("[^"]*"|'[^']*')|\bsetTheme\b/gi, ($0, $1) => {
return $1 === undefined ? 'this.setTheme' : $1;
});
code = code.replace(/("[^"]*"|'[^']*')|\bsetWholeWord\b/gi, ($0, $1) => {
return $1 === undefined ? 'this.setWholeWord' : $1;
});

View file

@ -34,15 +34,20 @@ import { GBDialogStep, GBLog, GBMinInstance } from 'botlib';
import { GBConfigService } from '../../core.gbapp/services/GBConfigService';
import { CollectionUtil } from 'pragmatismo-io-framework';
import * as request from 'request-promise-native';
const urlJoin = require('url-join');
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
import { GBDeployer } from '../../core.gbapp/services/GBDeployer';
import { DialogKeywords } from './DialogKeywords';
const path = require('path');
import { Tabulator } from 'tabulator-tables';
import { GBServer } from '../../../src/app';
const urlJoin = require('url-join');
const puppeteer = require('puppeteer')
const Path = require('path');
const sgMail = require('@sendgrid/mail');
const ComputerVisionClient = require('@azure/cognitiveservices-computervision').ComputerVisionClient;
const ApiKeyCredentials = require('@azure/ms-rest-js').ApiKeyCredentials;
const alasql = require('alasql');
/**
* @fileoverview General Bots server core.
@ -127,9 +132,9 @@ export class SystemKeywords {
for (let i = 0; i < result.regions.length; i++) {
const region = result.regions[i];
for (let j = 0; j < region.lines.length; j++) {
for (let j = 0; j < region.lines.length; j++) {
const line = region.lines[j];
for (let k = 0; k < line.words.length; k++) {
final += `${line.words[k].text} `;
}
@ -172,6 +177,115 @@ export class SystemKeywords {
}
}
/**
*
* @param data
* @param renderPDF
* @param renderImage
* @returns
*
* @see http://tabulator.info/examples/5.2
* @see puppeteer.
*/
private async renderTable(data, renderPDF, renderImage) {
const gbaiName = `${this.min.botId}.gbai`;
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
// Includes the associated CSS related to current theme.
const theme = this.dk.user.basicOptions.theme;
switch (theme) {
case "white":
await page.addStyleTag({ path: 'node_modules/tabulator-tables/dist/css/tabulator_simple.min.css' })
break;
case "dark":
await page.addStyleTag({ path: 'node_modules/tabulator-tables/dist/css/tabulator_midnight.min.css' })
break;
case "blue":
await page.addStyleTag({ path: 'node_modules/tabulator-tables/dist/css/tabulator_modern.min.css' })
break;
default:
break;
}
let fields = [];
for (let i = 0; i < data.length; i++) {
fields.push({field:data[i]});
}
await page.evaluate(() => {
const el = document.createElement("div");
el.id = "table";
document.body.prepend(el);
});
await page.evaluate(`
new Tabulator("#example-table", {
height:"311px",
data: ${JSON.stringify(data)},
columns:[ ${JSON.stringify(fields)}]
});
`);
let url;
let localName;
if (renderImage) {
localName = Path.join('work', gbaiName, 'cache', `img${GBAdminService.getRndReadableIdentifier()}.png`);
await page.screenshot({ path: localName });
url = urlJoin(
GBServer.globals.publicAddress,
this.min.botId,
'cache',
Path.basename(localName)
);
GBLog.info(`BASIC: Table image generated at ${url} .`);
}
if (renderPDF) {
localName = Path.join('work', gbaiName, 'cache', `img${GBAdminService.getRndReadableIdentifier()}.pdf`);
url = urlJoin(
GBServer.globals.publicAddress,
this.min.botId,
'cache',
Path.basename(localName)
);
let pdf = await page.pdf({ format: 'A4' });
GBLog.info(`BASIC: Table PDF generated at ${url} .`);
}
await browser.close();
return [url, localName];
}
public async asPDF(data, filename) {
let file = await this.renderTable(data, true, false);
return file['url'];
}
public async asImage(data, filename) {
let file = await this.renderTable(data, false, true);
return file['url'];
}
public async executeSQL(data, sql, tableName) {
sql = `SELECT ${sql}`.replaceAll(tableName, '?');
return alasql(sql, [data]);
}
/**
* Retrives the content of a given URL.
*/
@ -250,14 +364,13 @@ export class SystemKeywords {
*
*/
public async set(file: any, address: string, value: any): Promise<any> {
// Handles calls for HTML stuff
if (file._javascriptEnabled)
{
if (file._javascriptEnabled) {
GBLog.info(`BASIC: Web automation setting ${file}' to '${value}' (SET). `);
await this.dk.type(null, file, address, value );
await this.dk.type(null, file, address, value);
return;
}

View file

@ -888,7 +888,7 @@ export class GBMinService {
user.subjects = [];
user.cb = undefined;
user.welcomed = false;
user.basicOptions = { maxLines: 100, translatorOn: true, wholeWord: true };
user.basicOptions = { maxLines: 100, translatorOn: true, wholeWord: true, theme: "white" };
firstTime = true;