mirror of
https://github.com/cheveguerra/bot-whatsapp.git
synced 2026-04-19 12:09:15 +00:00
added dialogflow filter for media
This commit is contained in:
@@ -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
4
.gitignore
vendored
@@ -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
103
adapter/gdrive.js
Normal 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
52
app.js
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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 }
|
||||
@@ -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
8
flow/dialogflow.json
Normal 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
89
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user