From 3ad0d8ecf5ccb178a1f110f72cb92436c86e3007 Mon Sep 17 00:00:00 2001 From: Rodrigo Rodriguez Date: Sat, 14 Sep 2024 10:45:54 -0300 Subject: [PATCH] fix (templates): llm-server almost OK. --- directline-3.0.json => directline-v2.json | 0 .../basic.gblib/services/DialogKeywords.ts | 27 ++-- packages/core.gbapp/services/router/bridge.ts | 12 +- src/util.ts | 118 +++++++++--------- 4 files changed, 74 insertions(+), 83 deletions(-) rename directline-3.0.json => directline-v2.json (100%) diff --git a/directline-3.0.json b/directline-v2.json similarity index 100% rename from directline-3.0.json rename to directline-v2.json diff --git a/packages/basic.gblib/services/DialogKeywords.ts b/packages/basic.gblib/services/DialogKeywords.ts index 9a3b16e95..b396370d8 100644 --- a/packages/basic.gblib/services/DialogKeywords.ts +++ b/packages/basic.gblib/services/DialogKeywords.ts @@ -42,7 +42,7 @@ import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js'; import { Messages } from '../strings.js'; import { CollectionUtil } from 'pragmatismo-io-framework'; import { GBConversationalService } from '../../core.gbapp/services/GBConversationalService.js'; -import fs from 'fs/promises'; +import fs from 'fs/promises'; import libphonenumber from 'google-libphonenumber'; import * as df from 'date-diff'; import tesseract from 'node-tesseract-ocr'; @@ -66,7 +66,7 @@ import puppeteer from 'puppeteer'; * Default check interval for user replay */ const DEFAULT_HEAR_POLL_INTERVAL = 500; -const API_RETRIES = 120; +const POOLING_COUNT = 120; /** * Base services of conversation to be called by BASIC. @@ -1314,11 +1314,9 @@ export class DialogKeywords { GBLogEx.info(min, `MESSAGE BOT: ${text}.`); const { conversation, client } = min['apiConversations'][pid]; - await client.apis.Conversations.Conversations_PostActivity({ conversationId: conversation.conversationId, activity: { - pid: pid, textFormat: 'plain', text: text, type: 'message', @@ -1332,7 +1330,7 @@ export class DialogKeywords { let messages = []; GBLogEx.info(min, `MessageBot: Starting message polling ${conversation.conversationId}).`); - let count = API_RETRIES; + let count = POOLING_COUNT; while (count--) { await GBUtil.sleep(DEFAULT_HEAR_POLL_INTERVAL); @@ -1345,28 +1343,23 @@ export class DialogKeywords { let activities = response.obj.activities; if (activities && activities.length) { - activities = activities.filter(m => m.from.id === min.botId && m.type === 'message'); + activities = activities.filter(m => m.from.id !== user.userSystemId && m.type === 'message'); if (activities.length) { activities.forEach(activity => { messages.push(activity.text); GBLogEx.info(min, `MESSAGE BOT answer from bot: ${activity.text}`); }); + return messages.join('\n'); } - return messages.join('\n'); } } catch (err) { - GBLog.error( - `Error calling printMessages in messageBot API ${err.data === undefined ? err : err.data} ${ - err.errObj ? err.errObj.message : '' - }` - ); - return err; + GBLog.error(`API Message Pooling error: ${GBUtil.toYAML(err)}`); } } + return null; } public async start({ botId, botApiKey, userSystemId, text }) { - let min: GBMinInstance = GBServer.globals.minInstances.filter(p => p.instance.botId === botId)[0]; let sec = new SecService(); let user = await sec.getUserFromSystemId(userSystemId); @@ -1500,7 +1493,7 @@ export class DialogKeywords { 'cache', `${fileOnly.replace(/\s/gi, '')}-${GBAdminService.getNumberIdentifier()}.${ext}` ); - await fs.writeFile(localName1, buf, { encoding: null }); + await fs.writeFile(localName1, buf, { encoding: null }); url = urlJoin(GBServer.globals.publicAddress, min.botId, 'cache', path.basename(localName1)); } @@ -1513,7 +1506,7 @@ export class DialogKeywords { const buf = await fs.readFile(filename); const gbaiName = GBUtil.getGBAIPath(min.botId); const localName = path.join('work', gbaiName, 'cache', `tmp${GBAdminService.getRndReadableIdentifier()}.${ext}`); - await fs.writeFile(localName, buf, { encoding: null }); + await fs.writeFile(localName, buf, { encoding: null }); url = urlJoin(GBServer.globals.publicAddress, min.botId, 'cache', path.basename(localName)); } @@ -1546,7 +1539,7 @@ export class DialogKeywords { const gbaiName = GBUtil.getGBAIPath(min.botId); const localName = path.join('work', gbaiName, 'cache', `qr${GBAdminService.getRndReadableIdentifier()}.png`); -await fs.writeFile(localName, buf, { encoding: null }); + await fs.writeFile(localName, buf, { encoding: null }); const url = urlJoin(GBServer.globals.publicAddress, min.botId, 'cache', path.basename(localName)); return { data: data, localName: localName, url: url }; diff --git a/packages/core.gbapp/services/router/bridge.ts b/packages/core.gbapp/services/router/bridge.ts index 97a549748..a0d7d40ec 100644 --- a/packages/core.gbapp/services/router/bridge.ts +++ b/packages/core.gbapp/services/router/bridge.ts @@ -84,7 +84,7 @@ export const getRouter = ( }); // Gets activities from store (local history array for now) - router.get(`/directline/${botId}/conversations/:conversationId/activities`, (req, res) => { + router.get(`/api/messages/${botId}/v3/directline/conversations/:conversationId/activities`, (req, res) => { const watermark = req.query.watermark && req.query.watermark !== 'null' ? Number(req.query.watermark) : 0; const conversation = getConversation(req.params.conversationId, conversationInitRequired); @@ -146,14 +146,12 @@ export const getRouter = ( router.post('/v3/conversations', (req, res) => { console.warn('/v3/conversations not implemented'); }); - - router.post('/v3/conversations/:conversationId/activities', (req, res) => { + + router.post(`/api/messages/${botId}/v3/directline/conversations/:conversationId/activities`, (req, res) => { let activity: IActivity; activity = req.body; - activity.id = uuidv4.v4(); - activity.from = { id: 'id', name: 'Bot' }; - + const conversation = getConversation(req.params.conversationId, conversationInitRequired); if (conversation) { conversation.history.push(activity); @@ -164,7 +162,7 @@ export const getRouter = ( } }); - router.post('/v3/conversations/:conversationId/activities/:activityId', (req, res) => { + router.post(`/api/messages/${botId}/v3/conversations/:conversationId/activities/:activityId`, (req, res) => { let activity: IActivity; activity = req.body; diff --git a/src/util.ts b/src/util.ts index 874fa1f13..a8743e60a 100644 --- a/src/util.ts +++ b/src/util.ts @@ -75,22 +75,26 @@ export class GBUtil { } public static async getDirectLineClient(min) { - let config = { - spec: JSON.parse(await fs.readFile('directline-3.0.json', 'utf8')), - requestInterceptor: req => { - req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`; - } - }; + let config; if (!GBConfigService.get('STORAGE_NAME')) { - (config['spec'].url = `http://127.0.0.1:${GBConfigService.getServerPort()}/api/messages/${min.botId}`), - (config['spec'].servers = [ - { url: `http://127.0.0.1:${GBConfigService.getServerPort()}/api/messages/${min.botId}` } - ]); - config['spec'].openapi = '3.0.0'; - delete config['spec'].host; - delete config['spec'].swagger; - } + config = { + spec: JSON.parse(await fs.readFile('directline-v2.json', 'utf8')), + requestInterceptor: req => { + req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`; + } + }; + config.spec['host'] = `127.0.0.1:${GBConfigService.getServerPort()}`; + config.spec['basePath'] = `/api/messages/${min.botId}`; + config.spec['schemes'] = ["http"]; + } else { + config = { + spec: JSON.parse(await fs.readFile('directline-v2.json', 'utf8')), + requestInterceptor: req => { + req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`; + } + }; + } return await new SwaggerClient(config); } @@ -124,33 +128,29 @@ export class GBUtil { if (!listOrRow || typeof listOrRow !== 'object') { return listOrRow; } - + // Helper function to convert property names to lowercase - const lowercase = key => typeof key === 'string' ? key.toLowerCase() : key; - + const lowercase = key => (typeof key === 'string' ? key.toLowerCase() : key); + // Create a proxy that maps property accesses to lowercase property names const createCaseInsensitiveProxy = obj => { - const propertiesMap = new Map( - Object.keys(obj).map(propKey => [lowercase(propKey), obj[propKey]]) - ); - + const propertiesMap = new Map(Object.keys(obj).map(propKey => [lowercase(propKey), obj[propKey]])); + const caseInsensitiveGetHandler = { get: (target, property) => propertiesMap.get(lowercase(property)) }; - + return new Proxy(obj, caseInsensitiveGetHandler); }; - + // Handle arrays by mapping each element to a case-insensitive proxy if (Array.isArray(listOrRow)) { - return listOrRow.map(row => - typeof row === 'object' && row !== null ? createCaseInsensitiveProxy(row) : row - ); + return listOrRow.map(row => (typeof row === 'object' && row !== null ? createCaseInsensitiveProxy(row) : row)); } else { return createCaseInsensitiveProxy(listOrRow); } } - + public static async exists(filePath: string): Promise { try { await fs.access(filePath); @@ -163,43 +163,43 @@ export class GBUtil { public static async copyIfNewerRecursive(src, dest) { // Check if the source exists if (!(await GBUtil.exists(src))) { - return; + return; } - - // Check if the source is a directory - if ((await fs.stat(src)).isDirectory()) { - // Create the destination directory if it doesn't exist - if (!(await GBUtil.exists(dest))) { - await fs.mkdir(dest, { recursive: true }); - } - - // Read all files and directories in the source directory - const entries = await fs.readdir(src); - - for (let entry of entries) { - const srcEntry = path.join(src, entry); - const destEntry = path.join(dest, entry); - - // Recursively copy each entry - await this.copyIfNewerRecursive(srcEntry, destEntry); - } - } else { - // Source is a file, check if we need to copy it - if (await GBUtil.exists(dest)) { - const srcStat = await fs.stat(src); - const destStat = await fs.stat(dest); - - // Copy only if the source file is newer than the destination file - if (srcStat.mtime > destStat.mtime) { - await fs.cp(src, dest, { force: true }); - } - } else { - // Destination file doesn't exist, so copy it + + // Check if the source is a directory + if ((await fs.stat(src)).isDirectory()) { + // Create the destination directory if it doesn't exist + if (!(await GBUtil.exists(dest))) { + await fs.mkdir(dest, { recursive: true }); + } + + // Read all files and directories in the source directory + const entries = await fs.readdir(src); + + for (let entry of entries) { + const srcEntry = path.join(src, entry); + const destEntry = path.join(dest, entry); + + // Recursively copy each entry + await this.copyIfNewerRecursive(srcEntry, destEntry); + } + } else { + // Source is a file, check if we need to copy it + if (await GBUtil.exists(dest)) { + const srcStat = await fs.stat(src); + const destStat = await fs.stat(dest); + + // Copy only if the source file is newer than the destination file + if (srcStat.mtime > destStat.mtime) { await fs.cp(src, dest, { force: true }); } + } else { + // Destination file doesn't exist, so copy it + await fs.cp(src, dest, { force: true }); } + } } - // Check if is a tree or flat object. + // Check if is a tree or flat object. public static hasSubObject(t) { for (var key in t) {