mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-13 15:14:49 -06:00
feat: Added Typebot integration
This commit is contained in:
parent
a16b5f4644
commit
7c5d94c19e
@ -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',
|
||||
|
@ -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: {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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[];
|
||||
}
|
||||
|
@ -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 },
|
||||
},
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -91,6 +91,8 @@ export declare namespace wa {
|
||||
url?: string;
|
||||
typebot?: string;
|
||||
expire?: number;
|
||||
delay_message?: number;
|
||||
unknown_message?: string;
|
||||
sessions?: Session[];
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user