added dialogflow filter for media

This commit is contained in:
jzvi12
2022-12-22 20:43:16 -05:00
parent 33490dc737
commit 748262302c
9 changed files with 279 additions and 30 deletions

View File

@@ -10,4 +10,6 @@ SQL_USER=
SQL_PASS=
SQL_DATABASE=
KEEP_DIALOG_FLOW=false
MULTI_DEVICE=true
MULTI_DEVICE=true
DIALOGFLOW_MEDIA_FOR_SLOT_FILLING=false
GDRIVE_FOLDER_ID=

4
.gitignore vendored
View File

@@ -9,4 +9,6 @@ mediaSend/*
!mediaSend/.gitkeep
!mediaSend/nota-de-voz.mp3
.env
.wwebjs_auth
.wwebjs_auth
backup
backup/*

103
adapter/gdrive.js Normal file
View File

@@ -0,0 +1,103 @@
require('dotenv').config({ path: `${__dirname}/../.env` });
const { google } = require('googleapis');
const path = require('path');
const fs = require('fs');
//const clientEmail = require(`${__dirname}/../chatbot-account.json`);
/**
* La funcion 'generatePublicUrl' genera un error muy menor al enviar el 'requestBody'
* siempre y cuando necesites que el acceso sea restringido y solo ciertos usuarios puedan acceder.
* Esto se logra con la combinacion requerida: 'reader', 'user' y 'emailAddress':
* requestBody: {
* role: 'reader',
* type: 'user',
* emailAddress: usuario@gmail.com,
* },
* Segun la documentacion https://developers.google.com/drive/api/v3/reference/permissions/create#request-body,
* los datos se envian correctamente, pero la respuesta del API regresa este error:
* Bad Request. User message: "You cannot share this item because it has been flagged as inappropriate."
* Al parecer, es un error conocido en stackoverflow.com entre varios usuarios del API.
*/
if (process.env.DATABASE === 'dialogflow') {
/**
* Debes de tener tu archivo con el nombre "chatbot-account.json" en la raíz del proyecto
*/
const KEYFILEPATH = path.join(`${__dirname}/../chatbot-account.json`);
const SCOPES = ['https://www.googleapis.com/auth/drive'];
const auth = new google.auth.GoogleAuth({
keyFile: KEYFILEPATH,
scopes: SCOPES,
});
const drive = google.drive({
version: 'v3',
auth,
});
const uploadSingleFile = async (fileName, filePath) => {
const folderId = process.env.GDRIVE_FOLDER_ID;
const { data: { id, name } = {} } = await drive.files.create({
resource: {
name: fileName,
parents: [folderId],
},
media: {
mimeType: 'image/jpg',
body: fs.createReadStream(filePath),
},
fields: 'id,name',
});
generatePublicUrl(id).then(() => {
console.log(`Se generó enlace https://drive.google.com/open?id=${id} para el archivo ${name}`);
});
return `https://drive.google.com/open?id=${id}`
};
const scanFolderForFiles = async (folderPath) => {
const folder = await fs.promises.opendir(folderPath);
for await (const dirent of folder) {
if (dirent.isFile() && dirent.name.endsWith('.jpeg')) {
await uploadSingleFile(dirent.name, path.join(folderPath, dirent.name));
await fs.promises.rm(filePath);
}
}
};
async function generatePublicUrl(id) {
try {
const fileId = id;
await drive.permissions.create({
fileId: fileId,
supportsAllDrives: true,
requestBody: {
role: 'reader',
type: 'domain', // 'anyone' da acceso al publico vía enlace https://drive.google.com...
domain: 'gserviceaccount.com', // Si tu cuenta esta bajo un dominio (usuario@empresa.com) y no bajo gmail.com
allowFileDiscovery: false,
},
});
/*
webViewLink: Ver el archivo en el navegador
webContentLink: Enlace de descarga directa
*/
const result = await drive.files.get({
fileId: fileId,
fields: 'webViewLink, webContentLink',
});
console.log(result.data);
} catch (error) {
//console.log(error.message); // Imprime 'Internal Error', pero aún así genera el enlace
console.error = () => { }; // No muestra el error anterior
}
}
module.exports = { uploadSingleFile, scanFolderForFiles }
} else {
console.log(`Actualmente, la base de datos es:\n\t'DATABASE=${process.env.DATABASE}'\nPara usar Google Drive, cambiar a:\n\t'DATABASE=dialogflow'`);
}

52
app.js
View File

@@ -11,8 +11,8 @@ const mysqlConnection = require('./config/mysql')
const { middlewareClient } = require('./middleware/client')
const { generateImage, cleanNumber, checkEnvFile, createClient, isValidNumber } = require('./controllers/handle')
const { connectionReady, connectionLost } = require('./controllers/connection')
const { saveMedia } = require('./controllers/save')
const { getMessages, responseMessages, bothResponse } = require('./controllers/flows')
const { saveMedia, saveMediaToGoogleDrive } = require('./controllers/save')
const { getMessages, responseMessages, bothResponse, waitFor } = require('./controllers/flows')
const { sendMedia, sendMessage, lastTrigger, sendMessageButton, readChat } = require('./controllers/send')
const app = express();
app.use(cors())
@@ -22,6 +22,7 @@ const server = require('http').Server(app)
const port = process.env.PORT || 3000
var client;
var dialogflowFilter = false;
app.use('/', require('./routes/web'))
/**
@@ -46,7 +47,7 @@ const listenMessage = () => client.on('message', async msg => {
/**
* Guardamos el archivo multimedia que envia
*/
if (process.env.SAVE_MEDIA && hasMedia) {
if (process.env.SAVE_MEDIA === 'true' && hasMedia) {
const media = await msg.downloadMedia();
saveMedia(media);
}
@@ -56,12 +57,27 @@ const listenMessage = () => client.on('message', async msg => {
*/
if (process.env.DATABASE === 'dialogflow') {
if (process.env.DIALOGFLOW_MEDIA_FOR_SLOT_FILLING === 'true' && dialogflowFilter) {
waitFor(_ => hasMedia, 30000)
.then(async _ => {
if (hasMedia) {
const media = await msg.downloadMedia();
message = await saveMediaToGoogleDrive(media);
const response = await bothResponse(message.substring(256, -1), number);
await sendMessage(client, from, response.replyMessage);
}
return
});
dialogflowFilter = false;
}
if (!message.length) return;
const response = await bothResponse(message.substring(256,-1), number);
const response = await bothResponse(message.substring(256, -1), number);
await sendMessage(client, from, response.replyMessage);
if(response.actions){
await sendMessageButton(client, from, null, response.actions);
return
if (response.actions) {
await sendMessageButton(client, from, null, response.actions);
return
}
if (response.media) {
sendMedia(client, from, response.media);
@@ -128,7 +144,26 @@ const listenMessage = () => client.on('message', async msg => {
}
});
/**
* Este evento es necesario para el filtro de Dialogflow
*/
const listenMessageFromBot = () => client.on('message_create', async botMsg => {
const { body } = botMsg;
const dialogflowFilterConfig = fs.readFileSync('./flow/dialogflow.json', 'utf8');
const keywords = JSON.parse(dialogflowFilterConfig);
for (i = 0; i < keywords.length; i++) {
key = keywords[i];
for (var j = 0; j < key.phrases.length; j++) {
let filters = key.phrases[j];
if (body.includes(filters)) {
dialogflowFilter = true;
//console.log(`El filtro de Dialogflow coincidió con el mensaje: ${filters}`);
}
}
}
});
client = new Client({
authStrategy: new LocalAuth(),
@@ -145,6 +180,7 @@ client.on('qr', qr => generateImage(qr, () => {
client.on('ready', (a) => {
connectionReady()
listenMessage()
listenMessageFromBot()
// socketEvents.sendStatus(client)
});
@@ -159,8 +195,6 @@ client.on('authenticated', () => {
client.initialize();
/**
* Verificamos si tienes un gesto de db
*/

View File

@@ -1,5 +1,5 @@
const {get, reply, getIA} = require('../adapter')
const {saveExternalFile, checkIsUrl} = require('./handle')
const { get, reply, getIA } = require('../adapter')
const { saveExternalFile, checkIsUrl } = require('./handle')
const getMessages = async (message) => {
const data = await get(message)
@@ -8,21 +8,29 @@ const getMessages = async (message) => {
const responseMessages = async (step) => {
const data = await reply(step)
if(data && data.media){
if (data && data.media) {
const file = checkIsUrl(data.media) ? await saveExternalFile(data.media) : data.media;
return {...data,...{media:file}}
return { ...data, ...{ media: file } }
}
return data
}
const bothResponse = async (message, sessionId) => {
const data = await getIA(message, sessionId)
if(data && data.media){
if (data && data.media) {
const file = await saveExternalFile(data.media)
return {...data,...{media:file}}
return { ...data, ...{ media: file } }
}
return data
}
const waitFor = (conditionFunction, WAIT_TIME) => {
const poll = resolve => {
if (conditionFunction())
resolve();
else setTimeout(_ => poll(resolve), WAIT_TIME);
}
return new Promise(poll);
}
module.exports = { getMessages, responseMessages, bothResponse }
module.exports = { getMessages, responseMessages, bothResponse, waitFor }

View File

@@ -1,5 +1,8 @@
const mimeDb = require('mime-db')
const fs = require('fs')
const mimeDb = require('mime-db');
const { uploadSingleFile } = require('../adapter/gdrive');
const fs = require('fs');
var fileName;
/**
* Guardamos archivos multimedia que nuestro cliente nos envie!
@@ -16,9 +19,20 @@ const saveMedia = (media) => {
} else {
ext = extensionProcess.extensions[0];
}
fs.writeFile(`./media/${Date.now()}.${ext}`, media.data, { encoding: 'base64' }, function (err) {
console.log('** Archivo Media Guardado **');
fileName = `${Date.now()}.${ext}`;
fs.writeFile(`./media/${fileName}`, media.data, { encoding: 'base64' }, function (err) {
console.log(`** Archivo Media ${fileName} Guardado **`);
});
return fileName
}
module.exports = {saveMedia}
const saveMediaToGoogleDrive = async (media) => {
fileName = saveMedia(media);
filePath = `${__dirname}/../media/${fileName}`
const googleDriveUrl = await uploadSingleFile(fileName, filePath);
return googleDriveUrl
}
module.exports = { saveMedia, saveMediaToGoogleDrive }

8
flow/dialogflow.json Normal file
View File

@@ -0,0 +1,8 @@
[
{
"phrases": [
"Se requiere una foto de alguna identificación por razones de seguridad.",
"Por favor envíenos una foto de su ID para completar su formulario."
]
}
]

89
package-lock.json generated
View File

@@ -15,6 +15,7 @@
"exceljs": "^4.3.0",
"express": "^4.18.1",
"file-type": "^17.1.6",
"googleapis": "^109.0.1",
"mime-db": "^1.52.0",
"moment": "^2.29.4",
"mysql": "^2.18.1",
@@ -23,7 +24,7 @@
"qrcode-terminal": "^0.12.0",
"socket.io": "^4.5.1",
"stormdb": "^0.6.0",
"whatsapp-web.js": "github:pedroslopez/whatsapp-web.js#fix-buttons-list",
"whatsapp-web.js": "^1.18.4",
"xlsx": "^0.18.5"
},
"devDependencies": {
@@ -2282,6 +2283,42 @@
"node": ">=12.0.0"
}
},
"node_modules/googleapis": {
"version": "109.0.1",
"resolved": "https://registry.npmjs.org/googleapis/-/googleapis-109.0.1.tgz",
"integrity": "sha512-x286OtNu0ngzxfGz2XgRs4aMhrwutRCkCE12dh2M1jIZOpOndB7ELFXEhmtxaJ7z3257flKIbiiCJZeBO+ze/Q==",
"dependencies": {
"google-auth-library": "^8.0.2",
"googleapis-common": "^6.0.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/googleapis-common": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-6.0.4.tgz",
"integrity": "sha512-m4ErxGE8unR1z0VajT6AYk3s6a9gIMM6EkDZfkPnES8joeOlEtFEJeF8IyZkb0tjPXkktUfYrE4b3Li1DNyOwA==",
"dependencies": {
"extend": "^3.0.2",
"gaxios": "^5.0.1",
"google-auth-library": "^8.0.2",
"qs": "^6.7.0",
"url-template": "^2.0.8",
"uuid": "^9.0.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/googleapis-common/node_modules/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/graceful-fs": {
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
@@ -4953,6 +4990,11 @@
"safe-buffer": "~5.1.0"
}
},
"node_modules/url-template": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
"integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw=="
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -5028,9 +5070,9 @@
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatsapp-web.js": {
"version": "1.18.3-alpha.0",
"resolved": "git+ssh://git@github.com/pedroslopez/whatsapp-web.js.git#c8fe80635afc6fba9913577a3097e8bf1f557a0b",
"license": "Apache-2.0",
"version": "1.18.4",
"resolved": "https://registry.npmjs.org/whatsapp-web.js/-/whatsapp-web.js-1.18.4.tgz",
"integrity": "sha512-Dqu6Q37tDDAcVJ44aMdRE76sI/9rBCUG+NTz1Kxh2w4obX2WtpoRetilxqgx1r4+pFUl58Lf21wGOEwPZ1pT/A==",
"dependencies": {
"@pedroslopez/moduleraid": "^5.0.2",
"fluent-ffmpeg": "^2.1.2",
@@ -7061,6 +7103,35 @@
"node-forge": "^1.3.1"
}
},
"googleapis": {
"version": "109.0.1",
"resolved": "https://registry.npmjs.org/googleapis/-/googleapis-109.0.1.tgz",
"integrity": "sha512-x286OtNu0ngzxfGz2XgRs4aMhrwutRCkCE12dh2M1jIZOpOndB7ELFXEhmtxaJ7z3257flKIbiiCJZeBO+ze/Q==",
"requires": {
"google-auth-library": "^8.0.2",
"googleapis-common": "^6.0.0"
}
},
"googleapis-common": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-6.0.4.tgz",
"integrity": "sha512-m4ErxGE8unR1z0VajT6AYk3s6a9gIMM6EkDZfkPnES8joeOlEtFEJeF8IyZkb0tjPXkktUfYrE4b3Li1DNyOwA==",
"requires": {
"extend": "^3.0.2",
"gaxios": "^5.0.1",
"google-auth-library": "^8.0.2",
"qs": "^6.7.0",
"url-template": "^2.0.8",
"uuid": "^9.0.0"
},
"dependencies": {
"uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg=="
}
}
},
"graceful-fs": {
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
@@ -9119,6 +9190,11 @@
}
}
},
"url-template": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
"integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw=="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -9178,8 +9254,9 @@
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"whatsapp-web.js": {
"version": "git+ssh://git@github.com/pedroslopez/whatsapp-web.js.git#c8fe80635afc6fba9913577a3097e8bf1f557a0b",
"from": "whatsapp-web.js@github:pedroslopez/whatsapp-web.js#fix-buttons-list",
"version": "1.18.4",
"resolved": "https://registry.npmjs.org/whatsapp-web.js/-/whatsapp-web.js-1.18.4.tgz",
"integrity": "sha512-Dqu6Q37tDDAcVJ44aMdRE76sI/9rBCUG+NTz1Kxh2w4obX2WtpoRetilxqgx1r4+pFUl58Lf21wGOEwPZ1pT/A==",
"requires": {
"@pedroslopez/moduleraid": "^5.0.2",
"archiver": "^5.3.1",

View File

@@ -36,6 +36,7 @@
"exceljs": "^4.3.0",
"express": "^4.18.1",
"file-type": "^17.1.6",
"googleapis": "^109.0.1",
"mime-db": "^1.52.0",
"moment": "^2.29.4",
"mysql": "^2.18.1",
@@ -44,7 +45,7 @@
"qrcode-terminal": "^0.12.0",
"socket.io": "^4.5.1",
"stormdb": "^0.6.0",
"whatsapp-web.js": "github:pedroslopez/whatsapp-web.js#fix-buttons-list",
"whatsapp-web.js": "^1.18.4",
"xlsx": "^0.18.5"
},
"devDependencies": {