diff --git a/GLOSSARY.md b/GLOSSARY.md index ec85e10..d054e6f 100644 --- a/GLOSSARY.md +++ b/GLOSSARY.md @@ -1,2 +1,2 @@ CTX: Es el objeto que representa un mensaje, con opciones, id, ref -messageInComming: Objeto entrante del provider {body, from,...} \ No newline at end of file +messageInComming: Objeto entrante del provider {body, from,to,...} \ No newline at end of file diff --git a/package.json b/package.json index 8a8ebe0..92f2f3d 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "create-bot:rollup": "rollup --config ./packages/create-bot-whatsapp/rollup-create.config.js ", "bot:rollup": "rollup --config ./packages/bot/rollup-bot.config.js", "provider:rollup": "rollup --config ./packages/provider/rollup-provider.config.js ", + "contexts:rollup": "rollup --config ./packages/contexts/rollup-contexts.config.js", "database:rollup": "rollup --config ./packages/database/rollup-database.config.js", "create-bot-whatsapp:rollup": "rollup --config ./packages/create-bot-whatsapp/rollup-create.config.js", "format:check": "prettier --check ./packages", @@ -17,7 +18,7 @@ "fmt.staged": "pretty-quick --staged", "lint:check": "eslint ./packages", "lint:fix": "eslint --fix ./packages", - "build": "yarn run cli:rollup && yarn run bot:rollup && yarn run provider:rollup && yarn run database:rollup && yarn run create-bot-whatsapp:rollup", + "build": "yarn run cli:rollup && yarn run bot:rollup && yarn run provider:rollup && yarn run database:rollup && yarn run contexts:rollup && yarn run create-bot-whatsapp:rollup", "copy.lib": "node ./scripts/move.js", "test.unit": "node ./node_modules/uvu/bin.js packages test", "test.coverage": "node ./node_modules/c8/bin/c8.js npm run test.unit", @@ -37,6 +38,7 @@ "packages/cli", "packages/database", "packages/provider", + "packages/contexts", "packages/docs" ], "keywords": [ diff --git a/packages/bot/core/core.class.js b/packages/bot/core/core.class.js index 7411954..e545a55 100644 --- a/packages/bot/core/core.class.js +++ b/packages/bot/core/core.class.js @@ -58,13 +58,13 @@ class CoreClass { ] /** - * - * @param {*} messageInComming + * GLOSSARY.md + * @param {*} messageCtxInComming * @returns */ - handleMsg = async (messageInComming) => { - logger.log(`[handleMsg]: `, messageInComming) - const { body, from } = messageInComming + handleMsg = async (messageCtxInComming) => { + logger.log(`[handleMsg]: `, messageCtxInComming) + const { body, from } = messageCtxInComming let msgToSend = [] let fallBackFlag = false @@ -95,9 +95,12 @@ class CoreClass { // 📄 Se encarga de revisar si el contexto del mensaje tiene callback y ejecutarlo const cbEveryCtx = (inRef) => { const indexFlow = this.flowClass.findIndexByRef(inRef) - this.flowClass.allCallbacks[indexFlow].callback(messageInComming, { - fallBack, - }) + this.flowClass.allCallbacks[indexFlow].callback( + messageCtxInComming, + { + fallBack, + } + ) } // 📄 [options: callback]: Si se tiene un callback se ejecuta diff --git a/packages/contexts/package.json b/packages/contexts/package.json new file mode 100644 index 0000000..9d27195 --- /dev/null +++ b/packages/contexts/package.json @@ -0,0 +1,16 @@ +{ + "name": "@bot-whatsapp/contexts", + "version": "0.0.1", + "description": "", + "main": "./lib/bundle.contexts.cjs", + "files": [ + "./lib/" + ], + "exports": { + "./mock": "./lib/mock/index.cjs", + "./dialogflow": "./lib/dialogflow/index.cjs" + }, + "dependencies": { + "@bot-whatsapp/bot": "*" + } +} diff --git a/packages/contexts/rollup-contexts.config.js b/packages/contexts/rollup-contexts.config.js new file mode 100644 index 0000000..59a7624 --- /dev/null +++ b/packages/contexts/rollup-contexts.config.js @@ -0,0 +1,24 @@ +const banner = require('../../config/banner.rollup.json') +const commonjs = require('@rollup/plugin-commonjs') +const { join } = require('path') + +module.exports = [ + { + input: join(__dirname, 'src', 'mock', 'index.js'), + output: { + banner: banner['banner.output'].join(''), + file: join(__dirname, 'lib', 'mock', 'index.cjs'), + format: 'cjs', + }, + plugins: [commonjs()], + }, + { + input: join(__dirname, 'src', 'dialogflow', 'index.js'), + output: { + banner: banner['banner.output'].join(''), + file: join(__dirname, 'lib', 'dialogflow', 'index.cjs'), + format: 'cjs', + }, + plugins: [commonjs()], + }, +] diff --git a/packages/contexts/src/dialogflow/dialogflow.class.js b/packages/contexts/src/dialogflow/dialogflow.class.js new file mode 100644 index 0000000..db34e50 --- /dev/null +++ b/packages/contexts/src/dialogflow/dialogflow.class.js @@ -0,0 +1,113 @@ +const { CoreClass } = require('@bot-whatsapp/bot') +const dialogflow = require('@google-cloud/dialogflow') +const { existsSync, readFileSync } = require('fs') +const { join } = require('path') + +/** + * Necesita extender de core.class + * handleMsg(messageInComming) // const { body, from } = messageInComming + */ + +const GOOGLE_ACCOUNT_PATH = join(process.cwd(), 'google-key.json') + +class DialogFlowContext extends CoreClass { + projectId = null + configuration = null + sessionClient = null + optionsDX = { + language: 'es', + } + + constructor(_database, _provider, _optionsDX = {}) { + super(null, _database, _provider) + this.optionsDX = { ...this.optionsDX, ..._optionsDX } + this.init() + } + + /** + * Verificar conexión con servicio de DialogFlow + */ + init = () => { + if (!existsSync(GOOGLE_ACCOUNT_PATH)) { + console.log(`[ERROR]: No se encontro ${GOOGLE_ACCOUNT_PATH}`) + /** + * Emitir evento de error para que se mueste por consola dicinedo que no tiene el json + * */ + } + + const rawJson = readFileSync(GOOGLE_ACCOUNT_PATH, 'utf-8') + const { project_id, private_key, client_email } = JSON.parse(rawJson) + + this.projectId = project_id + this.configuration = { + credentials: { + private_key, + client_email, + }, + } + + this.sessionClient = new dialogflow.SessionsClient(this.configuration) + } + + /** + * GLOSSARY.md + * @param {*} messageCtxInComming + * @returns + */ + handleMsg = async (messageCtxInComming) => { + const languageCode = this.optionsDX.language + const { from, body } = messageCtxInComming + + let customPayload = {} + + /** + * 📄 Creamos session de contexto basado en el numero de la persona + * para evitar este problema. + * https://github.com/codigoencasa/bot-whatsapp/pull/140 + */ + const session = this.sessionClient.projectAgentSessionPath( + this.projectId, + from + ) + const reqDialog = { + session, + queryInput: { + text: { + text: body, + languageCode, + }, + }, + } + + const [single] = (await this.sessionClient.detectIntent(reqDialog)) || [ + null, + ] + + const { queryResult } = single + + const msgPayload = queryResult?.fulfillmentMessages?.find( + (a) => a.message === 'payload' + ) + + // Revisamos si el dialogFlow tiene multimedia + if (msgPayload && msgPayload?.payload) { + const { fields } = msgPayload.payload + const mapButtons = fields?.buttons?.listValue?.values.map((m) => { + return m?.structValue?.fields?.body?.stringValue + }) + customPayload = { + media: fields?.media?.stringValue, + buttons: mapButtons, + } + } + + const ctxFromDX = { + ...customPayload, + answer: queryResult?.fulfillmentText, + } + + this.sendFlow([ctxFromDX], from) + } +} + +module.exports = DialogFlowContext diff --git a/packages/contexts/src/dialogflow/index.js b/packages/contexts/src/dialogflow/index.js new file mode 100644 index 0000000..e988f50 --- /dev/null +++ b/packages/contexts/src/dialogflow/index.js @@ -0,0 +1,14 @@ +const DialogFlowClass = require('./dialogflow.class') + +/** + * Crear instancia de clase Bot + * @param {*} args + * @returns + */ +const createBotDialog = async ({ database, provider }) => + new DialogFlowClass(database, provider) + +module.exports = { + createBotDialog, + DialogFlowClass, +} diff --git a/packages/contexts/src/mock/index.js b/packages/contexts/src/mock/index.js new file mode 100644 index 0000000..b609be5 --- /dev/null +++ b/packages/contexts/src/mock/index.js @@ -0,0 +1,14 @@ +const MockClass = require('./mock.class') + +/** + * Crear instancia de clase Bot + * @param {*} args + * @returns + */ +const createBotMock = async ({ database, provider }) => + new MockClass(database, provider) + +module.exports = { + createBotMock, + MockClass, +} diff --git a/packages/contexts/src/mock/mock.class.js b/packages/contexts/src/mock/mock.class.js new file mode 100644 index 0000000..4ffece4 --- /dev/null +++ b/packages/contexts/src/mock/mock.class.js @@ -0,0 +1,24 @@ +const { CoreClass } = require('@bot-whatsapp/bot') +/** + * Necesita extender de core.class + * handleMsg(messageInComming) // const { body, from } = messageInComming + */ + +class MockContext extends CoreClass { + constructor(_database, _provider) { + super(null, _database, _provider) + } + + init = () => {} + + /** + * GLOSSARY.md + * @param {*} messageCtxInComming + * @returns + */ + handleMsg = async ({ from, body }) => { + console.log('DEBUG:', messageCtxInComming) + } +} + +module.exports = MockContext diff --git a/packages/provider/src/baileys/index.js b/packages/provider/src/baileys/index.js index 0b14afe..3e5c446 100644 --- a/packages/provider/src/baileys/index.js +++ b/packages/provider/src/baileys/index.js @@ -100,7 +100,8 @@ class BaileysProvider extends ProviderClass { }, { event: 'messages.upsert', - func: ({ messages }) => { + func: ({ messages, type }) => { + if (type !== 'notify') return const [messageCtx] = messages let payload = { ...messageCtx, diff --git a/scripts/move.js b/scripts/move.js index d92d233..078581a 100644 --- a/scripts/move.js +++ b/scripts/move.js @@ -15,4 +15,5 @@ Promise.all([ copyLibPkg('bot', appDir), copyLibPkg('database', appDir), copyLibPkg('provider', appDir), + copyLibPkg('contexts', appDir), ]).then(() => console.log('Todas las librerías copiadas')) diff --git a/yarn.lock b/yarn.lock index e5389fe..a977b83 100644 --- a/yarn.lock +++ b/yarn.lock @@ -963,6 +963,14 @@ __metadata: languageName: unknown linkType: soft +"@bot-whatsapp/contexts@workspace:packages/contexts": + version: 0.0.0-use.local + resolution: "@bot-whatsapp/contexts@workspace:packages/contexts" + dependencies: + "@bot-whatsapp/bot": "*" + languageName: unknown + linkType: soft + "@bot-whatsapp/database@npm:*": version: 0.1.2 resolution: "@bot-whatsapp/database@npm:0.1.2"