Skip to content

Instantly share code, notes, and snippets.

@alexchristianqr
Last active September 4, 2022 20:12
Show Gist options
  • Save alexchristianqr/9d90f9eba3b2eb5e25d6bcf583a72fa8 to your computer and use it in GitHub Desktop.
Save alexchristianqr/9d90f9eba3b2eb5e25d6bcf583a72fa8 to your computer and use it in GitHub Desktop.
Clase js para la logica de chatbots
'use strict'
const Chatbot = require('app/SaaS/Chat/Models/Chatbots/Chatbot')
const NodeChatbot = require('app/SaaS/Chat/Models/Chatbots/NodeChatbot')
const ChatbotService = require('app/SaaS/Chat/Services/Chatbots/ChatbotService')
const Ticket = require('app/SaaS/Chat/Models/Conversations/Ticket')
const Message = require('app/SaaS/Chat/Models/Messages/Message')
const User = require('app/Http/Models/Users/User')
class ChatbotChatService {
/**
* Encontrar chatbot
* @param companyId
* @param userId
* @param ticketId
* @param validateContactId
* @return {Promise<{chatbot: null, validateChatbot: boolean}>}
*/
static async findChatbot({ validateContactId, companyId, userId, ticketId }) {
console.log('ChatbotChatService.findChatbot', { companyId, userId, ticketId })
// Set
const result = {
validateChatbot: false,
chatbot: null,
}
// Obtener chatbots
const chatbotsFiltered = await Chatbot.find({
companyId: companyId, // Empresa ID
status: true, // Activo
'deleted.status': false, // Eliminado
})
// Obtener horarios válidos
for (const mychatbot of chatbotsFiltered) {
mychatbot.schedules = mychatbot.schedules.map((item) => {
item.schedule = item.schedule.filter((subitem) => subitem.start.time != null && subitem.end.time != null)
return item
})
}
// No tienes chatbots activos
if (!chatbotsFiltered) {
return result
}
// Validar horario de todos los chatbots activos
const responseSchedule = ChatbotService.validateScheduleChatbotWebhook({
chatbotsFiltered,
})
// Validar chatbot
if (!responseSchedule.validateChatbot) {
return result
}
// console.info({ validateContactId })
if (!validateContactId) {
// Obtener nodo chatbot
const nodeChatbot = await NodeChatbot.findOne(
{
companyId: companyId,
chatbotId: responseSchedule.chatbot._id,
root: true, // Obtener el primer nodo que debe ejecutarse
'deleted.status': false, // Obtener nodos no eliminados
},
['_id'],
)
// Actualizar ticket
await Ticket.updateOne(
{
companyId: companyId, // Empresa ID
_id: ticketId, // Ticket ID
},
{
'tree.chatbotId': responseSchedule.chatbot._id,
'tree.nodeChatbotId': nodeChatbot._id,
},
)
} else {
// Actualizar ticket
await Ticket.updateOne(
{
companyId: companyId, // Empresa ID
_id: ticketId, // Ticket ID
},
{
'tree.chatbotId': responseSchedule.chatbot._id,
},
)
}
// Set
result.validateChatbot = responseSchedule.validateChatbot
result.chatbot = responseSchedule.chatbot
// Response
return result
}
/**
* Encontrar nodo chatbot
* @param companyId
* @param chatbotId
* @param ticketId
* @param messagePayload
* @param validateContactId
* @param ticketFounded
* @return {Promise<*>}
*/
static async findNodeChatbot({ validateContactId, companyId, chatbotId, ticketId, messagePayload, ticketFounded }) {
console.log('ChatbotChatService.findNodeChatbot', { companyId, chatbotId, ticketId, messagePayload })
// Set
let nodeChatbots = null
let nodeChatbot
const result = {
validateNodeChatbot: false,
nodeChatbot: null,
messageNodechatbot: null,
}
// Obtener nodo
console.info({ messagePayload })
if (validateContactId) {
let parentNodeChatbotId = ticketFounded?.tree?.nodeChatbotId
let beforeNodeChatbot = await NodeChatbot.findOne({
companyId: companyId,
chatbotId: chatbotId,
root: false, // Obtener el siguiente nodo que debe ejecutarse
parent: parentNodeChatbotId,
'item.value': messagePayload,
'deleted.status': false, // Obtener nodos no eliminados
})
console.info({ beforeNodeChatbot })
nodeChatbot = await NodeChatbot.findOne({
companyId: companyId,
chatbotId: chatbotId,
_id: beforeNodeChatbot.action.nodeChatbotId,
root: false, // Obtener el siguiente nodo que debe ejecutarse
'deleted.status': false, // Obtener nodos no eliminados
})
} else {
nodeChatbot = await NodeChatbot.findOne({
companyId: companyId,
chatbotId: chatbotId,
root: true, // Obtener el primer nodo que debe ejecutarse
'deleted.status': false, // Obtener nodos no eliminados
})
}
if (!nodeChatbot) {
throw {
message: 'nodo chatbot not found',
status: 400,
}
}
// Set
let message = `${nodeChatbot.item.text}\n`
// Validar tipo nodo
switch (nodeChatbot.type) {
case 'multiple':
// Obtener nodos chatbots
nodeChatbots = await NodeChatbot.find(
{
companyId: companyId,
chatbotId: chatbotId,
_id: { $in: nodeChatbot.nodeChatbotIds },
'deleted.status': false, // Obtener nodos no eliminados
},
['item'],
)
if (!nodeChatbots) {
return result
}
// Iterar nodos
for (let field of nodeChatbots) {
message += `${field.item.value}. ${field.item.text}\n`
}
// Set
result.validateNodeChatbot = true
result.nodeChatbot = nodeChatbot
result.messageNodechatbot = message
break
case 'options':
switch (nodeChatbot.action.type) {
case 'transfer':
case 'archive':
case 'back':
case 'continue':
// Set
result.nodeChatbot = nodeChatbot
result.messageNodechatbot = message
break
case 'finish':
console.info('nodo chatbot finish')
break
default:
}
break
case 'single':
// Obtener nodos chatbots
nodeChatbots = await NodeChatbot.find(
{
companyId: companyId,
chatbotId: chatbotId,
_id: { $in: nodeChatbot.nodeChatbotIds },
'deleted.status': false, // Obtener nodos no eliminados
},
['item'],
)
if (!nodeChatbots) {
return result
}
// Set
result.validateNodeChatbot = true
// Iterar nodos
for (let field of nodeChatbots) {
message += `${field.item.value}. ${field.item.text}\n`
}
// console.info({ message })
// Actualizar ticket}
// console.info('alex #2')
// await Ticket.updateOne(
// {
// companyId: companyId, // Empresa ID
// _id: ticketId, // Ticket ID
// },
// {
// 'tree.chatbotId': chatbotId,
// // 'tree.nodeChatbotId': nodeChatbotId,
// },
// )
// Set
result.nodeChatbot = nodeChatbot
result.messageNodechatbot = message
break
default:
throw {
message: 'type nodo chatbot not support',
status: 400,
}
}
// Response
return result
}
/**
* Responder como nodo chatbot o chatbot
* @param contactId
* @param userId
* @param companyId
* @param channel
* @param conversationId
* @param ticket
* @param ticketId
* @param payload
* @param message
* @param provider
* @param messageType
* @param url
* @return {Promise<*>}
*/
static async setMessageForChatbot({ validateContactId, contactId, userId, companyId, channel, conversationId, ticket, ticketId, payload, messagePayload, provider, messageType, url }) {
console.log('ChatbotChatService.setMessageForChatbot', { messagePayload, validateContactId })
// Set
let chatbotId = null
let messageString = ''
let responseChatbot = null
let result = {
lastMessage: null,
message: null,
}
// Contacto existe
if (validateContactId) {
// Obtener chatbot
const { validateChatbot, chatbot } = await this.findChatbot({
companyId,
userId,
ticketId,
validateContactId,
})
if (!validateChatbot) {
// Preparar mensaje
const responseChatbot = await this.dispatchWebhookMessage({
validateContactId,
provider,
companyId,
channel,
conversationId,
userId,
ticket,
chatbotId,
messagePayload,
payload,
contactId,
messageString,
messageType,
url,
})
// Set
result.lastMessage = responseChatbot.lastMessage
result.message = responseChatbot.message
// Response
return result
}
// Set
chatbotId = chatbot._id
// Obtener ticket
const ticketFounded = await Ticket.findOne({
companyId: companyId, // Empresa ID
channel: channel, // Canal
conversationId: conversationId, // Conversación ID
ticket: ticket, // Numero de ticket
'tree.chatbotId': chatbotId, // Chatbot ID
})
if (!ticketFounded) {
throw new Error('not found ticket')
}
// Obtener nodo chatbot
const { validateNodeChatbot, nodeChatbot, messageNodechatbot } = await ChatbotChatService.findNodeChatbot({
companyId,
chatbotId,
messagePayload,
validateContactId,
ticketFounded,
})
if (!validateNodeChatbot) {
throw new Error('not found node chatbot')
}
// Obtener usuario chatbot
let userChatbotId = await this.getUserChatbot(companyId)
// console.info({ userChatbotId })
// Preparar mensaje
responseChatbot = await this.dispatchWebhookMessage({
validateContactId,
provider,
companyId,
channel,
conversationId,
userId,
ticket,
chatbotId,
nodeChatbot,
payload,
messagePayload,
contactId,
messageString,
messageType,
url,
userChatbotId,
})
// Set
result.lastMessage = responseChatbot.lastMessage
result.message = responseChatbot.message
// TODO
// Set
messageString = `${messageNodechatbot}`
// Crear ultimo mensaje
await Message.create({
channel: channel, // Canal
provider: provider, // Proveedor
sender: payload.sender,
recipient: payload.recipient,
guid: payload.guid,
ticket: ticket,
conversationId: conversationId, // ObjectId()
userId: userChatbotId, // ObjectId()
message: messageString, // Mensaje
messageType: messageType, // Tipo de mensaje
messageStatus: 'delivered', // Entregado
mediafileUrl: url,
status: true, // Activo
})
// TODO
}
// Contacto no existe
else {
// Obtener chatbot
const { validateChatbot, chatbot } = await this.findChatbot({
companyId,
userId,
validateContactId,
})
if (!validateChatbot) {
// Preparar mensaje
const responseChatbot = await this.dispatchWebhookMessage({
validateContactId,
provider,
companyId,
channel,
conversationId,
userId,
ticket,
chatbotId,
messagePayload,
payload,
contactId,
messageString,
messageType,
url,
})
// Set
result.lastMessage = responseChatbot.lastMessage
result.message = responseChatbot.message
// Response
return result
}
// Set
chatbotId = chatbot._id
// Obtener nodo chatbot
const { validateNodeChatbot, nodeChatbot, messageNodechatbot } = await ChatbotChatService.findNodeChatbot({
companyId,
chatbotId,
validateContactId,
})
if (!validateNodeChatbot) {
throw new Error('not found node chatbot')
}
// Obtener usuario chatbot
let userChatbotId = await this.getUserChatbot(companyId)
console.log({ userChatbotId })
// Preparar mensaje
const responseChatbot = await this.dispatchWebhookMessage({
validateContactId,
provider,
companyId,
channel,
conversationId,
userId,
ticket,
chatbotId,
nodeChatbot,
messagePayload,
messageNodechatbot,
payload,
contactId,
messageString,
messageType,
url,
userChatbotId,
})
// Set
result.lastMessage = responseChatbot.lastMessage
result.message = responseChatbot.message
// Set
messagePayload = `${messageNodechatbot}`
// Crear ultimo mensaje
await Message.create({
channel: channel, // Canal
provider: provider, // Proveedor
sender: payload.sender,
recipient: payload.recipient,
guid: payload.guid,
ticket: ticket,
conversationId: conversationId, // ObjectId()
userId: userChatbotId, // ObjectId()
message: messagePayload, // Mensaje
messageType: messageType, // Tipo de mensaje
messageStatus: 'delivered', // Entregado
mediafileUrl: url,
status: true, // Activo
})
}
// Response
return result
}
/**
* Preparar mensaje
* @param validateContactId
* @param provider
* @param companyId
* @param channel
* @param conversationId
* @param userId
* @param ticket
* @param chatbotId
* @param nodeChatbot
* @param messagePayload
* @param messageNodechatbot
* @param payload
* @param contactId
* @param messageString
* @param messageType
* @param url
* @param userChatbotId
* @return {Promise<void>}
*/
static async dispatchWebhookMessage({
validateContactId,
provider,
companyId,
channel,
conversationId,
userId,
ticket,
chatbotId,
nodeChatbot,
messagePayload,
messageNodechatbot,
payload,
contactId,
messageString,
messageType,
url,
userChatbotId,
}) {
console.log('Chatbot.dispatchWebhookMessage', { messagePayload, messageNodechatbot, messageString })
// Set
let nodeChatbotId
if (validateContactId && nodeChatbot) {
// Set
nodeChatbotId = nodeChatbot._id
// Actualizar ticket
await Ticket.updateOne(
{
companyId: companyId, // Empresa ID
channel: channel, // Canal
conversationId: conversationId, // Conversacion ID
userId: userId, // Usuario Id
ticket: ticket, // Numero de ticket
'tree.chatbotId': chatbotId, // Chatbot ID
},
{
'tree.nodeChatbotId': nodeChatbotId, // Nodo chatbot ID
},
)
} else {
if (chatbotId) {
// Obtener nodo chatbot
const tmpnodeChatbot = await NodeChatbot.findOne(
{
companyId: companyId,
chatbotId: chatbotId,
root: true, // Obtener el primer nodo que debe ejecutarse
'deleted.status': false, // Obtener nodos no eliminados
},
['_id'],
)
// Actualizar ticket
await Ticket.updateOne(
{
companyId: companyId, // Empresa ID
channel: channel, // Canal
conversationId: conversationId, // Conversacion ID
userId: userId, // Usuario Id
ticket: ticket, // Numero de ticket
},
{
'tree.chatbotId': chatbotId, // Chatbot ID
'tree.nodeChatbotId': tmpnodeChatbot._id, // Nodo chatbot ID
},
)
}
}
// Crear ultimo mensaje
const lastMessage = await Message.create({
channel: channel, // Canal
provider: provider, // Proveedor
sender: payload.sender,
recipient: payload.recipient,
guid: payload.guid,
ticket: ticket,
conversationId: conversationId, // ObjectId()
contactId: contactId, // ObjectId()
message: messagePayload, // Mensaje
messageType: messageType, // Tipo de mensaje
messageStatus: 'delivered', // Entregado
mediafileUrl: url,
status: true, // Activo
})
// Obtener ultimo mensaje
const message = await Message.findOne({
_id: lastMessage._id, // ObjectId()
}).populate('contactId')
// Set RelationsShip
message.contact = message.contactId
message.contactId = message.contact._id
// Response
return {
message,
lastMessage,
}
}
/**
* Obtener usuario chatbot por empresa ID
* @param companyId
* @returns {Promise<*>}
*/
static async getUserChatbot(companyId) {
// Obtener usuario chatbot
const user = await User.findOne(
{
companyId: companyId,
isBot: true,
},
['_id'],
)
// Response
return user._id
}
}
module.exports = ChatbotChatService
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment