new(basic.gblib): SEND FILE pdf as temporary images.
This commit is contained in:
parent
53e0558593
commit
7013d168df
9 changed files with 137 additions and 74 deletions
|
@ -37,7 +37,7 @@ import urlJoin from 'url-join';
|
|||
import { GBServer } from '../../../src/app.js';
|
||||
import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js';
|
||||
import { SecService } from '../../security.gbapp/services/SecService.js';
|
||||
import {Jimp} from 'jimp';
|
||||
import { Jimp } from 'jimp';
|
||||
import jsQR from 'jsqr';
|
||||
import { SystemKeywords } from './SystemKeywords.js';
|
||||
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
||||
|
@ -254,28 +254,28 @@ export class DialogKeywords {
|
|||
*
|
||||
* @example EXIT
|
||||
*/
|
||||
public async exit({}) {}
|
||||
public async exit({ }) { }
|
||||
|
||||
/**
|
||||
* Get active tasks.
|
||||
*
|
||||
* @example list = ACTIVE TASKS
|
||||
*/
|
||||
public async getActiveTasks({ pid }) {}
|
||||
public async getActiveTasks({ pid }) { }
|
||||
|
||||
/**
|
||||
* Creates a new deal.
|
||||
*
|
||||
* @example CREATE DEAL dealname,contato,empresa,amount
|
||||
*/
|
||||
public async createDeal({ pid, dealName, contact, company, amount }) {}
|
||||
public async createDeal({ pid, dealName, contact, company, amount }) { }
|
||||
|
||||
/**
|
||||
* Finds contacts in XRM.
|
||||
*
|
||||
* @example list = FIND CONTACT "Sandra"
|
||||
*/
|
||||
public async fndContact({ pid, name }) {}
|
||||
public async fndContact({ pid, name }) { }
|
||||
|
||||
public getContentLocaleWithCulture(contentLocale) {
|
||||
switch (contentLocale) {
|
||||
|
@ -936,7 +936,7 @@ export class DialogKeywords {
|
|||
* @example MENU
|
||||
*
|
||||
*/
|
||||
public async showMenu({}) {
|
||||
public async showMenu({ }) {
|
||||
// https://github.com/GeneralBots/BotServer/issues/237
|
||||
// return await beginDialog('/menu');
|
||||
}
|
||||
|
@ -1215,20 +1215,20 @@ export class DialogKeywords {
|
|||
const handle = WebAutomationServices.cyrb53({ pid, str: min.botId + answer.filename });
|
||||
GBServer.globals.files[handle] = answer;
|
||||
|
||||
// Load the image with Jimp
|
||||
const image = await Jimp.read(answer.data);
|
||||
// Load the image with Jimp
|
||||
const image = await Jimp.read(answer.data);
|
||||
|
||||
// Get the image data
|
||||
const imageData = {
|
||||
data: new Uint8ClampedArray(image.bitmap.data),
|
||||
width: image.bitmap.width,
|
||||
height: image.bitmap.height,
|
||||
};
|
||||
// Get the image data
|
||||
const imageData = {
|
||||
data: new Uint8ClampedArray(image.bitmap.data),
|
||||
width: image.bitmap.width,
|
||||
height: image.bitmap.height,
|
||||
};
|
||||
|
||||
// Use jsQR to decode the QR code
|
||||
const decodedQR = jsQR(imageData.data, imageData.width, imageData.height);
|
||||
// Use jsQR to decode the QR code
|
||||
const decodedQR = jsQR(imageData.data, imageData.width, imageData.height);
|
||||
|
||||
result = decodedQR.data;
|
||||
result = decodedQR.data;
|
||||
|
||||
} else if (kind === 'zipcode') {
|
||||
const extractEntity = (text: string) => {
|
||||
|
@ -1455,6 +1455,36 @@ export class DialogKeywords {
|
|||
let nameOnly;
|
||||
const gbaiName = GBUtil.getGBAIPath(min.botId);
|
||||
|
||||
if (filename.endsWith('.pdf')) {
|
||||
const gbdriveName = GBUtil.getGBAIPath(min.botId, 'gbdrive');
|
||||
const pdf = path.join(GBConfigService.get('STORAGE_LIBRARY'), gbdriveName, filename);
|
||||
|
||||
const pngs = await GBUtil.pdfPageAsImage(min, pdf, undefined);
|
||||
|
||||
await CollectionUtil.asyncForEach(pngs, async png => {
|
||||
|
||||
|
||||
// Prepare a cache to be referenced by Bot Framework.
|
||||
|
||||
url = urlJoin(GBServer.globals.publicAddress, min.botId, 'cache', path.basename(png.localName));
|
||||
|
||||
const contentType = mime.lookup(url);
|
||||
const reply = { type: ActivityTypes.Message, text: caption };
|
||||
reply['attachments'] = [];
|
||||
reply['attachments'].push({
|
||||
name: nameOnly,
|
||||
contentType: contentType,
|
||||
contentUrl: url
|
||||
});
|
||||
|
||||
if (channel === 'omnichannel' || !user) {
|
||||
await min.conversationalService.sendFile(min, null, mobile, url, caption);
|
||||
} else {
|
||||
await min.conversationalService['sendOnConversation'](min, user, reply);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Web automation.
|
||||
|
||||
if (element) {
|
||||
|
@ -1489,32 +1519,37 @@ export class DialogKeywords {
|
|||
|
||||
// .gbdrive direct sending.
|
||||
else {
|
||||
const ext = path.extname(filename);
|
||||
const gbaiName = GBUtil.getGBAIPath(min.botId);
|
||||
|
||||
let { baseUrl, client } = await GBDeployer.internalGetDriveClient(min);
|
||||
const fileUrl = urlJoin('/', gbaiName, `${min.botId}.gbdrive`, filename);
|
||||
GBLogEx.info(min, `Direct send from .gbdrive: ${fileUrl} to ${mobile}.`);
|
||||
|
||||
const sys = new SystemKeywords();
|
||||
if (GBConfigService.get('STORAGE_NAME')) {
|
||||
|
||||
const pathOnly = fileUrl.substring(0, fileUrl.lastIndexOf('/'));
|
||||
const fileOnly = fileUrl.substring(fileUrl.lastIndexOf('/') + 1);
|
||||
const ext = path.extname(filename);
|
||||
const gbaiName = GBUtil.getGBAIPath(min.botId);
|
||||
|
||||
let template = await sys.internalGetDocument(client, baseUrl, pathOnly, fileOnly);
|
||||
let { baseUrl, client } = await GBDeployer.internalGetDriveClient(min);
|
||||
const fileUrl = urlJoin('/', gbaiName, `${min.botId}.gbdrive`, filename);
|
||||
GBLogEx.info(min, `Direct send from .gbdrive: ${fileUrl} to ${mobile}.`);
|
||||
|
||||
const driveUrl = template['@microsoft.graph.downloadUrl'];
|
||||
const res = await fetch(driveUrl);
|
||||
let buf: any = Buffer.from(await res.arrayBuffer());
|
||||
let localName1 = path.join(
|
||||
'work',
|
||||
gbaiName,
|
||||
'cache',
|
||||
`${fileOnly.replace(/\s/gi, '')}-${GBAdminService.getNumberIdentifier()}.${ext}`
|
||||
);
|
||||
await fs.writeFile(localName1, buf, { encoding: null });
|
||||
const sys = new SystemKeywords();
|
||||
|
||||
url = urlJoin(GBServer.globals.publicAddress, min.botId, 'cache', path.basename(localName1));
|
||||
const pathOnly = fileUrl.substring(0, fileUrl.lastIndexOf('/'));
|
||||
const fileOnly = fileUrl.substring(fileUrl.lastIndexOf('/') + 1);
|
||||
|
||||
let template = await sys.internalGetDocument(client, baseUrl, pathOnly, fileOnly);
|
||||
|
||||
const driveUrl = template['@microsoft.graph.downloadUrl'];
|
||||
const res = await fetch(driveUrl);
|
||||
let buf: any = Buffer.from(await res.arrayBuffer());
|
||||
let localName1 = path.join(
|
||||
'work',
|
||||
gbaiName,
|
||||
'cache',
|
||||
`${fileOnly.replace(/\s/gi, '')}-${GBAdminService.getNumberIdentifier()}.${ext}`
|
||||
);
|
||||
await fs.writeFile(localName1, buf, { encoding: null });
|
||||
|
||||
url = urlJoin(GBServer.globals.publicAddress, min.botId, 'cache', path.basename(localName1));
|
||||
}
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
|
|
|
@ -775,14 +775,14 @@ export class KeywordsExpressions {
|
|||
// Handles the GET http version.
|
||||
else {
|
||||
|
||||
const value = $2.replace(/\`/gi, '');
|
||||
return `
|
||||
|
||||
if (value.endsWith('.pdf') && !value.startsWith('https')) {
|
||||
return `${$1} = await sys.getPdf({pid: pid, file: ${$2}});`;
|
||||
if (${$2}.endsWith('.pdf') && !${$2}.startsWith('https')) {
|
||||
${$1} = await sys.getPdf({pid: pid, file: ${$2}});
|
||||
} else {
|
||||
return `
|
||||
|
||||
let __${$1} = null
|
||||
await retry(
|
||||
await retry(
|
||||
|
||||
async (bail) => {
|
||||
await ensureTokens();
|
||||
|
@ -790,11 +790,10 @@ export class KeywordsExpressions {
|
|||
},{ retries: 5});
|
||||
|
||||
${$1} = __${$1}
|
||||
__${$1} = null
|
||||
|
||||
__${$1} = null
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
@ -952,7 +952,7 @@ export class SystemKeywords {
|
|||
GBLogEx.info(min, `GET '${addressOrHeaders}' in '${file}'.`);
|
||||
let { baseUrl, client } = await GBDeployer.internalGetDriveClient(min);
|
||||
const botId = min.instance.botId;
|
||||
('');
|
||||
|
||||
const packagePath = GBUtil.getGBAIPath(botId, 'gbdata');
|
||||
|
||||
let document = await this.internalGetDocument(client, baseUrl, packagePath, file);
|
||||
|
|
|
@ -149,8 +149,8 @@ export class GBLLMOutputParser extends BaseLLMOutputParser<ExpectedOutput> {
|
|||
const localName = path.join(process.env.PWD, 'work', gbaiName, 'docs', source.file);
|
||||
|
||||
if (localName) {
|
||||
const { url } = await ChatServices.pdfPageAsImage(this.min, localName, source.page);
|
||||
text = `
|
||||
const pngs = await GBUtil.pdfPageAsImage(this.min, localName, source.page);
|
||||
text = `
|
||||
${text}`;
|
||||
found = true;
|
||||
source.file = localName;
|
||||
|
@ -167,30 +167,7 @@ export class GBLLMOutputParser extends BaseLLMOutputParser<ExpectedOutput> {
|
|||
}
|
||||
|
||||
export class ChatServices {
|
||||
public static async pdfPageAsImage(min, filename, pageNumber) {
|
||||
// Converts the PDF to PNG.
|
||||
|
||||
GBLogEx.info(min, `Converting ${filename}, page: ${pageNumber}...`);
|
||||
const pngPages: PngPageOutput[] = await pdfToPng(filename, {
|
||||
disableFontFace: true,
|
||||
useSystemFonts: true,
|
||||
viewportScale: 2.0,
|
||||
pagesToProcess: [pageNumber],
|
||||
strictPagesToProcess: false,
|
||||
verbosityLevel: 0
|
||||
});
|
||||
|
||||
// Prepare an image on cache and return the GBFILE information.
|
||||
|
||||
if (pngPages.length > 0) {
|
||||
const buffer = pngPages[0].content;
|
||||
const gbaiName = GBUtil.getGBAIPath(min.botId, null);
|
||||
const localName = path.join('work', gbaiName, 'cache', `img${GBAdminService.getRndReadableIdentifier()}.png`);
|
||||
const url = urlJoin(GBServer.globals.publicAddress, min.botId, 'cache', path.basename(localName));
|
||||
await fs.writeFile(localName, buffer, { encoding: null });
|
||||
return { localName: localName, url: url, data: buffer };
|
||||
}
|
||||
}
|
||||
|
||||
private static async getRelevantContext(
|
||||
vectorStore: HNSWLib,
|
||||
|
|
39
src/util.ts
39
src/util.ts
|
@ -42,8 +42,12 @@ import { VerbosityLevel, getDocument } from 'pdfjs-dist/legacy/build/pdf.mjs';
|
|||
VerbosityLevel.ERRORS = 0;
|
||||
VerbosityLevel.WARNINGS = 0;
|
||||
VerbosityLevel.INFOS = 0;
|
||||
import { Page } from 'puppeteer';
|
||||
import urljoin from 'url-join';
|
||||
import { GBAdminService } from '../packages/admin.gbapp/services/GBAdminService.js';
|
||||
import { GBLogEx } from '../packages/core.gbapp/services/GBLogEx.js';
|
||||
import { PngPageOutput, pdfToPng } from 'pdf-to-png-converter';
|
||||
import urlJoin from 'url-join';
|
||||
import { GBServer } from './app.js';
|
||||
|
||||
export class GBUtil {
|
||||
public static repeat(chr, count) {
|
||||
|
@ -244,4 +248,37 @@ export class GBUtil {
|
|||
return urljoin(gbai, packageName ? packageName : `${botId}.${packageType}`);
|
||||
}
|
||||
}
|
||||
|
||||
public static async pdfPageAsImage(min, filename, pageNumber) {
|
||||
// Converts the PDF to PNG.
|
||||
|
||||
GBLogEx.info(min, `Converting ${filename}, page: ${pageNumber ?? 'all'}...`);
|
||||
|
||||
const options = {
|
||||
disableFontFace: true,
|
||||
useSystemFonts: true,
|
||||
viewportScale: 2.0,
|
||||
pagesToProcess: pageNumber !== undefined ? [pageNumber] : undefined,
|
||||
strictPagesToProcess: false,
|
||||
verbosityLevel: 0
|
||||
};
|
||||
|
||||
const pngPages: PngPageOutput[] = await pdfToPng(filename, options);
|
||||
|
||||
const generatedFiles = [];
|
||||
|
||||
for (const pngPage of pngPages) {
|
||||
const buffer = pngPage.content;
|
||||
const gbaiName = GBUtil.getGBAIPath(min.botId, null);
|
||||
const localName = path.join('work', gbaiName, 'cache', `img${GBAdminService.getRndReadableIdentifier()}.png`);
|
||||
const url = urlJoin(GBServer.globals.publicAddress, min.botId, 'cache', path.basename(localName));
|
||||
|
||||
await fs.writeFile(localName, buffer, { encoding: null });
|
||||
|
||||
generatedFiles.push({ localName: localName, url: url, data: buffer });
|
||||
}
|
||||
|
||||
return generatedFiles.length > 0 ? generatedFiles : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
TALK "Please, take a photo of the QR Code and send to me."
|
||||
HEAR doc as QRCODE
|
||||
text = GET "doc-" + doc + ".pdf"
|
||||
TALK "Reading document " + doc + "..."
|
||||
text = GET doc
|
||||
|
||||
IF text THEN
|
||||
|
||||
|
@ -8,7 +9,10 @@ IF text THEN
|
|||
SET CONTEXT text
|
||||
SET ANSWER MODE "document"
|
||||
TALK "Document ${doc} loaded. You can ask me anything about it."
|
||||
TALK "I will also send it to you..."
|
||||
SEND FILE doc
|
||||
|
||||
ELSE
|
||||
TALK "Document was not found, please try again."
|
||||
END IF
|
||||
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
BEGIN TALK
|
||||
Welcome to the General Bots AI Search Template!
|
||||
|
||||
We are here to assist you! To get started, please choose one of the options below:
|
||||
|
||||
1 - Scan a QR Code: Send a photo of the QR Code you would like to scan typping 'QR'.
|
||||
|
||||
2 - Find a Procedure: If you need information about a specific procedure, just let me know what it is, and I will help you!
|
||||
|
||||
Let’s get started!
|
||||
END TALK
|
||||
|
||||
BEGIN SYSTEM PROMPT
|
||||
|
||||
|
|
BIN
templates/ai-search.gbai/ai-search.gbdrive/42LB5800.pdf
Normal file
BIN
templates/ai-search.gbai/ai-search.gbdrive/42LB5800.pdf
Normal file
Binary file not shown.
Binary file not shown.
Loading…
Add table
Reference in a new issue