mirror of
https://github.com/cheveguerra/bot-whatsapp.git
synced 2026-04-21 04:59:15 +00:00
Compare commits
59 Commits
buttons
...
0.0.1-alph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee87e9e875 | ||
|
|
1884832192 | ||
|
|
f21a58b6ff | ||
|
|
8a4f134327 | ||
|
|
9b6ce92612 | ||
|
|
663fcafc9c | ||
|
|
f36ddd3014 | ||
|
|
3fadaaaf13 | ||
|
|
dfa569f29d | ||
|
|
601508f379 | ||
|
|
e7ad205268 | ||
|
|
f62ba0a076 | ||
|
|
a9efa0aa58 | ||
|
|
3276c21bc3 | ||
|
|
1114f25a71 | ||
|
|
f13a34ff75 | ||
|
|
d45ea85e7d | ||
|
|
10e2b138d3 | ||
|
|
a1bf5ba5c2 | ||
|
|
19102b7b3a | ||
|
|
5efcc2a9a6 | ||
|
|
8279c07a88 | ||
|
|
02d7b3bd98 | ||
|
|
f8f6a3000d | ||
|
|
9a92b152a4 | ||
|
|
f86700deaf | ||
|
|
4ba259b46c | ||
|
|
cf459e94d2 | ||
|
|
4f8ed1361c | ||
|
|
bad8802241 | ||
|
|
f09ac862d5 | ||
|
|
fe7567e1a9 | ||
|
|
9b0b7f4d54 | ||
|
|
3ddbf462a8 | ||
|
|
e6043c99a7 | ||
|
|
b1daa0020e | ||
|
|
190d35c9a5 | ||
|
|
e4378fe848 | ||
|
|
981a6bd928 | ||
|
|
676e48021f | ||
|
|
1d4daf10db | ||
|
|
3c9341d87d | ||
|
|
04982941a7 | ||
|
|
ba4f05ebb2 | ||
|
|
5aaf761fce | ||
|
|
12539d00fa | ||
|
|
ec8ad955ee | ||
|
|
d10504c40b | ||
|
|
d200100caa | ||
|
|
902431c533 | ||
|
|
e23540593a | ||
|
|
9b548d9418 | ||
|
|
c25de59a93 | ||
|
|
cfe2c17165 | ||
|
|
1309b7f806 | ||
|
|
1071469e53 | ||
|
|
1795e8de20 | ||
|
|
7414d958ab | ||
|
|
a3ebebb19c |
@@ -9,3 +9,5 @@ SQL_HOST=
|
|||||||
SQL_USER=
|
SQL_USER=
|
||||||
SQL_PASS=
|
SQL_PASS=
|
||||||
SQL_DATABASE=
|
SQL_DATABASE=
|
||||||
|
KEEP_DIALOG_FLOW=false
|
||||||
|
MULTI_DEVICE=true
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,4 +7,6 @@ media/*
|
|||||||
!media/.gitkeep
|
!media/.gitkeep
|
||||||
mediaSend/*
|
mediaSend/*
|
||||||
!mediaSend/.gitkeep
|
!mediaSend/.gitkeep
|
||||||
|
!mediaSend/nota-de-voz.mp3
|
||||||
.env
|
.env
|
||||||
|
.wwebjs_auth
|
||||||
82
README.md
82
README.md
@@ -1,18 +1,4 @@
|
|||||||
## Chatbot Whatsapp (OpenSource)
|
## Chatbot Whatsapp (OpenSource)
|
||||||
#### Actualizado Enero 2022
|
|
||||||
|
|
||||||
El siguiente proyecto se realizó con fines educativos para el canal de [Youtube (Leifer Mendez)](https://www.youtube.com/channel/UCgrIGp5QAnC0J8LfNJxDRDw?sub_confirmation=1) donde aprendemos a crear y implementar un chatbot increíble usando [node.js](https://codigoencasa.com/tag/nodejs/) además le agregamos inteligencia artificial gracias al servicio de __dialogflow__.
|
|
||||||
|
|
||||||
[](https://youtu.be/5lEMCeWEJ8o)
|
|
||||||
|
|
||||||
#### Acceso rápido
|
|
||||||
> Si tienes una cuenta en __heroku__ puedes desplegar este proyecto con (1 click)
|
|
||||||
|
|
||||||
[](https://heroku.com/deploy?template=https://github.com/leifermendez/bot-ventas)
|
|
||||||
|
|
||||||
> Comprarme un cafe!
|
|
||||||
|
|
||||||
[](https://www.buymeacoffee.com/leifermendez)
|
|
||||||
|
|
||||||
#### Actualización
|
#### Actualización
|
||||||
|
|
||||||
@@ -23,22 +9,55 @@ El siguiente proyecto se realizó con fines educativos para el canal de [Youtube
|
|||||||
| JSON File | ✅ |
|
| JSON File | ✅ |
|
||||||
| QR Scan (route) | ✅ |
|
| QR Scan (route) | ✅ |
|
||||||
| Easy deploy heroku | ✅ |
|
| Easy deploy heroku | ✅ |
|
||||||
| Buttons | ✅ |
|
| Buttons | ✅ℹ️ (No funciona en multi-device)|
|
||||||
|
| Send Voice Note | ✅ |
|
||||||
| Add support ubuntu/linux | ✅ |
|
| Add support ubuntu/linux | ✅ |
|
||||||
|
|
||||||
### (Nuevo) Botones
|
|
||||||
|
|
||||||
[](https://youtu.be/5lEMCeWEJ8o)
|
|
||||||
|
|
||||||
## Requisitos
|
## Requisitos
|
||||||
- node v14 o superior
|
- node v14 o superior
|
||||||
- VSCode (Editor de codigo) [Descargar](https://code.visualstudio.com/download)
|
- VSCode (Editor de codigo) [Descargar](https://code.visualstudio.com/download)
|
||||||
- MySql (opcional) solo aplica si vas a usar el modo 'mysql' [sql-bot.sql migración](https://github.com/leifermendez/bot-whatsapp/blob/main/sql-bot.sql)
|
- MySql (opcional) solo aplica si vas a usar el modo 'mysql' [sql-bot.sql migración](https://github.com/leifermendez/bot-whatsapp/blob/main/sql-bot.sql)
|
||||||
- Dialogflow (opcional) solo aplica si vas a usar el modo 'dialogflow'
|
- Dialogflow (opcional) solo aplica si vas a usar el modo 'dialogflow'
|
||||||
|
|
||||||
|
### (Nuevo) Botones
|
||||||
|
|
||||||
|
[](https://youtu.be/5lEMCeWEJ8o)
|
||||||
|
|
||||||
|
> Implementar los botones solo necesitas hacer uso del metodo __sendMessageButton__ que se encuentra dentro `./controllers/send` dejo un ejemplo de como usarlo.
|
||||||
|
[Ver implementación](https://github.com/leifermendez/bot-whatsapp/blob/main/app.js#L123)
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
const { sendMessageButton } = require('./controllers/send')
|
||||||
|
|
||||||
|
await sendMessageButton(
|
||||||
|
{
|
||||||
|
"title":"¿Que te interesa ver?",
|
||||||
|
"message":"Recuerda todo este contenido es gratis y estaria genial que me siguas!",
|
||||||
|
"footer":"Gracias",
|
||||||
|
"buttons":[
|
||||||
|
{"body":"😎 Cursos"},
|
||||||
|
{"body":"👉 Youtube"},
|
||||||
|
{"body":"😁 Telegram"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notas de Voz
|
||||||
|
[](https://i.imgur.com/zq6xYDp.png)
|
||||||
|
|
||||||
|
> Se pueden enviar notas de voz con formato nativo para que no se vea como reenviado. En este ejemplo enviare el archivo __PTT-20220223-WA0000.opus__ que se encuentra dentro de la carpeta de __/mediaSend__
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
const { sendMediaVoiceNote } = require('./controllers/send')
|
||||||
|
|
||||||
|
await sendMediaVoiceNote(client, from, 'PTT-20220223-WA0000.opus')
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## Instruciones
|
## Instruciones
|
||||||
__Descargar o Clonar repositorio__
|
__Descargar o Clonar repositorio__
|
||||||

|
|
||||||
|
|
||||||
__Usas ¿Ubuntu / Linux?__
|
__Usas ¿Ubuntu / Linux?__
|
||||||
> Asegurate de instalar los siguientes paquetes
|
> Asegurate de instalar los siguientes paquetes
|
||||||
@@ -50,9 +69,9 @@ sudo apt install -y gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups
|
|||||||
__Instalar dependencias (npm install)__
|
__Instalar dependencias (npm install)__
|
||||||
> Ubicate en le directorio que descargaste y via consola o terminal ejecuta el siguiente comando
|
> Ubicate en le directorio que descargaste y via consola o terminal ejecuta el siguiente comando
|
||||||
|
|
||||||
`npm install`
|
```
|
||||||
|
npm i
|
||||||

|
```
|
||||||
|
|
||||||
__Configurar .env__
|
__Configurar .env__
|
||||||
> Con el editor de texto crea un archivo `.env` el cual debes de guiarte del archivo `.env.example`
|
> Con el editor de texto crea un archivo `.env` el cual debes de guiarte del archivo `.env.example`
|
||||||
@@ -71,21 +90,14 @@ SQL_PASS=
|
|||||||
SQL_DATABASE=
|
SQL_DATABASE=
|
||||||
```
|
```
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
__Ejecutar el script__
|
__Ejecutar el script__
|
||||||
> Ubicate en le directorio que descargaste y via consola o terminal ejecuta el siguiente comando
|
> Ubicate en le directorio que descargaste y via consola o terminal ejecuta el siguiente comando
|
||||||
`npm run start`
|
`npm run start`
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
__Whatsapp en tu celular__
|
__Whatsapp en tu celular__
|
||||||
> Ahora abre la aplicación de Whatsapp en tu dispositivo y escanea el código QR
|
> Ahora abre la aplicación de Whatsapp en tu dispositivo y escanea el código QR
|
||||||
<img src="https://i.imgur.com/RSbPtat.png" width="500" />
|
<img src="https://i.imgur.com/RSbPtat.png" width="500" />
|
||||||
Visitar la pagina
|
Tambien puedes visitar la pagina http://127.0.0.1:3000/qr
|
||||||
`http://localhost:3000/qr`
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
__Listo 😎__
|
__Listo 😎__
|
||||||
> Cuando sale este mensaje tu BOT está __listo__ para trabajar!
|
> Cuando sale este mensaje tu BOT está __listo__ para trabajar!
|
||||||
@@ -102,11 +114,3 @@ __Listo 😎__
|
|||||||
|
|
||||||
> Ahora deberías obtener un arespuesta por parte del BOT como la siguiente, ademas de esto tambien se crea un archivo excel
|
> Ahora deberías obtener un arespuesta por parte del BOT como la siguiente, ademas de esto tambien se crea un archivo excel
|
||||||
con el historial de conversación con el número de tu cliente
|
con el historial de conversación con el número de tu cliente
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
## Preguntar al BOT
|
|
||||||
> Puedes interactuar con el bot ejemplo escribele __hola__ y el bot debe responderte!
|
|
||||||
|
|
||||||

|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
const dialogflow = require('@google-cloud/dialogflow');
|
const dialogflow = require('@google-cloud/dialogflow');
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const nanoid = require('nanoid')
|
|
||||||
/**
|
/**
|
||||||
* Debes de tener tu archivo con el nombre "chatbot-account.json" en la raíz del proyecto
|
* Debes de tener tu archivo con el nombre "chatbot-account.json" en la raíz del proyecto
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const KEEP_DIALOG_FLOW = (process.env.KEEP_DIALOG_FLOW === 'true')
|
||||||
let PROJECID;
|
let PROJECID;
|
||||||
let CONFIGURATION;
|
let CONFIGURATION;
|
||||||
let sessionClient;
|
let sessionClient;
|
||||||
@@ -28,9 +30,9 @@ const checkFileCredentials = () => {
|
|||||||
|
|
||||||
|
|
||||||
// Detect intent method
|
// Detect intent method
|
||||||
const detectIntent = async (queryText) => {
|
const detectIntent = async (queryText, waPhoneNumber) => {
|
||||||
let media = null;
|
let media = null;
|
||||||
const sessionId = nanoid.nanoid()
|
const sessionId = KEEP_DIALOG_FLOW ? 1 : waPhoneNumber;
|
||||||
const sessionPath = sessionClient.projectAgentSessionPath(PROJECID, sessionId);
|
const sessionPath = sessionClient.projectAgentSessionPath(PROJECID, sessionId);
|
||||||
const languageCode = process.env.LANGUAGE
|
const languageCode = process.env.LANGUAGE
|
||||||
const request = {
|
const request = {
|
||||||
@@ -54,7 +56,7 @@ const detectIntent = async (queryText) => {
|
|||||||
const { fields } = parsePayload.payload
|
const { fields } = parsePayload.payload
|
||||||
media = fields.media.stringValue || null
|
media = fields.media.stringValue || null
|
||||||
}
|
}
|
||||||
// const customPayload = parsePayload['payload']
|
const customPayload = parsePayload ? parsePayload['payload'] : null
|
||||||
|
|
||||||
const parseData = {
|
const parseData = {
|
||||||
replyMessage: queryResult.fulfillmentText,
|
replyMessage: queryResult.fulfillmentText,
|
||||||
@@ -64,8 +66,8 @@ const detectIntent = async (queryText) => {
|
|||||||
return parseData
|
return parseData
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDataIa = (message = '', cb = () => { }) => {
|
const getDataIa = (message = '', sessionId = '', cb = () => { }) => {
|
||||||
detectIntent(message).then((res) => {
|
detectIntent(message, sessionId).then((res) => {
|
||||||
cb(res)
|
cb(res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const { getData, getReply } = require('./mysql')
|
const { getData, getReply, saveMessageMysql } = require('./mysql')
|
||||||
|
const { saveMessageJson } = require('./jsonDb')
|
||||||
const { getDataIa } = require('./diaglogflow')
|
const { getDataIa } = require('./diaglogflow')
|
||||||
const stepsInitial = require('../flow/initial.json')
|
const stepsInitial = require('../flow/initial.json')
|
||||||
const stepsReponse = require('../flow/response.json')
|
const stepsReponse = require('../flow/response.json')
|
||||||
@@ -51,17 +52,39 @@ const reply = (step) => new Promise((resolve, reject) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const getIA = (message) => new Promise((resolve, reject) => {
|
const getIA = (message, sessionId) => new Promise((resolve, reject) => {
|
||||||
/**
|
/**
|
||||||
* Si usas dialogflow
|
* Si usas dialogflow
|
||||||
*/
|
*/
|
||||||
if (process.env.DATABASE === 'dialogflow') {
|
if (process.env.DATABASE === 'dialogflow') {
|
||||||
let resData = { replyMessage: '', media: null, trigger: null }
|
let resData = { replyMessage: '', media: null, trigger: null }
|
||||||
getDataIa(message,(dt) => {
|
getDataIa(message, sessionId, (dt) => {
|
||||||
resData = { ...resData, ...dt }
|
resData = { ...resData, ...dt }
|
||||||
resolve(resData)
|
resolve(resData)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
module.exports = { get, reply, getIA }
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} message
|
||||||
|
* @param {*} date
|
||||||
|
* @param {*} trigger
|
||||||
|
* @param {*} number
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const saveMessage = ( message, trigger, number ) => new Promise( async (resolve, reject) => {
|
||||||
|
switch ( process.env.DATABASE ) {
|
||||||
|
case 'mysql':
|
||||||
|
resolve( await saveMessageMysql( message, trigger, number ) )
|
||||||
|
break;
|
||||||
|
case 'none':
|
||||||
|
resolve( await saveMessageJson( message, trigger, number ) )
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
resolve(true)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = { get, reply, getIA, saveMessage }
|
||||||
20
adapter/jsonDb.js
Normal file
20
adapter/jsonDb.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
const Path = require('path')
|
||||||
|
const StormDB = require("stormdb");
|
||||||
|
const date = new Date().toISOString();
|
||||||
|
const saveMessageJson = (message, trigger, number) => new Promise( async(resolve,reject) =>{
|
||||||
|
try {
|
||||||
|
const engine = new StormDB.localFileEngine( Path.join(__dirname, `/../chats/${number}.json`) );
|
||||||
|
const db = new StormDB(engine);
|
||||||
|
// set default db value if db is empty
|
||||||
|
db.default({ messages: [] });
|
||||||
|
// add new users entry
|
||||||
|
db.get("messages").push({ message, date, trigger });
|
||||||
|
db.save();
|
||||||
|
resolve('Saved')
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = { saveMessageJson }
|
||||||
@@ -21,8 +21,54 @@ getReply = (option_key = '', callback) => connection.query(
|
|||||||
replyMessage:response?.replyMessage || '',
|
replyMessage:response?.replyMessage || '',
|
||||||
trigger:response?.trigger || '',
|
trigger:response?.trigger || '',
|
||||||
media:response?.media || ''
|
media:response?.media || ''
|
||||||
|
|
||||||
}
|
}
|
||||||
callback(value)
|
callback(value)
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = {getData, getReply}
|
getMessages = ( number ) => new Promise((resolve,reejct) => {
|
||||||
|
try {
|
||||||
|
connection.query(
|
||||||
|
`SELECT * FROM ${DATABASE_NAME}.response WHERE number = '${number}'`, (error, results) => {
|
||||||
|
if(error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
const [response] = results;
|
||||||
|
console.log(response)
|
||||||
|
const value = {
|
||||||
|
replyMessage:response?.replyMessage || '',
|
||||||
|
trigger:response?.trigger || '',
|
||||||
|
media:response?.media || ''
|
||||||
|
}
|
||||||
|
resolve(value)
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
saveMessageMysql = ( message, date, trigger, number ) => new Promise((resolve,reejct) => {
|
||||||
|
try {
|
||||||
|
connection.query(
|
||||||
|
`INSERT INTO ${DATABASE_NAME}.messages `+"( `message`, `date`, `trigger`, `number`)"+` VALUES ('${message}','${date}','${trigger}', '${number}')` , (error, results) => {
|
||||||
|
if(error) {
|
||||||
|
//TODO esta parte es mejor incluirla directamente en el archivo .sql template
|
||||||
|
console.log('DEBES DE CREAR LA TABLA DE MESSAGE')
|
||||||
|
// if( error.code === 'ER_NO_SUCH_TABLE' ){
|
||||||
|
// connection.query( `CREATE TABLE ${DATABASE_NAME}.messages `+"( `date` DATE NOT NULL , `message` VARCHAR(450) NOT NULL , `trigger` VARCHAR(450) NOT NULL , `number` VARCHAR(50) NOT NULL ) ENGINE = InnoDB", async (error, results) => {
|
||||||
|
// setTimeout( async () => {
|
||||||
|
// return resolve( await this.saveMessageMysql( message, date, trigger, number ) )
|
||||||
|
// }, 150)
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
console.log('Saved')
|
||||||
|
console.log( results )
|
||||||
|
resolve(results)
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = {getData, getReply, saveMessageMysql}
|
||||||
118
app.js
118
app.js
@@ -6,10 +6,10 @@ const fs = require('fs');
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const cors = require('cors')
|
const cors = require('cors')
|
||||||
const qrcode = require('qrcode-terminal');
|
const qrcode = require('qrcode-terminal');
|
||||||
const { Client } = require('whatsapp-web.js');
|
const { Client, LocalAuth } = require('whatsapp-web.js');
|
||||||
const mysqlConnection = require('./config/mysql')
|
const mysqlConnection = require('./config/mysql')
|
||||||
const { middlewareClient } = require('./middleware/client')
|
const { middlewareClient } = require('./middleware/client')
|
||||||
const { generateImage, cleanNumber } = require('./controllers/handle')
|
const { generateImage, cleanNumber, checkEnvFile, createClient, isValidNumber } = require('./controllers/handle')
|
||||||
const { connectionReady, connectionLost } = require('./controllers/connection')
|
const { connectionReady, connectionLost } = require('./controllers/connection')
|
||||||
const { saveMedia } = require('./controllers/save')
|
const { saveMedia } = require('./controllers/save')
|
||||||
const { getMessages, responseMessages, bothResponse } = require('./controllers/flows')
|
const { getMessages, responseMessages, bothResponse } = require('./controllers/flows')
|
||||||
@@ -17,35 +17,23 @@ const { sendMedia, sendMessage, lastTrigger, sendMessageButton, readChat } = req
|
|||||||
const app = express();
|
const app = express();
|
||||||
app.use(cors())
|
app.use(cors())
|
||||||
app.use(express.json())
|
app.use(express.json())
|
||||||
|
const MULTI_DEVICE = process.env.MULTI_DEVICE || 'true';
|
||||||
const server = require('http').Server(app)
|
const server = require('http').Server(app)
|
||||||
const io = require('socket.io')(server, {
|
|
||||||
cors: {
|
|
||||||
origins: ['http://localhost:4200']
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let socketEvents = {sendQR:() => {} ,sendStatus:() => {}};
|
|
||||||
|
|
||||||
io.on('connection', (socket) => {
|
|
||||||
const CHANNEL = 'main-channel';
|
|
||||||
socket.join(CHANNEL);
|
|
||||||
socketEvents = require('./controllers/socket')(socket)
|
|
||||||
console.log('Se conecto')
|
|
||||||
})
|
|
||||||
|
|
||||||
app.use('/', require('./routes/web'))
|
|
||||||
|
|
||||||
const port = process.env.PORT || 3000
|
const port = process.env.PORT || 3000
|
||||||
const SESSION_FILE_PATH = './session.json';
|
|
||||||
var client;
|
var client;
|
||||||
var sessionData;
|
app.use('/', require('./routes/web'))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Escuchamos cuando entre un mensaje
|
* Escuchamos cuando entre un mensaje
|
||||||
*/
|
*/
|
||||||
const listenMessage = () => client.on('message', async msg => {
|
const listenMessage = () => client.on('message', async msg => {
|
||||||
const { from, body, hasMedia } = msg;
|
const { from, body, hasMedia } = msg;
|
||||||
|
|
||||||
|
if (!isValidNumber(from)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Este bug lo reporto Lucas Aldeco Brescia para evitar que se publiquen estados
|
// Este bug lo reporto Lucas Aldeco Brescia para evitar que se publiquen estados
|
||||||
if (from === 'status@broadcast') {
|
if (from === 'status@broadcast') {
|
||||||
return
|
return
|
||||||
@@ -54,6 +42,7 @@ const listenMessage = () => client.on('message', async msg => {
|
|||||||
console.log('BODY', message)
|
console.log('BODY', message)
|
||||||
const number = cleanNumber(from)
|
const number = cleanNumber(from)
|
||||||
await readChat(number, message)
|
await readChat(number, message)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Guardamos el archivo multimedia que envia
|
* Guardamos el archivo multimedia que envia
|
||||||
*/
|
*/
|
||||||
@@ -67,7 +56,8 @@ const listenMessage = () => client.on('message', async msg => {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (process.env.DATABASE === 'dialogflow') {
|
if (process.env.DATABASE === 'dialogflow') {
|
||||||
const response = await bothResponse(message);
|
if (!message.length) return;
|
||||||
|
const response = await bothResponse(message, number);
|
||||||
await sendMessage(client, from, response.replyMessage);
|
await sendMessage(client, from, response.replyMessage);
|
||||||
if (response.media) {
|
if (response.media) {
|
||||||
sendMedia(client, from, response.media);
|
sendMedia(client, from, response.media);
|
||||||
@@ -82,7 +72,6 @@ const listenMessage = () => client.on('message', async msg => {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const lastStep = await lastTrigger(from) || null;
|
const lastStep = await lastTrigger(from) || null;
|
||||||
console.log({ lastStep })
|
|
||||||
if (lastStep) {
|
if (lastStep) {
|
||||||
const response = await responseMessages(lastStep)
|
const response = await responseMessages(lastStep)
|
||||||
await sendMessage(client, from, response.replyMessage);
|
await sendMessage(client, from, response.replyMessage);
|
||||||
@@ -92,12 +81,21 @@ const listenMessage = () => client.on('message', async msg => {
|
|||||||
* Respondemos al primero paso si encuentra palabras clave
|
* Respondemos al primero paso si encuentra palabras clave
|
||||||
*/
|
*/
|
||||||
const step = await getMessages(message);
|
const step = await getMessages(message);
|
||||||
console.log({ step })
|
|
||||||
|
|
||||||
if (step) {
|
if (step) {
|
||||||
const response = await responseMessages(step)
|
const response = await responseMessages(step);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Si quieres enviar botones
|
||||||
|
*/
|
||||||
|
|
||||||
await sendMessage(client, from, response.replyMessage, response.trigger);
|
await sendMessage(client, from, response.replyMessage, response.trigger);
|
||||||
|
|
||||||
|
if (response.hasOwnProperty('actions')) {
|
||||||
|
const { actions } = response;
|
||||||
|
await sendMessageButton(client, from, null, actions);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!response.delay && response.media) {
|
if (!response.delay && response.media) {
|
||||||
sendMedia(client, from, response.media);
|
sendMedia(client, from, response.media);
|
||||||
@@ -126,51 +124,16 @@ const listenMessage = () => client.on('message', async msg => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Revisamos si tenemos credenciales guardadas para inciar sessio
|
|
||||||
* este paso evita volver a escanear el QRCODE
|
|
||||||
*/
|
|
||||||
const withSession = () => {
|
|
||||||
// Si exsite cargamos el archivo con las credenciales
|
|
||||||
console.log(`Validando session con Whatsapp...`)
|
|
||||||
sessionData = require(SESSION_FILE_PATH);
|
|
||||||
client = new Client({
|
|
||||||
session: sessionData,
|
|
||||||
puppeteer: {
|
|
||||||
args: [
|
|
||||||
'--no-sandbox'
|
|
||||||
],
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('ready', () => {
|
|
||||||
connectionReady()
|
|
||||||
listenMessage()
|
|
||||||
loadRoutes(client);
|
|
||||||
socketEvents.sendStatus()
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('auth_failure', () => connectionLost())
|
|
||||||
|
|
||||||
client.initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generamos un QRCODE para iniciar sesion
|
|
||||||
*/
|
|
||||||
const withOutSession = () => {
|
|
||||||
console.log('No tenemos session guardada');
|
|
||||||
|
|
||||||
client = new Client({
|
client = new Client({
|
||||||
puppeteer: {
|
authStrategy: new LocalAuth(),
|
||||||
args: [
|
puppeteer: { headless: true }
|
||||||
'--no-sandbox'
|
|
||||||
],
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('qr', qr => generateImage(qr, () => {
|
client.on('qr', qr => generateImage(qr, () => {
|
||||||
qrcode.generate(qr, { small: true });
|
qrcode.generate(qr, { small: true });
|
||||||
|
|
||||||
console.log(`Ver QR http://localhost:${port}/qr`)
|
console.log(`Ver QR http://localhost:${port}/qr`)
|
||||||
socketEvents.sendQR(qr)
|
socketEvents.sendQR(qr)
|
||||||
}))
|
}))
|
||||||
@@ -178,35 +141,21 @@ const withOutSession = () => {
|
|||||||
client.on('ready', (a) => {
|
client.on('ready', (a) => {
|
||||||
connectionReady()
|
connectionReady()
|
||||||
listenMessage()
|
listenMessage()
|
||||||
loadRoutes(client);
|
|
||||||
// socketEvents.sendStatus(client)
|
// socketEvents.sendStatus(client)
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('auth_failure', () => connectionLost());
|
client.on('auth_failure', (e) => {
|
||||||
|
// console.log(e)
|
||||||
client.on('authenticated', (session) => {
|
// connectionLost()
|
||||||
sessionData = session;
|
|
||||||
fs.writeFile(SESSION_FILE_PATH, JSON.stringify(session), function (err) {
|
|
||||||
if (err) {
|
|
||||||
console.log(`Ocurrio un error con el archivo: `, err);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
client.on('authenticated', () => {
|
||||||
|
console.log('AUTHENTICATED');
|
||||||
});
|
});
|
||||||
|
|
||||||
client.initialize();
|
client.initialize();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cargamos rutas de express
|
|
||||||
*/
|
|
||||||
|
|
||||||
const loadRoutes = (client) => {
|
|
||||||
app.use('/api/', middlewareClient(client), require('./routes/api'))
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Revisamos si existe archivo con credenciales!
|
|
||||||
*/
|
|
||||||
(fs.existsSync(SESSION_FILE_PATH)) ? withSession() : withOutSession();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verificamos si tienes un gesto de db
|
* Verificamos si tienes un gesto de db
|
||||||
@@ -219,5 +168,4 @@ if (process.env.DATABASE === 'mysql') {
|
|||||||
server.listen(port, () => {
|
server.listen(port, () => {
|
||||||
console.log(`El server esta listo por el puerto ${port}`);
|
console.log(`El server esta listo por el puerto ${port}`);
|
||||||
})
|
})
|
||||||
|
checkEnvFile();
|
||||||
|
|
||||||
Binary file not shown.
@@ -1,9 +1,9 @@
|
|||||||
const mysql = require('mysql');
|
const mysql = require('mysql');
|
||||||
const connection = mysql.createConnection({
|
const connection = mysql.createConnection({
|
||||||
host : process.env.SQL_HOST || 'localhost',
|
host : process.env.SQL_HOST || 'localhost',
|
||||||
user : process.env.SQL_USER || 'me',
|
user : process.env.SQL_USER || 'root',
|
||||||
password : process.env.SQL_PASS || 'secret',
|
password : process.env.SQL_PASS || '',
|
||||||
database : process.env.SQL_DATABASE || 'my_db'
|
database : process.env.SQL_DATABASE || 'pruebas'
|
||||||
});
|
});
|
||||||
|
|
||||||
const connect = () => connection.connect(function(err) {
|
const connect = () => connection.connect(function(err) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const connectionReady = (cb = () =>{}) => {
|
const connectionReady = (cb = () =>{}) => {
|
||||||
console.log('Listo para escuchas mensajes')
|
console.log('Listo para escuchas mensajes')
|
||||||
console.log('Client is ready!');
|
console.log('Client is ready!');
|
||||||
|
console.log('🔴 escribe: hola');
|
||||||
cb()
|
cb()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const {get, reply, getIA} = require('../adapter')
|
const {get, reply, getIA} = require('../adapter')
|
||||||
const {saveExternalFile} = require('./handle')
|
const {saveExternalFile, checkIsUrl} = require('./handle')
|
||||||
|
|
||||||
const getMessages = async (message) => {
|
const getMessages = async (message) => {
|
||||||
const data = await get(message)
|
const data = await get(message)
|
||||||
@@ -9,14 +9,14 @@ const getMessages = async (message) => {
|
|||||||
const responseMessages = async (step) => {
|
const responseMessages = async (step) => {
|
||||||
const data = await reply(step)
|
const data = await reply(step)
|
||||||
if(data && data.media){
|
if(data && data.media){
|
||||||
const file = await saveExternalFile(data.media)
|
const file = checkIsUrl(data.media) ? await saveExternalFile(data.media) : data.media;
|
||||||
return {...data,...{media:file}}
|
return {...data,...{media:file}}
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
const bothResponse = async (message) => {
|
const bothResponse = async (message, sessionId) => {
|
||||||
const data = await getIA(message)
|
const data = await getIA(message, sessionId)
|
||||||
if(data && data.media){
|
if(data && data.media){
|
||||||
const file = await saveExternalFile(data.media)
|
const file = await saveExternalFile(data.media)
|
||||||
return {...data,...{media:file}}
|
return {...data,...{media:file}}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
const { Client, LegacySessionAuth, LocalAuth } = require('whatsapp-web.js');
|
||||||
const http = require('http'); // or 'https' for https:// URLs
|
const http = require('http'); // or 'https' for https:// URLs
|
||||||
const https = require('https'); // or 'https' for https:// URLs
|
const https = require('https'); // or 'https' for https:// URLs
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const qr = require('qr-image')
|
const qr = require('qr-image')
|
||||||
|
|
||||||
|
const MULTI_DEVICE = process.env.MULTI_DEVICE || 'true';
|
||||||
|
|
||||||
const cleanNumber = (number) => {
|
const cleanNumber = (number) => {
|
||||||
number = number.replace('@c.us', '');
|
number = number.replace('@c.us', '');
|
||||||
@@ -31,6 +33,16 @@ const saveExternalFile = (url) => new Promise((resolve, reject) => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const checkIsUrl = (path) => {
|
||||||
|
try{
|
||||||
|
regex = /^(http(s)?:\/\/)[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$/i;
|
||||||
|
match = path.match(regex);
|
||||||
|
return match[0]
|
||||||
|
}catch(e){
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const generateImage = (base64, cb = () => {}) => {
|
const generateImage = (base64, cb = () => {}) => {
|
||||||
let qr_svg = qr.image(base64, { type: 'svg', margin: 4 });
|
let qr_svg = qr.image(base64, { type: 'svg', margin: 4 });
|
||||||
qr_svg.pipe(require('fs').createWriteStream('./mediaSend/qr-code.svg'));
|
qr_svg.pipe(require('fs').createWriteStream('./mediaSend/qr-code.svg'));
|
||||||
@@ -39,4 +51,33 @@ const generateImage = (base64, cb = () => {}) => {
|
|||||||
cb()
|
cb()
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {cleanNumber, saveExternalFile, generateImage}
|
const checkEnvFile = () => {
|
||||||
|
const pathEnv = `${__dirname}/../.env`;
|
||||||
|
const isExist = fs.existsSync(pathEnv);
|
||||||
|
if(!isExist){
|
||||||
|
console.log(`🆗 ATENCION! 🆗 te falta crear tu archivo .env de lo contrario no funcionara`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} session
|
||||||
|
* @param {*} cb
|
||||||
|
*/
|
||||||
|
const createClient = () => {
|
||||||
|
client = new Client({
|
||||||
|
authStrategy: new LocalAuth(
|
||||||
|
{dataPath: './sessions/',
|
||||||
|
clientId: 'bot'}),
|
||||||
|
puppeteer: { headless: false }
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValidNumber = (rawNumber) => {
|
||||||
|
const regexGroup = /\@g.us\b/gm;
|
||||||
|
const exist = rawNumber.match(regexGroup);
|
||||||
|
return !exist
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {cleanNumber, saveExternalFile, generateImage, checkIsUrl, checkEnvFile, createClient, isValidNumber}
|
||||||
@@ -4,32 +4,64 @@ const moment = require('moment');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { MessageMedia, Buttons } = require('whatsapp-web.js');
|
const { MessageMedia, Buttons } = require('whatsapp-web.js');
|
||||||
const { cleanNumber } = require('./handle')
|
const { cleanNumber } = require('./handle')
|
||||||
const { saveMedia } = require('../controllers/save')
|
const DELAY_TIME = 170; //ms
|
||||||
|
const DIR_MEDIA = `${__dirname}/../mediaSend`;
|
||||||
|
// import { Low, JSONFile } from 'lowdb'
|
||||||
|
// import { join } from 'path'
|
||||||
|
const { saveMessage } = require('../adapter')
|
||||||
/**
|
/**
|
||||||
* Enviamos archivos multimedia a nuestro cliente
|
* Enviamos archivos multimedia a nuestro cliente
|
||||||
* @param {*} number
|
* @param {*} number
|
||||||
* @param {*} fileName
|
* @param {*} fileName
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const sendMedia = (client, number, fileName) => {
|
const sendMedia = (client, number = null, fileName = null) => {
|
||||||
const dirMedia = `${__dirname}/../mediaSend/${fileName}`;
|
if(!client) return cosnole.error("El objeto cliente no está definido.");
|
||||||
number = cleanNumber(number)
|
try {
|
||||||
if (fs.existsSync(dirMedia)) {
|
number = cleanNumber(number || 0)
|
||||||
const media = MessageMedia.fromFilePath(dirMedia);
|
const file = `${DIR_MEDIA}/${fileName}`;
|
||||||
client.sendMessage(number, media);
|
if (fs.existsSync(file)) {
|
||||||
|
const media = MessageMedia.fromFilePath(file);
|
||||||
|
client.sendMessage(number, media, { sendAudioAsVoice: true });
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enviamos archivos como notas de voz
|
||||||
|
* @param {*} number
|
||||||
|
* @param {*} fileName
|
||||||
|
*/
|
||||||
|
|
||||||
|
const sendMediaVoiceNote = (client, number = null, fileName = null) => {
|
||||||
|
if(!client) return cosnole.error("El objeto cliente no está definido.");
|
||||||
|
try {
|
||||||
|
number = cleanNumber(number || 0)
|
||||||
|
const file = `${DIR_MEDIA}/${fileName}`;
|
||||||
|
if (fs.existsSync(file)) {
|
||||||
|
const media = MessageMedia.fromFilePath(file);
|
||||||
|
client.sendMessage(number, media ,{ sendAudioAsVoice: true });
|
||||||
|
|
||||||
|
}
|
||||||
|
}catch(e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Enviamos un mensaje simple (texto) a nuestro cliente
|
* Enviamos un mensaje simple (texto) a nuestro cliente
|
||||||
* @param {*} number
|
* @param {*} number
|
||||||
*/
|
*/
|
||||||
const sendMessage = async (client, number = null, text = null, trigger = null) => {
|
const sendMessage = async (client, number = null, text = null, trigger = null) => {
|
||||||
|
setTimeout(async () => {
|
||||||
number = cleanNumber(number)
|
number = cleanNumber(number)
|
||||||
const message = text
|
const message = text
|
||||||
client.sendMessage(number, message);
|
client.sendMessage(number, message);
|
||||||
await readChat(number, message, trigger)
|
await readChat(number, message, trigger)
|
||||||
console.log(`⚡⚡⚡ Enviando mensajes....`);
|
console.log(`⚡⚡⚡ Enviando mensajes....`);
|
||||||
|
},DELAY_TIME)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,49 +105,9 @@ const lastTrigger = (number) => new Promise((resolve, reject) => {
|
|||||||
* @param {*} message
|
* @param {*} message
|
||||||
*/
|
*/
|
||||||
const readChat = async (number, message, trigger = null) => {
|
const readChat = async (number, message, trigger = null) => {
|
||||||
setTimeout(() => {
|
number = cleanNumber(number)
|
||||||
const pathExcel = `${__dirname}/../chats/${number}.xlsx`;
|
await saveMessage( message, trigger, number )
|
||||||
const workbook = new ExcelJS.Workbook();
|
console.log('Saved')
|
||||||
const today = moment().format('DD-MM-YYYY hh:mm')
|
|
||||||
|
|
||||||
if (fs.existsSync(pathExcel)) {
|
|
||||||
/**
|
|
||||||
* Si existe el archivo de conversacion lo actualizamos
|
|
||||||
*/
|
|
||||||
const workbook = new ExcelJS.Workbook();
|
|
||||||
workbook.xlsx.readFile(pathExcel)
|
|
||||||
.then(() => {
|
|
||||||
const worksheet = workbook.getWorksheet(1);
|
|
||||||
const lastRow = worksheet.lastRow;
|
|
||||||
var getRowInsert = worksheet.getRow(++(lastRow.number));
|
|
||||||
getRowInsert.getCell('A').value = today;
|
|
||||||
getRowInsert.getCell('B').value = message;
|
|
||||||
getRowInsert.getCell('C').value = trigger;
|
|
||||||
getRowInsert.commit();
|
|
||||||
workbook.xlsx.writeFile(pathExcel);
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/**
|
|
||||||
* NO existe el archivo de conversacion lo creamos
|
|
||||||
*/
|
|
||||||
const worksheet = workbook.addWorksheet('Chats');
|
|
||||||
worksheet.columns = [
|
|
||||||
{ header: 'Fecha', key: 'number_customer' },
|
|
||||||
{ header: 'Mensajes', key: 'message' },
|
|
||||||
{ header: 'Disparador', key: 'trigger' }
|
|
||||||
];
|
|
||||||
worksheet.addRow([today, message, trigger]);
|
|
||||||
workbook.xlsx.writeFile(pathExcel)
|
|
||||||
.then(() => {
|
|
||||||
|
|
||||||
console.log("saved");
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log("err", err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, 900)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { sendMessage, sendMedia, lastTrigger, sendMessageButton, readChat }
|
module.exports = { sendMessage, sendMedia, lastTrigger, sendMessageButton, readChat, sendMediaVoiceNote }
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const fs = require('fs')
|
|||||||
const { sendMessage } = require('../controllers/send')
|
const { sendMessage } = require('../controllers/send')
|
||||||
|
|
||||||
const sendMessagePost = (req, res) => {
|
const sendMessagePost = (req, res) => {
|
||||||
|
console.log('asdasdasdasdasd')
|
||||||
const { message, number } = req.body
|
const { message, number } = req.body
|
||||||
const client = req.clientWs || null;
|
const client = req.clientWs || null;
|
||||||
sendMessage(client, number, message)
|
sendMessage(client, number, message)
|
||||||
|
|||||||
@@ -21,8 +21,7 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"cursos",
|
"cursos",
|
||||||
"info",
|
"info",
|
||||||
"curso"
|
"curso" ],
|
||||||
],
|
|
||||||
"key": "STEP_2"
|
"key": "STEP_2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -69,20 +68,26 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"👉 Youtube"
|
"youtube"
|
||||||
],
|
],
|
||||||
"key": "STEP_5"
|
"key": "STEP_5"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"😎 Cursos"
|
"VER_CURSOS"
|
||||||
],
|
],
|
||||||
"key": "STEP_6"
|
"key": "STEP_6"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"😁 Telegram"
|
"telegram"
|
||||||
],
|
],
|
||||||
"key": "STEP_7"
|
"key": "STEP_7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keywords": [
|
||||||
|
"audio"
|
||||||
|
],
|
||||||
|
"key": "STEP_8"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -1,21 +1,15 @@
|
|||||||
{
|
{
|
||||||
"DEFAULT":{
|
"DEFAULT":{
|
||||||
"replyMessage":[
|
"replyMessage":[
|
||||||
"🆗 Bienvenido a este 🤖 CHATBOT de Whatsapp, lo primero \n",
|
"*Esta respuesta es un respuesta default* cuando no se consigue una palabra clave \n",
|
||||||
"decirte que mi nombre es *Leifer Mendez*😎 y te dejo opciones rapidas \n"
|
"la puedes desactivar en tu archivo .env DEFAULT_MESSAGE=false \n",
|
||||||
|
"tambien te quiero recordar que si presentas algun error pasarte por el repositorio \n",
|
||||||
|
"https://github.com/leifermendez/bot-whatsapp#chatbot-whatsapp-opensource \n",
|
||||||
|
"y recuerda tener la ultima versión del proyecto \n\n",
|
||||||
|
"Prueba escribiendo *hola* \n"
|
||||||
],
|
],
|
||||||
"media":null,
|
"media":null,
|
||||||
"trigger":null,
|
"trigger":null
|
||||||
"actions":{
|
|
||||||
"title":"¿Que te interesa ver?",
|
|
||||||
"message":"Recuerda todo este contenido es gratis y estaria genial que me siguas!",
|
|
||||||
"footer":"Gracias",
|
|
||||||
"buttons":[
|
|
||||||
{"body":"😎 Cursos"},
|
|
||||||
{"body":"👉 Youtube"},
|
|
||||||
{"body":"😁 Telegram"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"STEP_0":{
|
"STEP_0":{
|
||||||
"replyMessage":[
|
"replyMessage":[
|
||||||
@@ -28,13 +22,23 @@
|
|||||||
},
|
},
|
||||||
"STEP_1":{
|
"STEP_1":{
|
||||||
"replyMessage":[
|
"replyMessage":[
|
||||||
"✌️ Bienvenido a este 🤖 CHATBOT de Whatsapp, lo primero \n",
|
"Hola! y✌️ Bienvenido a este 🤖 CHATBOT de Whatsapp, lo primero \n",
|
||||||
"decirte que mi nombre es *Leifer Mendez*😎 \n",
|
"decirte que mi nombre es *Leifer Mendez*😎 \n",
|
||||||
"\n Si necesitas ver más info sobre las capacitacion tecnicas ",
|
"\n Si necesitas ver más info sobre las capacitacion tecnicas ",
|
||||||
"escribe *cursos* o *info*"
|
"escribe *cursos* o *info* o escribe *audio*"
|
||||||
],
|
],
|
||||||
"media":null,
|
"media":"https://media2.giphy.com/media/VQJu0IeULuAmCwf5SL/giphy.gif",
|
||||||
"trigger":null
|
"trigger":null,
|
||||||
|
"actions":{
|
||||||
|
"title":"¿Que te interesa ver?",
|
||||||
|
"message":"Recuerda todo este contenido es gratis y estaria genial que me siguas!",
|
||||||
|
"footer":"Gracias",
|
||||||
|
"buttons":[
|
||||||
|
{"body":"Cursos"},
|
||||||
|
{"body":"Youtube"},
|
||||||
|
{"body":"Telegram"}
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"STEP_2":{
|
"STEP_2":{
|
||||||
"replyMessage":[
|
"replyMessage":[
|
||||||
@@ -106,9 +110,10 @@
|
|||||||
},
|
},
|
||||||
"STEP_5":{
|
"STEP_5":{
|
||||||
"replyMessage":[
|
"replyMessage":[
|
||||||
"Muy bien te comparto el canal de Youtube \n"
|
"Muy bien te comparto el canal de Youtube \n",
|
||||||
|
"https://youtube.com/leifermendez \n"
|
||||||
],
|
],
|
||||||
"media":"https://youtube.com/leifermendez",
|
"media":null,
|
||||||
"trigger":null
|
"trigger":null
|
||||||
},
|
},
|
||||||
"STEP_6":{
|
"STEP_6":{
|
||||||
@@ -127,9 +132,17 @@
|
|||||||
},
|
},
|
||||||
"STEP_7":{
|
"STEP_7":{
|
||||||
"replyMessage":[
|
"replyMessage":[
|
||||||
"Vente al telegram \n"
|
"Vente al telegram \n",
|
||||||
|
"https://t.me/leifermendez \n"
|
||||||
],
|
],
|
||||||
"media":"https://t.me/leifermendez",
|
"media":null,
|
||||||
|
"trigger":null
|
||||||
|
},
|
||||||
|
"STEP_8":{
|
||||||
|
"replyMessage":[
|
||||||
|
"Esto es una nota de voz \n"
|
||||||
|
],
|
||||||
|
"media":"nota-de-voz.mp3",
|
||||||
"trigger":null
|
"trigger":null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
mediaSend/PTT-20220223-WA0000.opus
Normal file
BIN
mediaSend/PTT-20220223-WA0000.opus
Normal file
Binary file not shown.
BIN
mediaSend/nota-de-voz.mp3
Normal file
BIN
mediaSend/nota-de-voz.mp3
Normal file
Binary file not shown.
0
middleware/db.js
Normal file
0
middleware/db.js
Normal file
7661
package-lock.json
generated
7661
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
53
package.json
53
package.json
@@ -1,37 +1,56 @@
|
|||||||
{
|
{
|
||||||
"name": "test-ws-bot",
|
"name": "bot-whatsapp",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "Bot de wahtsapp open source para MVP o pequeños negocios",
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node ./app.js",
|
"start": "node ./app.js",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [
|
||||||
"author": "",
|
"whatsapp",
|
||||||
|
"bot-whatsapp",
|
||||||
|
"node-bot-whatsapp"
|
||||||
|
],
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"email": "leifer33@gmail.com",
|
||||||
|
"name": "Leifer Mendez",
|
||||||
|
"url": "https://leifermendez.github.io"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "aurik3",
|
||||||
|
"email": "aurik3@aurik3.com",
|
||||||
|
"url": "https://github.com/aurik3"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/leifermendez/bot-whatsapp"
|
||||||
|
},
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google-cloud/dialogflow": "^4.6.0",
|
"@google-cloud/dialogflow": "^5.2.0",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^11.0.0",
|
"dotenv": "^16.0.1",
|
||||||
"exceljs": "^4.3.0",
|
"exceljs": "^4.3.0",
|
||||||
"express": "^4.17.2",
|
"express": "^4.18.1",
|
||||||
"file-type": "^16.5.3",
|
"file-type": "^17.1.6",
|
||||||
"mime-db": "^1.51.0",
|
"mime-db": "^1.52.0",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.4",
|
||||||
"mysql": "^2.18.1",
|
"mysql": "^2.18.1",
|
||||||
"nanoid": "^3.1.32",
|
|
||||||
"qr-image": "^3.2.0",
|
"qr-image": "^3.2.0",
|
||||||
"qrcode-terminal": "^0.12.0",
|
"qrcode-terminal": "^0.12.0",
|
||||||
"socket.io": "^4.4.1",
|
"socket.io": "^4.5.1",
|
||||||
"whatsapp-web.js": "^1.15.4",
|
"stormdb": "^0.6.0",
|
||||||
"xlsx": "^0.16.9"
|
"whatsapp-web.js": "^1.18.4",
|
||||||
|
"xlsx": "^0.18.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"pm2": "^5.1.2",
|
"pm2": "^5.2.0",
|
||||||
"prettier": "2.5.1"
|
"prettier": "2.7.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "14.x"
|
"node": "16.x"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const express = require('express')
|
const express = require('express')
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const { sendMessagePost } = require('../controllers/web')
|
const { sendMessagePost } = require('../controllers/web')|
|
||||||
|
|
||||||
router.post('/send', sendMessagePost)
|
router.post('/send', sendMessagePost)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user