mirror of
https://github.com/cheveguerra/botLeiferAurik-Mod_2.0.git
synced 2026-04-17 19:36:17 +00:00
Commit inicial
This commit is contained in:
13
.env.example
Normal file
13
.env.example
Normal file
@@ -0,0 +1,13 @@
|
||||
######DATABASE: none, mysql, dialogflow
|
||||
|
||||
DEFAULT_MESSAGE=true
|
||||
SAVE_MEDIA=true
|
||||
PORT=3000
|
||||
DATABASE=none
|
||||
LANGUAGE=es
|
||||
SQL_HOST=
|
||||
SQL_USER=
|
||||
SQL_PASS=
|
||||
SQL_DATABASE=
|
||||
KEEP_DIALOG_FLOW=false
|
||||
MULTI_DEVICE=true
|
||||
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/node_modules
|
||||
/node_modules/*
|
||||
session.json
|
||||
chats/*
|
||||
!chats/.gitkeep
|
||||
media/*
|
||||
!media/.gitkeep
|
||||
mediaSend/*
|
||||
!mediaSend/.gitkeep
|
||||
!mediaSend/nota-de-voz.mp3
|
||||
.env
|
||||
.wwebjs_auth
|
||||
1
.prettierrc.json
Normal file
1
.prettierrc.json
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
14
CHANGELOG.md
Normal file
14
CHANGELOG.md
Normal file
@@ -0,0 +1,14 @@
|
||||
#### Actualización 14 Ene 2022
|
||||
- npm update
|
||||
- remove ora and chalk
|
||||
- add env
|
||||
- add mysql
|
||||
- add dialogflow
|
||||
- add scan qr from webpage
|
||||
- update route with middleware
|
||||
- fix send message to story
|
||||
- external download
|
||||
- easy deploy heroku
|
||||
- add support for ubuntu/linux
|
||||
|
||||
https://stackoverflow.com/questions/51855169/dialogflow-403-iam-permission-dialogflow-sessions-detectintent
|
||||
155
README.md
Normal file
155
README.md
Normal file
@@ -0,0 +1,155 @@
|
||||
## Chatbot Whatsapp (OpenSource)
|
||||
#### Actualizado Septiembre 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)
|
||||
|
||||
### ATENCION 🔴
|
||||
> 💥💥 Si te aparece el Error Multi-device es porque tienes la cuenta de whatsapp afiliada al modo "BETA de Multi dispositivo" por el momento no se tiene soporte para esas personas si tu quieres hacer uso de este __BOT__ debes de salir del modo BETA y intentarlo de la manera tradicional
|
||||
|
||||
> El core de whatsapp esta en constante actualizaciones por lo cual siempre revisa la ultima fecha de la actualizacion
|
||||
> [VER](https://github.com/leifermendez/bot-whatsapp/commits/main)
|
||||
|
||||
### Busco colaboradores ⭐
|
||||
Hola amigos me gusta mucho este proyecto pero por cuestiones de tiempo se me dificulta mantener las actualizaciones si alguno quieres participar en el proyecto escribeme a leifer.contacto@gmail.com
|
||||
|
||||
#### 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-whatsapp)
|
||||
|
||||
> Comprarme un cafe!
|
||||
|
||||
[](https://www.buymeacoffee.com/leifermendez)
|
||||
|
||||
#### Actualización
|
||||
|
||||
| Feature | Status |
|
||||
| ------------- | ------------- |
|
||||
| Dialogflow | ✅ |
|
||||
| MySQL | ✅ |
|
||||
| JSON File | ✅ |
|
||||
| QR Scan (route) | ✅ |
|
||||
| Easy deploy heroku | ✅ |
|
||||
| Buttons | ✅ℹ️ (No funciona en multi-device)|
|
||||
| Send Voice Note | ✅ |
|
||||
| Add support ubuntu/linux | ✅ |
|
||||
|
||||
## Requisitos
|
||||
- node v14 o superior
|
||||
- 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)
|
||||
- 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
|
||||
__Descargar o Clonar repositorio__
|
||||

|
||||
|
||||
__Usas ¿Ubuntu / Linux?__
|
||||
> Asegurate de instalar los siguientes paquetes
|
||||
```
|
||||
sudo apt-get install -y libgbm-dev
|
||||
sudo apt install -y gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
|
||||
```
|
||||
|
||||
__Instalar dependencias (npm install)__
|
||||
> Ubicate en le directorio que descargaste y via consola o terminal ejecuta el siguiente comando
|
||||
|
||||
`npm install`
|
||||
|
||||

|
||||
|
||||
__Configurar .env__
|
||||
> Con el editor de texto crea un archivo `.env` el cual debes de guiarte del archivo `.env.example`
|
||||
[Ver video explicando](https://youtu.be/5lEMCeWEJ8o?t=381)
|
||||
```
|
||||
######DATABASE: none, mysql, dialogflow
|
||||
|
||||
DEFAULT_MESSAGE=true
|
||||
SAVE_MEDIA=true
|
||||
PORT=3000
|
||||
DATABASE=none
|
||||
LANGUAGE=es
|
||||
SQL_HOST=
|
||||
SQL_USER=
|
||||
SQL_PASS=
|
||||
SQL_DATABASE=
|
||||
```
|
||||
|
||||

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

|
||||
|
||||
__Whatsapp en tu celular__
|
||||
> 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" />
|
||||
Visitar la pagina
|
||||
`http://localhost:3000/qr`
|
||||
|
||||

|
||||
|
||||
__Listo 😎__
|
||||
> Cuando sale este mensaje tu BOT está __listo__ para trabajar!
|
||||

|
||||
|
||||
# ¿Quieres ver como se creó? 🤖
|
||||
- [Ver Video 1](https://www.youtube.com/watch?v=A_Xu0OR_HkE)
|
||||
- [¿Como instalarlo? (Actulización)](https://youtu.be/5lEMCeWEJ8o)
|
||||
|
||||
## ¿Como usarlo el chatbot de whatsapp?
|
||||
> Escribe un mensaje al whatsapp que vinculaste con tu BOT
|
||||
|
||||

|
||||
|
||||
> 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
|
||||
|
||||

|
||||

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

|
||||
1
Whatsapp-Bot.ps1
Normal file
1
Whatsapp-Bot.ps1
Normal file
@@ -0,0 +1 @@
|
||||
npm start
|
||||
77
adapter/diaglogflow.js
Normal file
77
adapter/diaglogflow.js
Normal file
@@ -0,0 +1,77 @@
|
||||
const dialogflow = require('@google-cloud/dialogflow');
|
||||
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
|
||||
*/
|
||||
|
||||
const KEEP_DIALOG_FLOW = (process.env.KEEP_DIALOG_FLOW === 'true')
|
||||
let PROJECID;
|
||||
let CONFIGURATION;
|
||||
let sessionClient;
|
||||
|
||||
const checkFileCredentials = () => {
|
||||
if(!fs.existsSync(`${__dirname}/../chatbot-account.json`)){
|
||||
return false
|
||||
}
|
||||
|
||||
const parseCredentials = JSON.parse(fs.readFileSync(`${__dirname}/../chatbot-account.json`));
|
||||
PROJECID = parseCredentials.project_id;
|
||||
CONFIGURATION = {
|
||||
credentials: {
|
||||
private_key: parseCredentials['private_key'],
|
||||
client_email: parseCredentials['client_email']
|
||||
}
|
||||
}
|
||||
sessionClient = new dialogflow.SessionsClient(CONFIGURATION);
|
||||
}
|
||||
|
||||
// Create a new session
|
||||
|
||||
|
||||
// Detect intent method
|
||||
const detectIntent = async (queryText) => {
|
||||
let media = null;
|
||||
const sessionId = KEEP_DIALOG_FLOW ? 1 : nanoid();
|
||||
const sessionPath = sessionClient.projectAgentSessionPath(PROJECID, sessionId);
|
||||
const languageCode = process.env.LANGUAGE
|
||||
const request = {
|
||||
session: sessionPath,
|
||||
queryInput: {
|
||||
text: {
|
||||
text: queryText,
|
||||
languageCode: languageCode,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const responses = await sessionClient.detectIntent(request);
|
||||
const [singleResponse] = responses;
|
||||
const { queryResult } = singleResponse
|
||||
const { intent } = queryResult || { intent: {} }
|
||||
const parseIntent = intent['displayName'] || null
|
||||
const parsePayload = queryResult['fulfillmentMessages'].find((a) => a.message === 'payload');
|
||||
// console.log(singleResponse)
|
||||
if (parsePayload && parsePayload.payload) {
|
||||
const { fields } = parsePayload.payload
|
||||
media = fields.media.stringValue || null
|
||||
}
|
||||
const customPayload = parsePayload['payload']
|
||||
|
||||
const parseData = {
|
||||
replyMessage: queryResult.fulfillmentText,
|
||||
media,
|
||||
trigger: null
|
||||
}
|
||||
return parseData
|
||||
}
|
||||
|
||||
const getDataIa = (message = '', cb = () => { }) => {
|
||||
detectIntent(message).then((res) => {
|
||||
cb(res)
|
||||
})
|
||||
}
|
||||
|
||||
checkFileCredentials();
|
||||
|
||||
module.exports = { getDataIa }
|
||||
330
adapter/index.js
Normal file
330
adapter/index.js
Normal file
@@ -0,0 +1,330 @@
|
||||
const { getData, getReply, saveMessageMysql } = require('./mysql')
|
||||
const { saveMessageJson } = require('./jsonDb')
|
||||
const { getDataIa } = require('./diaglogflow')
|
||||
const stepsInitial = require('../flow/initial.json')
|
||||
const stepsReponse = require('../flow/response.json')
|
||||
const { isUndefined } = require('util');
|
||||
var msjsRecibidos = [];
|
||||
var ultimoStep; //MOD by CHV -
|
||||
var pasoAnterior = []; //MOD by CHV - Para guardar el paso anterior de cada número.
|
||||
var pasoRequerido; //MOD by CHV -
|
||||
var vamosA = ""; //MOD by CHV -
|
||||
var VA = ""; //MOD by CHV -
|
||||
var elNum; //MOD by CHV -
|
||||
var cumplePasoPrevio; //MOD by CHV -
|
||||
const resps = require('../flow/response.json'); //MOD by CHV - Agregamos para traer las respuestas.
|
||||
const { appendFile } = require('fs')
|
||||
|
||||
const get = (message, num) => new Promise((resolve, reject) => { //MOD by CHV - Agregamos parametro "num" para recibir el número de "app.js"
|
||||
// console.log(num)
|
||||
elNum = num //MOD by CHV -
|
||||
if(siguientePaso.find(k => k.numero.includes(elNum))){
|
||||
console.log("siguientePaso="+siguientePaso.find(k => k.numero.includes(elNum))["numero"], siguientePaso.find(k => k.numero.includes(elNum))["va"])
|
||||
// ultimoStep = siguientePaso.find(k => k.numero.includes(elNum))["va"]
|
||||
pasoAnterior[elNum] = siguientePaso.find(k => k.numero.includes(elNum))["va"] //Asignamos pasoAnterior al número.
|
||||
siguientePaso.splice(siguientePaso.indexOf(elNum), 1)
|
||||
console.log("******************** "+siguientePaso.find(k => k.numero.includes(elNum)))
|
||||
}
|
||||
if(siguientePaso.length>1){console.log(siguientePaso[1]["numero"], siguientePaso[1]["va"])}
|
||||
|
||||
/**
|
||||
* Si no estas usando un gesto de base de datos
|
||||
*/
|
||||
|
||||
if (process.env.DATABASE === 'none') {
|
||||
var { key } = stepsInitial.find(k => k.keywords.includes(message)) || { key: null }
|
||||
|
||||
/* ############################################### * REGEXP * ####################################################
|
||||
Si queremos usar RegExp, en los "keywords" de inital.json, en lugar de un arreglo usamos un string (quitamos los [])
|
||||
y en él usamos "*" para significar cualquier texto y "|" para significar "OR", esto nos permite ser mas flexibles
|
||||
con los "keywords", por ejemplo, si queremos que el mensaje pueda decir:
|
||||
|
||||
"Hola quiero info del paquete" o "Requiero mas informacion"
|
||||
|
||||
ponemos "info" y la regla se va a disparar porque los dos contienen "info", o si queremos que se dispare con:
|
||||
|
||||
"Quiero info del paquete numero 3" o "Me gusto el paquete de Angular"
|
||||
|
||||
ponemos "paquete*3|paquete*angular" y la regla se dispara porque contiene "paquete" Y "3" -O- "paquete" Y "angular".
|
||||
|
||||
#####################################################################################################################
|
||||
*/
|
||||
var {keywords} = stepsInitial.find(k => k.key.includes(key)) || { keywords: null }
|
||||
if(!Array.isArray(keywords)){key=null;}//Si "keywords" no es arreglo entonces ponemos "key" en null y usamos REGEXP para buscar reglas.
|
||||
if(key == null && message.length > 0){
|
||||
console.log("======= KEY ES NULO USAMOS REGEXP =======");
|
||||
for (i=0; i<stepsInitial.length;i++){
|
||||
// console.log(i, stepsInitial[i].keywords, message.match(stepsInitial[i].keywords.toString().replaceAll("*",".*")));
|
||||
if(!Array.isArray(stepsInitial[i].keywords)){// Si "Keywords" NO es arreglo entonces ...
|
||||
x = null;
|
||||
console.log("KEY=|" + stepsInitial[i].key.toString() + "|" )
|
||||
// if(resps[stepsInitial[i].key.toString()].pasoRequerido != undefined){pr = resps[stepsInitial[i].key].pasoRequerido};
|
||||
// console.log(resps[stepsInitial[i].key.toString()].pasoRequerido== ultimoStep)
|
||||
console.log("Esta Key=" + stepsInitial[i].key.toString() + " - pasoReq=" + resps[stepsInitial[i].key.toString()].pasoRequerido + " - PasoAnt=" + ultimoStep+"|"+pasoAnterior[elNum])
|
||||
if(resps[stepsInitial[i].key.toString()].pasoRequerido == undefined || resps[stepsInitial[i].key.toString()].pasoRequerido == pasoAnterior[elNum]){
|
||||
var tempKeyword = "";
|
||||
if (stepsInitial[i].keywords == "%solo_correos%"){
|
||||
console.log("solo_correos")
|
||||
tempKeyword = "[a-zA-Z0-9]+[_a-zA-Z0-9\.-]*[a-zA-Z0-9]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+[\.][a-zA-Z]{2,12})"}
|
||||
else{tempKeyword = stepsInitial[i].keywords.toString().replaceAll("*",".*")}
|
||||
x = message.match(tempKeyword);
|
||||
// console.log("Keywords="+stepsInitial[i].keywords + " - key=" + stepsInitial[i].key + " - pasoReq=" + resps[stepsInitial[i].key].pasoRequerido + " - PasoAnt=" + ultimoStep)
|
||||
// console.log("x:"+x+" - ultimoStep="+ultimoStep+" - pasoReq="+resps[stepsInitial[i].key].pasoRequerido);
|
||||
// console.log(resps[stepsInitial[i].key].replyMessage.toString())
|
||||
if (x != null){
|
||||
key = stepsInitial[i].key;
|
||||
if(resps[stepsInitial[i].key].pasoRequerido != null && resps[stepsInitial[i].key].pasoRequerido != pasoAnterior[elNum]){key=null;}
|
||||
// console.log("KEY="+key+" - X="+x);
|
||||
if(resps[stepsInitial[i].key].replyMessage.toString().search("/URL") > -1){
|
||||
console.log("**************** HAY URL ****************")
|
||||
}
|
||||
break;
|
||||
}
|
||||
else{x = null;}
|
||||
} else
|
||||
{ console.log("NO CUMPLE PASO REQ");
|
||||
// console.log("pasoReq=" + resps[stepsInitial[i].key.toString()].pasoRequerido + " - PasoAnt=" + ultimoStep)
|
||||
}
|
||||
}
|
||||
}
|
||||
// console.log("<<<<<<<<< "+key);
|
||||
// cumplePasoRequerido(key)
|
||||
// ultimoPaso = pasoRequerido;
|
||||
// ultimoStep = key;
|
||||
}
|
||||
const response = key || null
|
||||
// if(key != null){remplazos(resps[key].replyMessage.join(''));}
|
||||
if(resps[key]!=undefined){VA = resps[key].goto}else{VA=null}
|
||||
cumplePasoRequerido(key);
|
||||
vamosA = VA;
|
||||
// console.log(elNum)
|
||||
|
||||
if(vamosA != "" && vamosA != undefined && cumplePasoPrevio == true){
|
||||
console.log("ASIGNAMOS VAMOSA = " + vamosA);
|
||||
pasoAnterior[elNum] = vamosA;
|
||||
}
|
||||
// console.log("ULTIMOSTEP="+ultimoStep)
|
||||
vamosA = "";
|
||||
// console.log("MESSAGE: "+message);
|
||||
// console.log("KEY: "+key);
|
||||
// console.log("RESPONSE: "+response);
|
||||
if(cumplePasoPrevio) {resolve(response);}
|
||||
}
|
||||
|
||||
/**
|
||||
* Si usas MYSQL
|
||||
*/
|
||||
if (process.env.DATABASE === 'mysql') {
|
||||
getData(message, (dt) => {
|
||||
resolve(dt)
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
const reply = (step) => new Promise((resolve, reject) => {
|
||||
/**
|
||||
* Si no estas usando un gesto de base de datos
|
||||
*/
|
||||
if (process.env.DATABASE === 'none') {
|
||||
let resData = { replyMessage: '', media: null, trigger: null }
|
||||
const responseFind = stepsReponse[step] || {};
|
||||
resData = {
|
||||
...resData,
|
||||
...responseFind,
|
||||
replyMessage:responseFind.replyMessage.join('')}
|
||||
resolve(resData);
|
||||
return
|
||||
}
|
||||
/**
|
||||
* Si usas MYSQL
|
||||
*/
|
||||
if (process.env.DATABASE === 'mysql') {
|
||||
let resData = { replyMessage: '', media: null, trigger: null }
|
||||
getReply(step, (dt) => {
|
||||
resData = { ...resData, ...dt }
|
||||
resolve(resData)
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
const getIA = (message) => new Promise((resolve, reject) => {
|
||||
/**
|
||||
* Si usas dialogflow
|
||||
*/
|
||||
if (process.env.DATABASE === 'dialogflow') {
|
||||
let resData = { replyMessage: '', media: null, trigger: null }
|
||||
getDataIa(message,(dt) => {
|
||||
resData = { ...resData, ...dt }
|
||||
resolve(resData)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} message
|
||||
* @param {*} date
|
||||
* @param {*} trigger
|
||||
* @param {*} number
|
||||
* @returns
|
||||
*/
|
||||
const saveMessage = ( message, trigger, number, regla ) => new Promise( async (resolve, reject) => { //MOD by CHV - Agregamos el partametro "regla" para poder guardarlo en "chats/numero.json"
|
||||
switch ( process.env.DATABASE ) {
|
||||
case 'mysql':
|
||||
resolve( await saveMessageMysql( message, trigger, number ) )
|
||||
break;
|
||||
case 'none':
|
||||
resolve( await saveMessageJson( message, trigger, number, regla) ) //MOD by CHV - Agregamos el paranetro "regla"
|
||||
// console.log("REGLA DESDE APP.JS="+regla)
|
||||
break;
|
||||
default:
|
||||
resolve(true)
|
||||
break;
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = { get, reply, getIA, saveMessage, remplazos, stepsInitial } //MOD by CHV - Agregamos "remplazos" y "stepsInitial" para usarlos en "apps.js"
|
||||
|
||||
/**
|
||||
* Reemplaza texto en la respuesta con variables predefinidas.
|
||||
*/
|
||||
function remplazos(elTexto){
|
||||
laLista = elTexto.toString().split(' ');
|
||||
// console.log(laLista);
|
||||
// console.log('============= remplazos ============');
|
||||
for (var i = 0; i < laLista.length; i++) {
|
||||
// console.log('Revisamos: '+laLista[i]);
|
||||
if (laLista[i].search('%dia_semana%')>-1){//Remplaza con el dia de hoy.
|
||||
var dia = new Date().getDay();
|
||||
if(dia==0){diaSemana='domingo';}
|
||||
else if(dia==1){diaSemana='lunes';}
|
||||
else if(dia==2){diaSemana='martes';}
|
||||
else if(dia==3){diaSemana='miercoles';}
|
||||
else if(dia==4){diaSemana='jueves';}
|
||||
else if(dia==5){diaSemana='viernes';}
|
||||
else {diaSemana='sábado';}
|
||||
elTexto = elTexto.replace('%dia_semana%', diaSemana);
|
||||
}
|
||||
if (laLista[i].search('%saludo%')>-1){//Remplaza con "Buenos dias, tardes o noches" dependiendo de la hora.
|
||||
var hora = new Date().getHours()
|
||||
if(hora>0 && hora < 12){saludo='Buenos días';}
|
||||
else if(hora>11 && hora < 19){saludo='Buenas tardes';}
|
||||
else {saludo='Buenas noches';}
|
||||
elTexto = elTexto.toString().replace('%saludo%', saludo);
|
||||
}
|
||||
if (laLista[i].search('%hora24%')>-1){//Remplaza con la hora a 24 hrs.
|
||||
var hora = new Date().getHours();
|
||||
if (hora.toString().length < 2){hora = "0" + hora;}
|
||||
elTexto = elTexto.toString().replace('%hora24%', hora);
|
||||
}
|
||||
if (laLista[i].search('%hora12%')>-1){//Remplaza con la hora a 12 hrs.
|
||||
var hora = new Date().getHours();
|
||||
var ampm = hora >= 12 ? 'pm' : 'am';
|
||||
hora = hora % 12;
|
||||
hora = hora ? hora : 12; // the hour '0' should be '12'
|
||||
if (hora.toString().length < 2){hora = "0" + hora;}
|
||||
elTexto = elTexto.toString().replace('%hora12%', hora);
|
||||
}
|
||||
if (laLista[i].search('%minutos%')>-1){//Remplaza con los minutos de la hora actual.
|
||||
var mins = new Date().getMinutes();
|
||||
if (mins.toString().length < 2){mins = "0" + mins;}
|
||||
elTexto = elTexto.toString().replace('%minutos%', mins);
|
||||
}
|
||||
if (laLista[i].search('%ampm%')>-1){//Remplaza con am o pm.
|
||||
var hours = new Date().getHours();
|
||||
var ampm = hours >= 12 ? 'pm' : 'am';
|
||||
elTexto = elTexto.toString().replace('%ampm%', ampm);
|
||||
}
|
||||
if (laLista[i].search('%rnd_')>-1){//Remplaza con opción al azar dentro de las especificadas.
|
||||
var inicio = laLista[i].search('%rnd_');
|
||||
var final = laLista[i].indexOf("%", inicio+1);
|
||||
// console.log(inicio, final);
|
||||
var subStr = laLista[i].substring(inicio, final+1);
|
||||
// console.log("El substring="+subStr);
|
||||
var partes = subStr.toString().split('_');
|
||||
if(partes.length > 1){
|
||||
var opciones = partes[1].toString().substring(0,partes[1].toString().length-1).split(",");
|
||||
var elRand = Math.floor(Math.random() * (opciones.length));
|
||||
if(elRand == opciones.length){elRand = elRand - 1;}
|
||||
// console.log(opciones.length, elRand, opciones[elRand]);
|
||||
elTexto = elTexto.toString().replace(subStr, opciones[elRand]);
|
||||
}
|
||||
else{
|
||||
elTexto = elTexto.toString().replace(subStr, "");
|
||||
}
|
||||
}
|
||||
if(laLista[i].search('%msjant_')>-1){//Remplaza con el mensaje anterior especificado.
|
||||
var histlMsjs = {};
|
||||
console.log("entramos a msjant")
|
||||
// var hayHistorial = (chkFile(`${__dirname}/chats/`+from+".json"));
|
||||
if(chkFile(`${__dirname}/../chats/`+elNum+".json")){
|
||||
let rawdata = fs.readFileSync(`./chats/${elNum}.json`);
|
||||
let elHistorial0 = JSON.parse(rawdata);
|
||||
elHistorial = elHistorial0["messages"];
|
||||
|
||||
var inicio = laLista[i].search('%msjant_');
|
||||
var final = laLista[i].indexOf("%", inicio+1);
|
||||
var subStr = laLista[i].substring(inicio, final+1);
|
||||
console.log("Substr = |" + subStr + "|");
|
||||
var partes = subStr.toString().split('_');
|
||||
if(partes.length > 1){
|
||||
console.log("Partes[1] = |" + partes[1] + "|");
|
||||
let posicion0 = partes[1].substring(0, partes[1].length-1)
|
||||
console.log("Posicion0 = |" + posicion0 + "|");
|
||||
posicion = ((posicion0*1) + 1);
|
||||
console.log("Posicion = " + posicion);
|
||||
console.log( elHistorial.length );
|
||||
console.log((elHistorial.length*1)-posicion);
|
||||
console.log("Mensaje="+elHistorial[elHistorial.length - posicion]["message"])
|
||||
elTexto = elTexto.toString().replace(subStr, elHistorial[elHistorial.length - posicion]["message"]);
|
||||
}
|
||||
// histlMsjs = elHistorial["messages"];
|
||||
// totalMsjs = histlMsjs.length-1;
|
||||
// ultimoMensaje = histlMsjs[histlMsjs.length-1];
|
||||
// let mensajeAnterior = elHistorial["messages"][totalMsjs-1];
|
||||
// console.log("Mensajes:"+totalMsjs+", Ultimo:"+JSON.stringify(ultimoMensaje));
|
||||
// console.log("Anterior:"+JSON.stringify(mensajeAnterior));
|
||||
}
|
||||
// return histlMsjs;
|
||||
|
||||
}
|
||||
}
|
||||
// console.log("EL TEXTO="+elTexto);
|
||||
return elTexto
|
||||
}
|
||||
|
||||
/**
|
||||
* Revisa si la regla especificada depende (es submenu) de otra regla, y cambia la variable "cumplePasoPrevio" a verdadero o falso.
|
||||
*/
|
||||
function cumplePasoRequerido(step){
|
||||
//Traemos las respuestas para obtener el "pasoRequerido".
|
||||
if(resps[step]!=undefined){pasoRequerido=resps[step].pasoRequerido}else{pasoRequerido=null}
|
||||
if((pasoRequerido != null && pasoRequerido == ultimoStep)){
|
||||
// console.log("REQUIERE PASO PREVIO Y CUMPLE");
|
||||
cumplePasoPrevio = true;
|
||||
}
|
||||
else if((pasoRequerido != null && pasoRequerido != pasoAnterior[elNum])){
|
||||
// console.log("REQUIERE PASO PREVIO Y NO LO CUMPLE");
|
||||
cumplePasoPrevio = false;
|
||||
}
|
||||
else{
|
||||
// console.log("NO REQUIERE PASO PREVIO")
|
||||
cumplePasoPrevio = true;
|
||||
}
|
||||
pasoAnterior[elNum] = step
|
||||
ultimoPaso = pasoRequerido;
|
||||
}
|
||||
|
||||
const fs = require('fs');
|
||||
function chkFile(theFile){ //MOD by CHV - Agregamos para revisar que exista el archivo "chats/numero.json"
|
||||
if (fs.existsSync(theFile)) {
|
||||
// console.log("Si existe el archivo "+ theFile);
|
||||
var h = true;
|
||||
}
|
||||
else{
|
||||
// console.log("No existe el archivo "+ theFile);
|
||||
var h = false;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
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, regla) => 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, regla});
|
||||
db.save();
|
||||
resolve('Saved')
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = { saveMessageJson }
|
||||
74
adapter/mysql.js
Normal file
74
adapter/mysql.js
Normal file
@@ -0,0 +1,74 @@
|
||||
const {connection} = require('../config/mysql')
|
||||
const DATABASE_NAME = process.env.SQL_DATABASE || 'db_test'
|
||||
|
||||
getData = (message = '', callback) => connection.query(
|
||||
`SELECT * FROM ${DATABASE_NAME}.initial WHERE keywords LIKE '%${message}%' LIMIT 1`,
|
||||
(error, results
|
||||
) => {
|
||||
const [response] = results
|
||||
const key = response?.option_key || null
|
||||
callback(key)
|
||||
});
|
||||
|
||||
|
||||
getReply = (option_key = '', callback) => connection.query(
|
||||
`SELECT * FROM ${DATABASE_NAME}.response WHERE option_key = '${option_key}' LIMIT 1`,
|
||||
(error, results
|
||||
) => {
|
||||
const [response] = results;
|
||||
console.log(response)
|
||||
const value = {
|
||||
replyMessage:response?.replyMessage || '',
|
||||
trigger:response?.trigger || '',
|
||||
media:response?.media || ''
|
||||
|
||||
}
|
||||
callback(value)
|
||||
});
|
||||
|
||||
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}
|
||||
405
app.js
Normal file
405
app.js
Normal file
@@ -0,0 +1,405 @@
|
||||
/**
|
||||
* ⚡⚡⚡ DECLARAMOS LAS LIBRERIAS y CONSTANTES A USAR! ⚡⚡⚡
|
||||
*/
|
||||
require('dotenv').config()
|
||||
const fs = require('fs');
|
||||
const express = require('express');
|
||||
global.siguientePaso = [{"numero":"1", "va":"XXX"}]; //MOD by CHV - Agregamos para pasar el VAMOSA a "index.js"
|
||||
const cors = require('cors')
|
||||
const axios = require('axios').default;//MOD by CHV - Agregamos para el get del "/URL"
|
||||
const qrcode = require('qrcode-terminal');
|
||||
const { Client, LocalAuth, Buttons, List } = require('whatsapp-web.js');
|
||||
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 { sendMedia, sendMessage, lastTrigger, sendMessageButton, readChat } = require('./controllers/send');
|
||||
const { remplazos, stepsInitial} = require('./adapter/index');//MOD by CHV - Agregamos para utilizar remplazos y stepsInitial
|
||||
const { isUndefined } = require('util');
|
||||
const { isSet } = require('util/types');
|
||||
const { Console } = require('console');
|
||||
const app = express();
|
||||
app.use(cors())
|
||||
app.use(express.json())
|
||||
const MULTI_DEVICE = process.env.MULTI_DEVICE || 'true';
|
||||
const server = require('http').Server(app)
|
||||
const port = process.env.PORT || 3000
|
||||
|
||||
var client;
|
||||
var totalMsjs; //MOD by CHV -
|
||||
var vamosA = ""; //MOD by CHV -
|
||||
var newBody; //MOD by CHV -
|
||||
var nuevaRespuesta; //MOD by CHV - Se agrego para los remplazos
|
||||
app.use('/', require('./routes/web'))
|
||||
|
||||
/**
|
||||
* Escuchamos cuando entre un mensaje
|
||||
*/
|
||||
const listenMessage = () => client.on('message', async msg => {
|
||||
const { from, body, hasMedia } = msg;
|
||||
// console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
||||
console.log("+++++++++++++++++++++++++++++++++++++ INICIO +++++++++++++++++++++++++++++++++++++++");
|
||||
// console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
||||
console.log("HORA:"+new Date().toLocaleTimeString()+" FROM:"+from+", BODY:"+body+", HASMEDIA:"+hasMedia);
|
||||
newBody = removeDiacritics(body) //MOD by CHV - Agregamos para quitar acentos
|
||||
// newBody = remplazos(newBody);
|
||||
vamosA = "";
|
||||
if(!isValidNumber(from)){
|
||||
return
|
||||
}
|
||||
// Este bug lo reporto Lucas Aldeco Brescia para evitar que se publiquen estados
|
||||
if (from === 'status@broadcast') {
|
||||
return
|
||||
}
|
||||
message = newBody.toLowerCase();
|
||||
const number = cleanNumber(from)
|
||||
|
||||
var { key } = stepsInitial.find(k => k.keywords.includes(message)) || { key: null }//MOD by CHV - Se agrega para obtener KEY
|
||||
await readChat(number, message, null , key) //MOD by CHV - Agregamos key/regla para guardarla en "chats/numero.json"
|
||||
|
||||
/**
|
||||
* Guardamos el archivo multimedia que envia
|
||||
*/
|
||||
if (process.env.SAVE_MEDIA && hasMedia) {
|
||||
const media = await msg.downloadMedia();
|
||||
saveMedia(media);
|
||||
}
|
||||
|
||||
/**
|
||||
* Si estas usando dialogflow solo manejamos una funcion todo es IA
|
||||
*/
|
||||
|
||||
if (process.env.DATABASE === 'dialogflow') {
|
||||
if(!message.length) return;
|
||||
const response = await bothResponse(message);
|
||||
await sendMessage(client, from, response.replyMessage);
|
||||
if (response.media) {
|
||||
sendMedia(client, from, response.media, response.trigger);
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var tempBody = body.toString().toLowerCase();
|
||||
|
||||
|
||||
/**
|
||||
* PRUEBA BOTONES NUEVOS
|
||||
*/
|
||||
// if(body=="579"){
|
||||
// const buttons_reply = new Buttons("Por favor vuelve a intentar, mandando *SOLO* la palabra *gallina* con una diagonal al principio 👇🏽 \n\n */gallina*\n ", [{body: "/gallina", id: 'errorGallina'}], 'Error', 'O haz clic en el siguiente botón') // Reply button
|
||||
// for (const component of [buttons_reply]) await client.sendMessage(from, component);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Ver si viene de un paso anterior
|
||||
* Aqui podemos ir agregando más pasos
|
||||
* a tu gusto!
|
||||
*/
|
||||
|
||||
const lastStep = await lastTrigger(from) || null;
|
||||
// console.log("LAST STEP="+lastStep+", FROM:"+from);
|
||||
if (lastStep) {
|
||||
const response = await responseMessages(lastStep)
|
||||
console.log("CLIENT="+client+", FROM:"+from+", REPLYMESSAGE:"+response.replyMessage);
|
||||
await sendMessage(client, from, response.replyMessage, lastStep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Respondemos al primero paso si encuentra palabras clave
|
||||
*/
|
||||
// const step = await getMessages(message, );
|
||||
// console.log("STEP - "+step+"|"+message);
|
||||
// console.log("****** STEP="+step);
|
||||
// console.log("****** MESSAGE:"+message);
|
||||
const step = await getMessages(message, from);
|
||||
if (step) {
|
||||
const response = await responseMessages(step);
|
||||
// console.log("URL:"+nuevaRespuesta);
|
||||
// console.log("HAY URL?? : "+nuevaRespuesta.search("/URL"));
|
||||
|
||||
var resps = require('./flow/response.json');
|
||||
nuevaRespuesta = remplazos(resps[step].replyMessage.join(''));
|
||||
var pasoRequerido = resps[step].pasoRequerido;
|
||||
// var hayRequest = false;
|
||||
// if(hayRequest==false && nuevaRespuesta.search("/URL")>-1){console.log("Paramos flujo para que no mande el mensaje '/URL'."); return;}//Si el trigger es desbloqueo ya no hace nada mas.
|
||||
|
||||
/**
|
||||
* Si quieres enviar botones
|
||||
*/
|
||||
if (response.delay){
|
||||
// console.log("+++++++++++++++++++ SENDING MSG WITH DELAY ("+response.delay+") +++++++++++++++++");
|
||||
setTimeout(() => {
|
||||
sendMessage(client, from, nuevaRespuesta, response.trigger, step);
|
||||
// console.log(" ************* Msg with delay SENT ****************")
|
||||
}, response.delay)
|
||||
}
|
||||
else{
|
||||
await sendMessage(client, from, nuevaRespuesta, response.trigger, step);
|
||||
}
|
||||
if (!response.delay && response.media) {
|
||||
// console.log("++++++++++++++++++++++++++++ SEND MEDIA NO DELAY +++++++++++++++++++++++++++++++++++");
|
||||
sendMedia(client, from, response.media, response.trigger);
|
||||
}
|
||||
if (response.delay && response.media) {
|
||||
setTimeout(() => {
|
||||
// console.log("++++++++++++++++++++++++++++ SEND MEDIA AND DELAY +++++++++++++++++++++++++++++++++++");
|
||||
sendMedia(client, from, response.media, response.trigger);
|
||||
}, response.delay)
|
||||
}
|
||||
if(response.hasOwnProperty('actions')){
|
||||
const { actions } = response;
|
||||
// console.log("++++++++++++++++++++++++++++ SEND MESG BUTTON +++++++++++++++++++++++++++++++++++");
|
||||
await sendMessageButton(client, from, null, actions);
|
||||
// return
|
||||
}
|
||||
return
|
||||
}
|
||||
/**
|
||||
* Regresa el mensaje enviado, con los remplazos procesados.
|
||||
*/
|
||||
if(message.search('/rpt') > -1){
|
||||
newBody = remplazos(newBody);
|
||||
newBody = newBody.replace("/rpt ", "");
|
||||
client.sendMessage(from, newBody);
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
============================================================================
|
||||
========================== ENVIO MASIVO TEST ===========================
|
||||
============================================================================
|
||||
*/
|
||||
if(message=='/spam'){
|
||||
const masivo = require('./spam.json')
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
async function retardo() {
|
||||
for (i=0;i<masivo.length;i++) {
|
||||
console.log(masivo[i].numero+"@c.us");
|
||||
client.sendMessage(masivo[i].numero+"@c.us", "Este es un mensaje de prueba para *"+masivo[i].numero+"*, HORA:*"+new Date().toLocaleTimeString()+"*");
|
||||
var rnd = getRandomInt(1,4); // Random entre 1 y 3 segundos.
|
||||
console.log(`Esperamos ${rnd} segundos...`);
|
||||
await sleep(rnd*1000);
|
||||
}
|
||||
console.log('Done');
|
||||
}
|
||||
retardo();
|
||||
}
|
||||
|
||||
function getRandomInt(min, max) {
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive
|
||||
}
|
||||
|
||||
|
||||
//Si quieres tener un mensaje por defecto
|
||||
if (process.env.DEFAULT_MESSAGE === 'true') {
|
||||
const response = await responseMessages('DEFAULT')
|
||||
await sendMessage(client, from, response.replyMessage, response.trigger);
|
||||
/**
|
||||
* Si quieres enviar botones
|
||||
*/
|
||||
if(response.hasOwnProperty('actions')){
|
||||
const { actions } = response;
|
||||
await sendMessageButton(client, from, null, actions);
|
||||
}
|
||||
return
|
||||
}
|
||||
});
|
||||
|
||||
client = new Client({
|
||||
authStrategy: new LocalAuth(),
|
||||
puppeteer: { headless: true, args: ['--no-sandbox','--disable-setuid-sandbox'] }
|
||||
});
|
||||
|
||||
client.on('qr', qr => generateImage(qr, () => {
|
||||
qrcode.generate(qr, { small: true });
|
||||
console.log(`Ver QR http://localhost:${port}/qr`)
|
||||
socketEvents.sendQR(qr)
|
||||
}))
|
||||
|
||||
client.on('ready', (a) => {
|
||||
connectionReady()
|
||||
listenMessage()
|
||||
// socketEvents.sendStatus(client)
|
||||
});
|
||||
|
||||
client.on('auth_failure', (e) => {
|
||||
// console.log(e)
|
||||
// connectionLost()
|
||||
});
|
||||
|
||||
client.on('authenticated', () => {
|
||||
console.log('AUTHENTICATED');
|
||||
});
|
||||
|
||||
client.initialize();
|
||||
|
||||
/**
|
||||
* Verificamos si tienes un gesto de db
|
||||
*/
|
||||
|
||||
if (process.env.DATABASE === 'mysql') {
|
||||
mysqlConnection.connect()
|
||||
}
|
||||
|
||||
server.listen(port, () => {
|
||||
console.log(`El server esta listo en el puerto ${port}`);
|
||||
})
|
||||
checkEnvFile();
|
||||
|
||||
function chkFile(theFile){ //MOD by CHV - Agregamos para revisar que exista el archivo "chats/numero.json"
|
||||
if (fs.existsSync(theFile)) {
|
||||
// console.log("Si existe el archivo "+ theFile);
|
||||
var h = true;
|
||||
}
|
||||
else{
|
||||
// console.log("No existe el archivo "+ theFile);
|
||||
var h = false;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regresa el historial de mensajes del número especificado del directorio "chats".
|
||||
*/
|
||||
function traeMensajes(from){ //MOD by CHV - Agregamos para traer el historial de mensajes
|
||||
var histlMsjs = {};
|
||||
var hayHistorial = (chkFile(`${__dirname}/chats/`+from+".json"));
|
||||
if(hayHistorial){
|
||||
let rawdata = fs.readFileSync(`./chats/${from}.json`);
|
||||
let elHistorial = JSON.parse(rawdata);
|
||||
histlMsjs = elHistorial["messages"];
|
||||
// totalMsjs = histlMsjs.length-1;
|
||||
ultimoMensaje = histlMsjs[histlMsjs.length-1];
|
||||
// let mensajeAnterior = elHistorial["messages"][totalMsjs-1];
|
||||
// console.log("Mensajes:"+totalMsjs+", Ultimo:"+JSON.stringify(ultimoMensaje));
|
||||
// console.log("Anterior:"+JSON.stringify(mensajeAnterior));
|
||||
}
|
||||
return histlMsjs;
|
||||
}
|
||||
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
var defaultDiacriticsRemovalMap = [ //MOD by CHV - Agregamos para eliminar acentos
|
||||
{'base':'A', 'letters':'\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F'},
|
||||
{'base':'AA','letters':'\uA732'},
|
||||
{'base':'AE','letters':'\u00C6\u01FC\u01E2'},
|
||||
{'base':'AO','letters':'\uA734'},
|
||||
{'base':'AU','letters':'\uA736'},
|
||||
{'base':'AV','letters':'\uA738\uA73A'},
|
||||
{'base':'AY','letters':'\uA73C'},
|
||||
{'base':'B', 'letters':'\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181'},
|
||||
{'base':'C', 'letters':'\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E'},
|
||||
{'base':'D', 'letters':'\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779\u00D0'},
|
||||
{'base':'DZ','letters':'\u01F1\u01C4'},
|
||||
{'base':'Dz','letters':'\u01F2\u01C5'},
|
||||
{'base':'E', 'letters':'\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E'},
|
||||
{'base':'F', 'letters':'\u0046\u24BB\uFF26\u1E1E\u0191\uA77B'},
|
||||
{'base':'G', 'letters':'\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E'},
|
||||
{'base':'H', 'letters':'\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D'},
|
||||
{'base':'I', 'letters':'\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197'},
|
||||
{'base':'J', 'letters':'\u004A\u24BF\uFF2A\u0134\u0248'},
|
||||
{'base':'K', 'letters':'\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2'},
|
||||
{'base':'L', 'letters':'\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780'},
|
||||
{'base':'LJ','letters':'\u01C7'},
|
||||
{'base':'Lj','letters':'\u01C8'},
|
||||
{'base':'M', 'letters':'\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C'},
|
||||
{'base':'N', 'letters':'\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4'},
|
||||
{'base':'NJ','letters':'\u01CA'},
|
||||
{'base':'Nj','letters':'\u01CB'},
|
||||
{'base':'O', 'letters':'\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C'},
|
||||
{'base':'OI','letters':'\u01A2'},
|
||||
{'base':'OO','letters':'\uA74E'},
|
||||
{'base':'OU','letters':'\u0222'},
|
||||
{'base':'OE','letters':'\u008C\u0152'},
|
||||
{'base':'oe','letters':'\u009C\u0153'},
|
||||
{'base':'P', 'letters':'\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754'},
|
||||
{'base':'Q', 'letters':'\u0051\u24C6\uFF31\uA756\uA758\u024A'},
|
||||
{'base':'R', 'letters':'\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782'},
|
||||
{'base':'S', 'letters':'\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784'},
|
||||
{'base':'T', 'letters':'\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786'},
|
||||
{'base':'TZ','letters':'\uA728'},
|
||||
{'base':'U', 'letters':'\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244'},
|
||||
{'base':'V', 'letters':'\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245'},
|
||||
{'base':'VY','letters':'\uA760'},
|
||||
{'base':'W', 'letters':'\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72'},
|
||||
{'base':'X', 'letters':'\u0058\u24CD\uFF38\u1E8A\u1E8C'},
|
||||
{'base':'Y', 'letters':'\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE'},
|
||||
{'base':'Z', 'letters':'\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762'},
|
||||
{'base':'a', 'letters':'\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250'},
|
||||
{'base':'aa','letters':'\uA733'},
|
||||
{'base':'ae','letters':'\u00E6\u01FD\u01E3'},
|
||||
{'base':'ao','letters':'\uA735'},
|
||||
{'base':'au','letters':'\uA737'},
|
||||
{'base':'av','letters':'\uA739\uA73B'},
|
||||
{'base':'ay','letters':'\uA73D'},
|
||||
{'base':'b', 'letters':'\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253'},
|
||||
{'base':'c', 'letters':'\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184'},
|
||||
{'base':'d', 'letters':'\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A'},
|
||||
{'base':'dz','letters':'\u01F3\u01C6'},
|
||||
{'base':'e', 'letters':'\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD'},
|
||||
{'base':'f', 'letters':'\u0066\u24D5\uFF46\u1E1F\u0192\uA77C'},
|
||||
{'base':'g', 'letters':'\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F'},
|
||||
{'base':'h', 'letters':'\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265'},
|
||||
{'base':'hv','letters':'\u0195'},
|
||||
{'base':'i', 'letters':'\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131'},
|
||||
{'base':'j', 'letters':'\u006A\u24D9\uFF4A\u0135\u01F0\u0249'},
|
||||
{'base':'k', 'letters':'\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3'},
|
||||
{'base':'l', 'letters':'\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747'},
|
||||
{'base':'lj','letters':'\u01C9'},
|
||||
{'base':'m', 'letters':'\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F'},
|
||||
{'base':'n', 'letters':'\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5'},
|
||||
{'base':'nj','letters':'\u01CC'},
|
||||
{'base':'o', 'letters':'\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275'},
|
||||
{'base':'oi','letters':'\u01A3'},
|
||||
{'base':'ou','letters':'\u0223'},
|
||||
{'base':'oo','letters':'\uA74F'},
|
||||
{'base':'p','letters':'\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755'},
|
||||
{'base':'q','letters':'\u0071\u24E0\uFF51\u024B\uA757\uA759'},
|
||||
{'base':'r','letters':'\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783'},
|
||||
{'base':'s','letters':'\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B'},
|
||||
{'base':'t','letters':'\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787'},
|
||||
{'base':'tz','letters':'\uA729'},
|
||||
{'base':'u','letters': '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289'},
|
||||
{'base':'v','letters':'\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C'},
|
||||
{'base':'vy','letters':'\uA761'},
|
||||
{'base':'w','letters':'\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73'},
|
||||
{'base':'x','letters':'\u0078\u24E7\uFF58\u1E8B\u1E8D'},
|
||||
{'base':'y','letters':'\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF'},
|
||||
{'base':'z','letters':'\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763'}
|
||||
];
|
||||
|
||||
var diacriticsMap = {};
|
||||
for (var i=0; i < defaultDiacriticsRemovalMap .length; i++){
|
||||
var letters = defaultDiacriticsRemovalMap [i].letters;
|
||||
for (var j=0; j < letters.length ; j++){
|
||||
diacriticsMap[letters[j]] = defaultDiacriticsRemovalMap [i].base;
|
||||
}
|
||||
}
|
||||
|
||||
// "what?" version ... http://jsperf.com/diacritics/12
|
||||
function removeDiacritics (str) {
|
||||
return str.replace(/[^\u0000-\u007E]/g, function(a){
|
||||
return diacriticsMap[a] || a;
|
||||
});
|
||||
}
|
||||
// var paragraph = "L'avantage d'utiliser le lorem ipsum est bien évidemment de pouvoir créer des maquettes ou de remplir un site internet de contenus qui présentent un rendu s'approchant un maximum du rendu final. \n Par défaut lorem ipsum ne contient pas d'accent ni de caractères spéciaux contrairement à la langue française qui en contient beaucoup. C'est sur ce critère que nous proposons une solution avec cet outil qui générant du faux-texte lorem ipsum mais avec en plus, des caractères spéciaux tel que les accents ou certains symboles utiles pour la langue française. \n L'utilisation du lorem standard est facile d’utilisation mais lorsque le futur client utilisera votre logiciel il se peut que certains caractères spéciaux ou qu'un accent ne soient pas codés correctement. \n Cette page a pour but donc de pouvoir perdre le moins de temps possible et donc de tester directement si tous les encodages de base de donnée ou des sites sont les bons de plus il permet de récuperer un code css avec le texte formaté !";
|
||||
// alert(removeDiacritics(paragraph));
|
||||
35
app.json
Normal file
35
app.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "Chatbot Whatsapp (Leifer Mendez)",
|
||||
"description": "El siguiente proyecto se realizó con fines educativos para el canal de Youtube (Leifer Mendez) donde aprendemos como usando node.js podemos crear un chatbot increíble que además le agregamos inteligencia artificial gracias al servicio de dialogflow",
|
||||
"repository": "https://github.com/leifermendez/bot-whatsapp",
|
||||
"logo": "https://avatars0.githubusercontent.com/u/15802366?s=460&u=77ec7ef359e8ed842aef769693f1675c0ed460fd&v=4",
|
||||
"keywords": [
|
||||
"nodejs",
|
||||
"whatsapp",
|
||||
"bot",
|
||||
"chatbot",
|
||||
"dialogflow"
|
||||
],
|
||||
"addons": [
|
||||
],
|
||||
"buildpacks": [
|
||||
{
|
||||
"url": "heroku/nodejs"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/jontewks/puppeteer-heroku-buildpack"
|
||||
}
|
||||
],
|
||||
"env": {
|
||||
"SAVE_MEDIA": "false",
|
||||
"DATABASE": {
|
||||
"description": "'none', 'mysql', 'dialogflow' por defecto 'none' Puedes usar alguna de los siguientes opciones. Pero antes debes de saber como funciona y eso lo explico en el video. Puedes obtener más información https://github.com/leifermendez/bot-whatsapp/blob/main/README.md",
|
||||
"value": "none"
|
||||
},
|
||||
"LANGUAGE": "es",
|
||||
"SQL_HOST":"your_host",
|
||||
"SQL_USER":"your_user",
|
||||
"SQL_PASS":"your_password",
|
||||
"SQL_DATABASE":"your_database"
|
||||
}
|
||||
}
|
||||
13
chatbot-account.json
Normal file
13
chatbot-account.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "",
|
||||
"project_id": "",
|
||||
"private_key_id": "",
|
||||
"private_key":"",
|
||||
"client_email": "",
|
||||
"client_id": "",
|
||||
"auth_uri": "",
|
||||
"token_uri": "",
|
||||
"auth_provider_x509_cert_url": "",
|
||||
"client_x509_cert_url":""
|
||||
}
|
||||
|
||||
0
chats/.gitkeep
Normal file
0
chats/.gitkeep
Normal file
18
config/mysql.js
Normal file
18
config/mysql.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const mysql = require('mysql');
|
||||
const connection = mysql.createConnection({
|
||||
host : process.env.SQL_HOST || 'localhost',
|
||||
user : process.env.SQL_USER || 'root',
|
||||
password : process.env.SQL_PASS || '',
|
||||
database : process.env.SQL_DATABASE || 'pruebas'
|
||||
});
|
||||
|
||||
const connect = () => connection.connect(function(err) {
|
||||
if (err) {
|
||||
console.error('error connecting: ' + err.stack);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Conexion correcta con tu base de datos MySQL')
|
||||
});
|
||||
|
||||
module.exports = {connect, connection}
|
||||
14
controllers/connection.js
Normal file
14
controllers/connection.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const connectionReady = (cb = () =>{}) => {
|
||||
console.log('Listo para escuchar mensajes')
|
||||
console.log('El cliente esta listo!');
|
||||
console.log('🔴 Escribe: /hola');
|
||||
cb()
|
||||
}
|
||||
|
||||
const connectionLost = (cb = () =>{}) => {
|
||||
console.log('** Error de autentificacion vuelve a generar el QRCODE (Borrar el archivo session.json) **');
|
||||
cb()
|
||||
}
|
||||
|
||||
|
||||
module.exports = {connectionReady, connectionLost}
|
||||
29
controllers/flows.js
Normal file
29
controllers/flows.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const {get, reply, getIA} = require('../adapter')
|
||||
const {saveExternalFile, checkIsUrl} = require('./handle')
|
||||
|
||||
const getMessages = async (message, num) => { //MOD by CHV - Agregamos el parametro "num" para recibir el numero desde "app.js"
|
||||
// console.log("GETMESSAGES (flow.js)")
|
||||
const data = await get(message, num) //MOD by CHV - Agregamos "num"
|
||||
return data
|
||||
}
|
||||
|
||||
const responseMessages = async (step) => {
|
||||
const data = await reply(step)
|
||||
if(data && data.media){
|
||||
const file = checkIsUrl(data.media) ? await saveExternalFile(data.media) : data.media;
|
||||
return {...data,...{media:file}}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
const bothResponse = async (message) => {
|
||||
const data = await getIA(message)
|
||||
if(data && data.media){
|
||||
const file = await saveExternalFile(data.media)
|
||||
return {...data,...{media:file}}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
|
||||
module.exports = { getMessages, responseMessages, bothResponse }
|
||||
83
controllers/handle.js
Normal file
83
controllers/handle.js
Normal file
@@ -0,0 +1,83 @@
|
||||
const { Client, LegacySessionAuth, LocalAuth } = require('whatsapp-web.js');
|
||||
const http = require('http'); // or 'https' for https:// URLs
|
||||
const https = require('https'); // or 'https' for https:// URLs
|
||||
const fs = require('fs');
|
||||
const qr = require('qr-image')
|
||||
|
||||
const MULTI_DEVICE = process.env.MULTI_DEVICE || 'true';
|
||||
|
||||
const cleanNumber = (number) => {
|
||||
number = number.replace('@c.us', '');
|
||||
number = `${number}@c.us`;
|
||||
return number
|
||||
}
|
||||
|
||||
const saveExternalFile = (url) => new Promise((resolve, reject) => {
|
||||
const ext = url.split('.').pop()
|
||||
const checkProtocol = url.split('/').includes('https:');
|
||||
const handleHttp = checkProtocol ? https : http;
|
||||
const name = `${Date.now()}.${ext}`;
|
||||
const file = fs.createWriteStream(`${__dirname}/../mediaSend/${name}`);
|
||||
console.log(url)
|
||||
handleHttp.get(url, function(response) {
|
||||
response.pipe(file);
|
||||
file.on('finish', function() {
|
||||
file.close(); // close() is async, call cb after close completes.
|
||||
resolve(name)
|
||||
});
|
||||
file.on('error', function() {
|
||||
console.log('errro')
|
||||
file.close(); // close() is async, call cb after close completes.
|
||||
resolve(null)
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
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 = () => {}) => {
|
||||
let qr_svg = qr.image(base64, { type: 'svg', margin: 4 });
|
||||
qr_svg.pipe(require('fs').createWriteStream('./mediaSend/qr-code.svg'));
|
||||
console.log(`⚡ Recuerda que el QR se actualiza cada minuto ⚡'`);
|
||||
console.log(`⚡ Actualiza F5 el navegador para mantener el mejor QR⚡`);
|
||||
cb()
|
||||
}
|
||||
|
||||
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, args: ['--no-sandbox','--disable-setuid-sandbox'] }
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
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}
|
||||
24
controllers/save.js
Normal file
24
controllers/save.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const mimeDb = require('mime-db')
|
||||
const fs = require('fs')
|
||||
|
||||
/**
|
||||
* Guardamos archivos multimedia que nuestro cliente nos envie!
|
||||
* @param {*} media
|
||||
*/
|
||||
|
||||
|
||||
const saveMedia = (media) => {
|
||||
var ext = "";
|
||||
const extensionProcess = mimeDb[media.mimetype]
|
||||
try {
|
||||
ext = extensionProcess.extensions[0]
|
||||
} catch (error) {
|
||||
ext = "";
|
||||
}
|
||||
|
||||
fs.writeFile(`./media/${Date.now()}.${ext}`, media.data, { encoding: 'base64' }, function (err) {
|
||||
console.log('** Archivo Media Guardado **');
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {saveMedia}
|
||||
124
controllers/send.js
Normal file
124
controllers/send.js
Normal file
@@ -0,0 +1,124 @@
|
||||
|
||||
const ExcelJS = require('exceljs');
|
||||
const moment = require('moment');
|
||||
const fs = require('fs');
|
||||
const { MessageMedia, Buttons } = require('whatsapp-web.js');
|
||||
const { cleanNumber } = require('./handle')
|
||||
const { remplazos } = require('../adapter/index'); //MOD by CHV - Agregamos remplazos
|
||||
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
|
||||
* @param {*} number
|
||||
* @param {*} fileName
|
||||
*/
|
||||
|
||||
const sendMedia = (client, number = null, fileName = null, trigger = null) => {
|
||||
if(!client) return console.error("El objeto cliente no está definido.");
|
||||
console.log("MEDIA:"+fileName);
|
||||
try {
|
||||
number = cleanNumber(number || 0)
|
||||
const file = `${DIR_MEDIA}/${fileName}`;
|
||||
console.log("FILE="+file);
|
||||
if (fs.existsSync(file)) {
|
||||
console.log("ARCHIVO EXISTE");
|
||||
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 console.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
|
||||
* @param {*} number
|
||||
*/
|
||||
const sendMessage = async (client, number = null, text = null, trigger = null, regla) => { //MOD by CHV - Agregamos el parametro "regla" para guardarlo en "chats/nuero.json"
|
||||
// console.log("SENDMESSAGE (send.js) & regla = " + regla)
|
||||
setTimeout(async () => {
|
||||
number = cleanNumber(number)
|
||||
const message = text
|
||||
// console.log("number="+number);
|
||||
client.sendMessage(number, message);
|
||||
await readChat(number, message, trigger, regla) //MOD by CHV - Agregamos el parametro "regla"
|
||||
console.log(`⚡⚡⚡ Enviando mensajes....`);
|
||||
// console.log("********************* SEND MESSAGE **************************************");
|
||||
},DELAY_TIME)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enviamos un mensaje con buttons a nuestro cliente
|
||||
* @param {*} number
|
||||
*/
|
||||
const sendMessageButton = async (client, number = null, text = null, actionButtons) => {
|
||||
number = cleanNumber(number)
|
||||
const { title = null, message = null, footer = null, buttons = [] } = actionButtons;
|
||||
let button = new Buttons(remplazos(message),[...buttons], title, footer);
|
||||
// console.log("number="+number);
|
||||
client.sendMessage(number, button);
|
||||
|
||||
console.log(`⚡⚡⚡ Enviando mensajes....`);
|
||||
console.log("sendMessageButton.");
|
||||
// console.log("Trigger="+trigger);
|
||||
// console.log("************************ SEND MESSAGE BUTTON ***********************************");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opte
|
||||
*/
|
||||
const lastTrigger = (number) => new Promise((resolve, reject) => {
|
||||
number = cleanNumber(number)
|
||||
const pathExcel = `${__dirname}/../chats/${number}.xlsx`;
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
if (fs.existsSync(pathExcel)) {
|
||||
workbook.xlsx.readFile(pathExcel)
|
||||
.then(() => {
|
||||
const worksheet = workbook.getWorksheet(1);
|
||||
const lastRow = worksheet.lastRow;
|
||||
const getRowPrevStep = worksheet.getRow(lastRow.number);
|
||||
const lastStep = getRowPrevStep.getCell('C').value;
|
||||
resolve(lastStep)
|
||||
});
|
||||
} else {
|
||||
resolve(null)
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Guardar historial de conversacion
|
||||
* @param {*} number
|
||||
* @param {*} message
|
||||
*/
|
||||
const readChat = async (number, message, trigger = null, regla) => { //MOD by CHV - Agregamos el parametro "regla" para guardarlo en "chats/numero.json"
|
||||
number = cleanNumber(number)
|
||||
await saveMessage( message, trigger, number, regla ) //MOD by CHV - Agegamos "regla"
|
||||
// console.log('Saved')
|
||||
}
|
||||
|
||||
module.exports = { sendMessage, sendMedia, lastTrigger, sendMessageButton, readChat, sendMediaVoiceNote }
|
||||
16
controllers/socket.js
Normal file
16
controllers/socket.js
Normal file
@@ -0,0 +1,16 @@
|
||||
module.exports = (socket) => {
|
||||
return {
|
||||
sendQR:(qr) => {
|
||||
socket.emit('connection_qr',{
|
||||
qr
|
||||
})
|
||||
},
|
||||
sendStatus:() => {
|
||||
socket.emit('connection_status',{
|
||||
a:1
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
17
controllers/web.js
Normal file
17
controllers/web.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const fs = require('fs')
|
||||
const { sendMessage } = require('../controllers/send')
|
||||
|
||||
const sendMessagePost = (req, res) => {
|
||||
console.log('asdasdasdasdasd')
|
||||
const { message, number } = req.body
|
||||
const client = req.clientWs || null;
|
||||
sendMessage(client, number, message)
|
||||
res.send({ status: 'Enviado!' })
|
||||
}
|
||||
|
||||
const getQr = (req, res) => {
|
||||
res.writeHead(200, { 'content-type': 'image/svg+xml' });
|
||||
fs.createReadStream(`${__dirname}/../mediaSend/qr-code.svg`).pipe(res);
|
||||
}
|
||||
|
||||
module.exports = { sendMessagePost, getQr }
|
||||
66
flow/initial.json
Normal file
66
flow/initial.json
Normal file
@@ -0,0 +1,66 @@
|
||||
[
|
||||
{
|
||||
"keywords": [
|
||||
"xmuchas gracias",
|
||||
"xgracias",
|
||||
"xvale gracias"
|
||||
],
|
||||
"key": "Gracias"
|
||||
},
|
||||
{
|
||||
"keywords": ["/menu"],
|
||||
"key": "menu"
|
||||
},
|
||||
{
|
||||
"keywords": ["1"],
|
||||
"key": "opcion1"
|
||||
},
|
||||
{
|
||||
"keywords": ["2"],
|
||||
"key": "opcion2"
|
||||
},
|
||||
{
|
||||
"keywords": ["3"],
|
||||
"key": "opcion3"
|
||||
},
|
||||
{
|
||||
"keywords": "*",
|
||||
"key": "recibenombre"
|
||||
},
|
||||
{
|
||||
"keywords": "*",
|
||||
"key": "recibecorreo"
|
||||
},
|
||||
{
|
||||
"keywords": "*",
|
||||
"key": "gRevisaCliente"
|
||||
},
|
||||
{
|
||||
"keywords": "*",
|
||||
"key": "gGuardainfo"
|
||||
},
|
||||
{
|
||||
"keywords": ["rnd"],
|
||||
"key": "rnd"
|
||||
},
|
||||
{
|
||||
"keywords": ["rnd2"],
|
||||
"key": "rnd2"
|
||||
},
|
||||
{
|
||||
"keywords": ["/venta","/borrarventa"],
|
||||
"key": "venta"
|
||||
},
|
||||
{
|
||||
"keywords": "*",
|
||||
"key": "borramosventa"
|
||||
},
|
||||
{
|
||||
"keywords": ["/rc","/recuperaclientes","/recuperarclientes"],
|
||||
"key": "clientes"
|
||||
},
|
||||
{
|
||||
"keywords": "*",
|
||||
"key": "recuperamosClientes"
|
||||
}
|
||||
]
|
||||
142
flow/response.json
Normal file
142
flow/response.json
Normal file
@@ -0,0 +1,142 @@
|
||||
{
|
||||
"DEFAULT":{
|
||||
"replyMessage":[
|
||||
"*Esta respuesta es un respuesta default* cuando no se consigue una palabra clave \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,
|
||||
"trigger":null
|
||||
},
|
||||
"menu":{
|
||||
"replyMessage":[
|
||||
"%saludo%, este es el menú, selecciona tus opciones: \n",
|
||||
"Pon *1* para esta opción\n",
|
||||
"Pon *2* para esta opción\n",
|
||||
"Pon *3* para esta opción\n"
|
||||
],
|
||||
"media":null,
|
||||
"trigger":null
|
||||
},
|
||||
"opcion1":{
|
||||
"replyMessage":[
|
||||
"Seleccionaste la opción 1 \n",
|
||||
"Dame por favor tu nombre.\n",
|
||||
"*Ultimo:*\n%msjant_0% \n*Penultimo:*\n%msjant_1% \n*Antepenultimo:*\n%msjant_2% "
|
||||
],
|
||||
"media":null,
|
||||
"pasoRequerido":"menu"
|
||||
},
|
||||
"opcion2":{
|
||||
"replyMessage":[
|
||||
"Seleccionaste la opción 2\n",
|
||||
"👍🏽"
|
||||
],
|
||||
"media":null,
|
||||
"pasoRequerido":"menu"
|
||||
},
|
||||
"opcion3":{
|
||||
"replyMessage":[
|
||||
"Seleccionaste la opción 3\n"
|
||||
],
|
||||
"media":null,
|
||||
"pasoRequerido":"menu",
|
||||
"goto":"pideCorreo"
|
||||
},
|
||||
"recibenombre":{
|
||||
"replyMessage":[
|
||||
"Gracias, ahora dame tu correo."
|
||||
],
|
||||
"media":null,
|
||||
"trigger":null,
|
||||
"pasoRequerido":"opcion1"
|
||||
},
|
||||
"recibecorreo":{
|
||||
"replyMessage":[
|
||||
"Gracias por tu correo."
|
||||
],
|
||||
"media":null,
|
||||
"trigger":null,
|
||||
"pasoRequerido":"recibenombre"
|
||||
},
|
||||
"gallina":{
|
||||
"replyMessage":[
|
||||
"%saludo%, por favor dame tu *número de cliente*, este lo puedes encontrar en tu ticket de compra."
|
||||
],
|
||||
"media":null,
|
||||
"trigger":null
|
||||
},
|
||||
"gRevisaCliente":{
|
||||
"replyMessage":[
|
||||
"/URL=http://localhost:8888/dbrquery?j={\"query\":\"select_revisacliente_GUNA\",\"exec\":\"ExecuteQuery\",\"params\":{\"par1\":\"XXPARAM1XX\"}}"
|
||||
],
|
||||
"media":null,
|
||||
"trigger":null,
|
||||
"pasoRequerido":"gallina"
|
||||
},
|
||||
"gGuardainfo":{
|
||||
"replyMessage":[
|
||||
"/URL=http://localhost:8888/dbrquery?j={\"query\":\"insert_registroGallina_GUNA\",\"exec\":\"ExecuteCommand\",\"params\":{\"par1\":\"XXPARAM1XX\", \"par2\":\"XXPARAM2XX\", \"par3\":\"XXPARAM3XX\", \"par4\":\"XXPARAM4XX\"}}"
|
||||
],
|
||||
"media":null,
|
||||
"trigger":null,
|
||||
"pasoRequerido":"gRevisaCliente"
|
||||
},
|
||||
"rnd":{
|
||||
"replyMessage":[
|
||||
"%saludo%\nHoy es %dia_semana%.\nSon las %hora24%:%minutos% hrs.\nSon las %hora12%:%minutos% %ampm%\n*Palabra random:* %rnd_arbol,burro,cabra,dinosaurio,elefante,fuego,gorila%\n*Emoji random:* %rnd_👍🏽,😁,🤣,🤔,🤦🏽♂️,🙄,😎%\n*Número random:* %rnd_1,2,3,4,5,6,7%\n"
|
||||
],
|
||||
"media":null,
|
||||
"trigger":null
|
||||
},
|
||||
"venta":{
|
||||
"replyMessage":[
|
||||
"%saludo%,\nPor favor escribe la *ruta* y el *almacén* de la venta que deseas borrar, separados por una diagonal.\nEjemplo: *101/6*\n"
|
||||
],
|
||||
"media":null,
|
||||
"trigger":null
|
||||
},
|
||||
"borramosventa":{
|
||||
"replyMessage":[
|
||||
"/URL=http://localhost:8888/dbrquery?j={\"query\":\"select_revisaBorrarVenta\",\"exec\":\"ExecuteQuery\",\"params\":{\"par01\":\"XXPARAM01XX\", \"par02\":\"XXPARAM02XX\", \"par03\":\"XXPARAM03XX\", \"par04\":\"XXPARAM04XX\", \"par05\":\"XXPARAM05XX\", \"par06\":\"XXPARAM06XX\", \"par07\":\"XXPARAM07XX\", \"par08\":\"XXPARAM08XX\", \"par09\":\"XXPARAM09XX\", \"par10\":\"XXPARAM10XX\"}}"
|
||||
],
|
||||
"media":null,
|
||||
"trigger":null,
|
||||
"pasoRequerido":"venta"
|
||||
},
|
||||
"rnd2":{
|
||||
"replyMessage":[
|
||||
""
|
||||
],
|
||||
"media":null,
|
||||
"trigger":null,
|
||||
"actions":{
|
||||
"title":"¿Que te interesa ver?",
|
||||
"message":"%saludo%\nHoy es %dia_semana%.\nSon las %hora24%:%minutos% hrs.\nSon las %hora12%:%minutos% %ampm%\n*Palabra random:* %rnd_arbol,burro,cabra,dinosaurio,elefante,fuego,gorila%\n*Emoji random:* %rnd_👍🏽,😁,🤣,🤔,🤦🏽♂️,🙄,😎%\n*Número random:* %rnd_1,2,3,4,5,6,7%\n",
|
||||
"footer":"Gracias",
|
||||
"buttons":[
|
||||
{"body":"Cursos"},
|
||||
{"body":"Youtube"},
|
||||
{"body":"Telegram"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"clientes":{
|
||||
"replyMessage":[
|
||||
"%saludo%,\nPor favor escribe la *ruta* y el *almacén* de la ruta de la que quieres recuperar los clientes, separados por una diagonal.\nEjemplo: *101/6*\n"
|
||||
],
|
||||
"media":null,
|
||||
"trigger":null
|
||||
},
|
||||
"recuperamosClientes":{
|
||||
"replyMessage":[
|
||||
"/URL=http://localhost:8888/dbrquery?j={\"query\":\"proc_recuperaClientesNuevos\",\"exec\":\"ExecuteCommand\",\"params\":{\"par01\":\"XXPARAM01XX\", \"par02\":\"XXPARAM02XX\", \"par03\":\"XXPARAM03XX\"}}"
|
||||
],
|
||||
"media":null,
|
||||
"trigger":null,
|
||||
"pasoRequerido":"clientes"
|
||||
}
|
||||
}
|
||||
0
media/.gitkeep
Normal file
0
media/.gitkeep
Normal file
0
mediaSend/.gitkeep
Normal file
0
mediaSend/.gitkeep
Normal file
BIN
mediaSend/nota-de-voz.mp3
Normal file
BIN
mediaSend/nota-de-voz.mp3
Normal file
Binary file not shown.
21
middleware/client.js
Normal file
21
middleware/client.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const middlewareClient = (client = null) => async (req, res, next) => {
|
||||
try {
|
||||
|
||||
if(!client){
|
||||
res.status(409)
|
||||
console.log(client)
|
||||
res.send({ error: 'Error de client.' })
|
||||
}else{
|
||||
req.clientWs = client;
|
||||
next()
|
||||
}
|
||||
|
||||
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
res.status(409)
|
||||
res.send({ error: 'Error de client' })
|
||||
}
|
||||
|
||||
}
|
||||
module.exports = { middlewareClient }
|
||||
0
middleware/db.js
Normal file
0
middleware/db.js
Normal file
9479
package-lock.json
generated
Normal file
9479
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
39
package.json
Normal file
39
package.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "test-ws-bot",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"start": "node ./app.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@google-cloud/dialogflow": "^5.2.0",
|
||||
"axios": "^0.27.2",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.0.1",
|
||||
"exceljs": "^4.3.0",
|
||||
"express": "^4.18.1",
|
||||
"file-type": "^17.1.6",
|
||||
"mime-db": "^1.52.0",
|
||||
"moment": "^2.29.4",
|
||||
"mysql": "^2.18.1",
|
||||
"nanoid": "^3.0.0",
|
||||
"qr-image": "^3.2.0",
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"socket.io": "^4.5.1",
|
||||
"stormdb": "^0.6.0",
|
||||
"whatsapp-web.js": "^1.18.4",
|
||||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"pm2": "^5.2.0",
|
||||
"prettier": "2.7.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "16.x"
|
||||
}
|
||||
}
|
||||
7
routes/api.js
Normal file
7
routes/api.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const express = require('express')
|
||||
const router = express.Router();
|
||||
const { sendMessagePost } = require('../controllers/web')|
|
||||
|
||||
router.post('/send', sendMessagePost)
|
||||
|
||||
module.exports = router
|
||||
7
routes/web.js
Normal file
7
routes/web.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const express = require('express');
|
||||
const router = express.Router()
|
||||
const { getQr } = require('../controllers/web')
|
||||
|
||||
router.use('/qr', getQr)
|
||||
|
||||
module.exports = router
|
||||
38
spam.json
Normal file
38
spam.json
Normal file
@@ -0,0 +1,38 @@
|
||||
[
|
||||
{
|
||||
"numero":"5215554192439"
|
||||
},
|
||||
{
|
||||
"numero":"5215527026728"
|
||||
},
|
||||
{
|
||||
"numero":"5215527026728"
|
||||
},
|
||||
{
|
||||
"numero":"5215527026728"
|
||||
},
|
||||
{
|
||||
"numero":"5215527026728"
|
||||
},
|
||||
{
|
||||
"numero":"5215527026728"
|
||||
},
|
||||
{
|
||||
"numero":"5215527026728"
|
||||
},
|
||||
{
|
||||
"numero":"5215527026728"
|
||||
},
|
||||
{
|
||||
"numero":"5215527026728"
|
||||
},
|
||||
{
|
||||
"numero":"5215527026728"
|
||||
},
|
||||
{
|
||||
"numero":"5215527026728"
|
||||
},
|
||||
{
|
||||
"numero":"5215554192439"
|
||||
}
|
||||
]
|
||||
79
sql-bot.sql
Normal file
79
sql-bot.sql
Normal file
@@ -0,0 +1,79 @@
|
||||
-- MySQL dump 10.13 Distrib 8.0.27, for Win64 (x86_64)
|
||||
--
|
||||
-- Host: 127.0.0.1 Database: db_test
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 5.7.33
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!50503 SET NAMES utf8 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `initial`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `initial`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `initial` (
|
||||
`option_key` varchar(500) DEFAULT NULL,
|
||||
`keywords` varchar(45) DEFAULT NULL,
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `initial`
|
||||
--
|
||||
|
||||
LOCK TABLES `initial` WRITE;
|
||||
/*!40000 ALTER TABLE `initial` DISABLE KEYS */;
|
||||
INSERT INTO `initial` VALUES ('STEP_1','hola, hola!,ola,inicio,welcome',2),('STEP_2','cursos,info,curso',3),('STEP_2_1','angular',4),('STEP_2_2','node',5),('STEP_2_3','ngrx',6),('STEP_2_4','aws',7),('STEP_3','asesor',8),('STEP_4','muchas gracias,gracias,vale gracias',9);
|
||||
/*!40000 ALTER TABLE `initial` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `response`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `response`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `response` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`option_key` varchar(45) DEFAULT NULL,
|
||||
`replyMessage` varchar(45) DEFAULT NULL,
|
||||
`trigger` varchar(45) DEFAULT NULL,
|
||||
`media` varchar(200) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `response`
|
||||
--
|
||||
|
||||
LOCK TABLES `response` WRITE;
|
||||
/*!40000 ALTER TABLE `response` DISABLE KEYS */;
|
||||
INSERT INTO `response` VALUES (1,'STEP_1','Hola soy el bot escribe curso',NULL,NULL),(2,'STEP_2','Te envio esto',NULL,'https://s2.q4cdn.com/175719177/files/doc_presentations/Placeholder-PDF.pdf');
|
||||
/*!40000 ALTER TABLE `response` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2022-01-18 20:52:34
|
||||
Reference in New Issue
Block a user