feat: Added Typebot integration

This commit is contained in:
Davidson Gomes 2023-08-07 15:43:57 -03:00
parent a16b5f4644
commit 7c5d94c19e
11 changed files with 140 additions and 63 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -983,11 +983,24 @@ export const typebotSchema: JSONSchema7 = {
url: { type: 'string' },
typebot: { type: 'string' },
expire: { type: 'integer' },
delay_message: { type: 'integer' },
unknown_message: { type: 'string' },
},
required: ['enabled', 'url', 'typebot', 'expire'],
...isNotEmpty('enabled', 'url', 'typebot', 'expire'),
};
export const typebotStatusSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
remoteJid: { type: 'string' },
status: { type: 'string', enum: ['opened', 'closed', 'paused'] },
},
required: ['remoteJid', 'status'],
...isNotEmpty('remoteJid', 'status'),
};
export const proxySchema: JSONSchema7 = {
$id: v4(),
type: 'object',

View File

@ -64,6 +64,8 @@ export class InstanceController {
typebot_url,
typebot,
typebot_expire,
typebot_delay_message,
typebot_unknown_message,
}: InstanceDto) {
try {
this.logger.verbose('requested createInstance from ' + instanceName + ' instance');
@ -241,6 +243,8 @@ export class InstanceController {
url: typebot_url,
typebot: typebot,
expire: typebot_expire,
delay_message: typebot_delay_message,
unknown_message: typebot_unknown_message,
});
} catch (error) {
this.logger.log(error);
@ -295,6 +299,8 @@ export class InstanceController {
url: typebot_url,
typebot,
expire: typebot_expire,
delay_message: typebot_delay_message,
unknown_message: typebot_unknown_message,
},
settings,
qrcode: getQrcode,
@ -384,6 +390,8 @@ export class InstanceController {
url: typebot_url,
typebot,
expire: typebot_expire,
delay_message: typebot_delay_message,
unknown_message: typebot_unknown_message,
},
settings,
chatwoot: {

View File

@ -33,4 +33,9 @@ export class TypebotController {
logger.verbose('requested findTypebot from ' + instance.instanceName + ' instance');
return this.typebotService.find(instance);
}
public async changeStatus(instance: InstanceDto, data: any) {
logger.verbose('requested changeStatus from ' + instance.instanceName + ' instance');
return this.typebotService.changeStatus(instance, data);
}
}

View File

@ -25,6 +25,8 @@ export class InstanceDto {
typebot_url?: string;
typebot?: string;
typebot_expire?: number;
typebot_delay_message?: number;
typebot_unknown_message?: string;
proxy_enabled?: boolean;
proxy_proxy?: string;
}

View File

@ -1,6 +1,7 @@
export class Session {
remoteJid?: string;
sessionId?: string;
status?: string;
createdAt?: number;
updateAt?: number;
}
@ -10,5 +11,7 @@ export class TypebotDto {
url: string;
typebot?: string;
expire?: number;
delay_message?: number;
unknown_message?: string;
sessions?: Session[];
}

View File

@ -5,6 +5,7 @@ import { dbserver } from '../../libs/db.connect';
class Session {
remoteJid?: string;
sessionId?: string;
status?: string;
createdAt?: number;
updateAt?: number;
}
@ -15,6 +16,8 @@ export class TypebotRaw {
url: string;
typebot?: string;
expire?: number;
delay_message?: number;
unknown_message?: string;
sessions?: Session[];
}
@ -24,10 +27,13 @@ const typebotSchema = new Schema<TypebotRaw>({
url: { type: String, required: true },
typebot: { type: String, required: true },
expire: { type: Number, required: true },
delay_message: { type: Number, required: true },
unknown_message: { type: String, required: true },
sessions: [
{
remoteJid: { type: String, required: true },
sessionId: { type: String, required: true },
status: { type: String, required: true },
createdAt: { type: Number, required: true },
updateAt: { type: Number, required: true },
},

View File

@ -1,7 +1,7 @@
import { RequestHandler, Router } from 'express';
import { Logger } from '../../config/logger.config';
import { instanceNameSchema, typebotSchema } from '../../validate/validate.schema';
import { instanceNameSchema, typebotSchema, typebotStatusSchema } from '../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router';
import { InstanceDto } from '../dto/instance.dto';
import { TypebotDto } from '../dto/typebot.dto';
@ -44,6 +44,22 @@ export class TypebotRouter extends RouterBroker {
execute: (instance) => typebotController.findTypebot(instance),
});
res.status(HttpStatus.OK).json(response);
})
.post(this.routerPath('changeStatus'), ...guards, async (req, res) => {
logger.verbose('request received in findTypebot');
logger.verbose('request body: ');
logger.verbose(req.body);
logger.verbose('request query: ');
logger.verbose(req.query);
const response = await this.dataValidate<InstanceDto>({
request: req,
schema: typebotStatusSchema,
ClassRef: InstanceDto,
execute: (instance, data) => typebotController.changeStatus(instance, data),
});
res.status(HttpStatus.OK).json(response);
});
}

View File

@ -33,23 +33,57 @@ export class TypebotService {
}
}
public async changeStatus(instance: InstanceDto, data: any) {
const remoteJid = data.remoteJid;
const status = data.status;
const findData = await this.find(instance);
const session = findData.sessions.find((session) => session.remoteJid === remoteJid);
if (session) {
if (status === 'closed') {
findData.sessions.splice(findData.sessions.indexOf(session), 1);
const typebotData = {
enabled: true,
url: findData.url,
typebot: findData.typebot,
expire: findData.expire,
sessions: findData.sessions,
};
this.create(instance, typebotData);
return { typebot: { ...instance, typebot: typebotData } };
}
findData.sessions.map((session) => {
if (session.remoteJid === remoteJid) {
session.status = status;
}
});
}
const typebotData = {
enabled: true,
url: findData.url,
typebot: findData.typebot,
expire: findData.expire,
sessions: findData.sessions,
};
this.create(instance, typebotData);
return { typebot: { ...instance, typebot: typebotData } };
}
private getTypeMessage(msg: any) {
this.logger.verbose('get type message');
const types = {
conversation: msg.conversation,
imageMessage: msg.imageMessage?.caption,
videoMessage: msg.videoMessage?.caption,
extendedTextMessage: msg.extendedTextMessage?.text,
messageContextInfo: msg.messageContextInfo?.stanzaId,
stickerMessage: undefined,
documentMessage: msg.documentMessage?.caption,
documentWithCaptionMessage: msg.documentWithCaptionMessage?.message?.documentMessage?.caption,
audioMessage: msg.audioMessage?.caption,
contactMessage: msg.contactMessage?.vcard,
contactsArrayMessage: msg.contactsArrayMessage,
locationMessage: msg.locationMessage,
liveLocationMessage: msg.liveLocationMessage,
};
this.logger.verbose('type message: ' + types);
@ -86,6 +120,10 @@ export class TypebotService {
sessionId: id,
startParams: {
typebot: data.typebot,
prefilledVariables: {
remoteJid: data.remoteJid,
pushName: data.pushName,
},
},
};
@ -95,6 +133,7 @@ export class TypebotService {
data.sessions.push({
remoteJid: data.remoteJid,
sessionId: `${id}-${request.data.sessionId}`,
status: 'opened',
createdAt: Date.now(),
updateAt: Date.now(),
});
@ -114,23 +153,9 @@ export class TypebotService {
}
public async sendWAMessage(instance: InstanceDto, remoteJid: string, messages: any[], input: any[]) {
processMessages(this.waMonitor.waInstances[instance.instanceName], messages, input)
.then(async () => {
if (!input) {
const typebotData = await this.find(instance);
const session = typebotData.sessions.find((session) => session.remoteJid === remoteJid);
if (session) {
typebotData.sessions.splice(typebotData.sessions.indexOf(session), 1);
this.create(instance, typebotData);
}
}
})
.catch((err) => {
console.error('Erro ao processar mensagens:', err);
});
processMessages(this.waMonitor.waInstances[instance.instanceName], messages, input).catch((err) => {
console.error('Erro ao processar mensagens:', err);
});
async function processMessages(instance, messages, input) {
for (const message of messages) {
@ -174,7 +199,7 @@ export class TypebotService {
await instance.textMessage({
number: remoteJid.split('@')[0],
options: {
delay: 1200,
delay: instance.localTypebot.delay_message || 1000,
presence: 'composing',
linkPreview: linkPreview,
},
@ -188,7 +213,7 @@ export class TypebotService {
await instance.mediaMessage({
number: remoteJid.split('@')[0],
options: {
delay: 1200,
delay: instance.localTypebot.delay_message || 1000,
presence: 'composing',
},
mediaMessage: {
@ -202,7 +227,7 @@ export class TypebotService {
await instance.mediaMessage({
number: remoteJid.split('@')[0],
options: {
delay: 1200,
delay: instance.localTypebot.delay_message || 1000,
presence: 'composing',
},
mediaMessage: {
@ -216,7 +241,7 @@ export class TypebotService {
await instance.audioWhatsapp({
number: remoteJid.split('@')[0],
options: {
delay: 1200,
delay: instance.localTypebot.delay_message || 1000,
presence: 'recording',
encoding: true,
},
@ -279,6 +304,7 @@ export class TypebotService {
expire: expire,
sessions: sessions,
remoteJid: remoteJid,
pushName: msg.pushName,
});
await this.sendWAMessage(instance, remoteJid, data.messages, data.input);
@ -287,6 +313,10 @@ export class TypebotService {
}
}
if (session && session.status !== 'opened') {
return;
}
if (!session) {
const data = await this.createNewSession(instance, {
url: url,
@ -294,6 +324,7 @@ export class TypebotService {
expire: expire,
sessions: sessions,
remoteJid: remoteJid,
pushName: msg.pushName,
});
await this.sendWAMessage(instance, remoteJid, data.messages, data.input);
@ -320,22 +351,18 @@ export class TypebotService {
const content = this.getConversationMessage(msg.message);
if (!content) {
return;
}
if (content.toLowerCase() === 'sair') {
sessions.splice(sessions.indexOf(session), 1);
const typebotData = {
enabled: true,
url: url,
typebot: typebot,
expire: expire,
sessions,
};
this.create(instance, typebotData);
if (this.waMonitor.waInstances[instance.instanceName].localTypebot.unknown_message) {
this.waMonitor.waInstances[instance.instanceName].textMessage({
number: remoteJid.split('@')[0],
options: {
delay: this.waMonitor.waInstances[instance.instanceName].localTypebot.delay_message || 1000,
presence: 'composing',
},
textMessage: {
text: this.waMonitor.waInstances[instance.instanceName].localTypebot.unknown_message,
},
});
}
return;
}
@ -346,18 +373,6 @@ export class TypebotService {
const request = await axios.post(url + '/api/v1/sendMessage', reqData);
if (!request.data.input) {
sessions.splice(sessions.indexOf(session), 1);
await this.createNewSession(instance, {
url: url,
typebot: typebot,
expire: expire,
sessions: sessions,
remoteJid: remoteJid,
});
}
await this.sendWAMessage(instance, remoteJid, request.data.messages, request.data.input);
return;

View File

@ -45,7 +45,6 @@ import { release } from 'os';
import { join } from 'path';
import P from 'pino';
import { ProxyAgent } from 'proxy-agent';
// import { ProxyAgent } from 'proxy-agent';
import qrcode, { QRCodeToDataURLOptions } from 'qrcode';
import qrcodeTerminal from 'qrcode-terminal';
import sharp from 'sharp';
@ -149,7 +148,7 @@ export class WAStartupService {
private readonly localSettings: wa.LocalSettings = {};
private readonly localWebsocket: wa.LocalWebsocket = {};
private readonly localRabbitmq: wa.LocalRabbitmq = {};
private readonly localTypebot: wa.LocalTypebot = {};
public readonly localTypebot: wa.LocalTypebot = {};
private readonly localProxy: wa.LocalProxy = {};
public stateConnection: wa.StateConnection = { state: 'close' };
public readonly storePath = join(ROOT_DIR, 'store');
@ -506,6 +505,12 @@ export class WAStartupService {
this.localTypebot.expire = data?.expire;
this.logger.verbose(`Typebot expire: ${this.localTypebot.expire}`);
this.localTypebot.delay_message = data?.delay_message;
this.logger.verbose(`Typebot delay_message: ${this.localTypebot.delay_message}`);
this.localTypebot.unknown_message = data?.unknown_message;
this.logger.verbose(`Typebot unknown_message: ${this.localTypebot.unknown_message}`);
this.localTypebot.sessions = data?.sessions;
this.logger.verbose('Typebot loaded');
@ -516,6 +521,8 @@ export class WAStartupService {
await this.repository.typebot.create(data, this.instanceName);
this.logger.verbose(`Typebot typebot: ${data.typebot}`);
this.logger.verbose(`Typebot expire: ${data.expire}`);
this.logger.verbose(`Typebot sessions: ${data.delay_message}`);
this.logger.verbose(`Typebot sessions: ${data.unknown_message}`);
Object.assign(this.localTypebot, data);
this.logger.verbose('Typebot set');
}

View File

@ -91,6 +91,8 @@ export declare namespace wa {
url?: string;
typebot?: string;
expire?: number;
delay_message?: number;
unknown_message?: string;
sessions?: Session[];
};