Merge branch 'ev2' into v2.0.0

This commit is contained in:
Stênio Aníbal 2024-08-20 11:26:34 -03:00
commit ec9e227413
21 changed files with 675 additions and 398 deletions

View File

@ -1,3 +1,10 @@
# 2.1.0 (develop)
### Features
* Improved layout manager
* Translation in manager: English, Portuguese, Spanish and French
# 2.0.10 (2024-08-16 16:23) # 2.0.10 (2024-08-16 16:23)
### Features ### Features

File diff suppressed because one or more lines are too long

381
manager/dist/assets/index-CNPbB3iJ.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,8 +5,8 @@
<link rel="icon" type="image/png" href="/assets/images/evolution-logo.png" /> <link rel="icon" type="image/png" href="/assets/images/evolution-logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Evolution Manager</title> <title>Evolution Manager</title>
<script type="module" crossorigin src="/assets/index-Cqx_OwQi.js"></script> <script type="module" crossorigin src="/assets/index-CNPbB3iJ.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DZ0gaAHg.css"> <link rel="stylesheet" crossorigin href="/assets/index-BJ9JMAl_.css">
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

View File

@ -1,6 +1,6 @@
{ {
"name": "evolution-api", "name": "evolution-api",
"version": "2.0.10", "version": "2.1.0",
"description": "Rest api for communication with WhatsApp", "description": "Rest api for communication with WhatsApp",
"main": "./dist/main.js", "main": "./dist/main.js",
"type": "commonjs", "type": "commonjs",

View File

@ -37,6 +37,7 @@ enum TriggerType {
all all
keyword keyword
none none
advanced
} }
enum TriggerOperator { enum TriggerOperator {

View File

@ -0,0 +1,2 @@
-- AlterEnum
ALTER TYPE "TriggerType" ADD VALUE 'advanced';

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "IntegrationSession" ADD COLUMN "context" JSONB;

View File

@ -37,6 +37,7 @@ enum TriggerType {
all all
keyword keyword
none none
advanced
} }
enum TriggerOperator { enum TriggerOperator {
@ -393,6 +394,7 @@ model IntegrationSession {
pushName String? pushName String?
status SessionStatus status SessionStatus
awaitUser Boolean @default(false) @db.Boolean awaitUser Boolean @default(false) @db.Boolean
context Json?
createdAt DateTime? @default(now()) @db.Timestamp createdAt DateTime? @default(now()) @db.Timestamp
updatedAt DateTime @updatedAt @db.Timestamp updatedAt DateTime @updatedAt @db.Timestamp
Message Message[] Message Message[]

View File

@ -5,6 +5,7 @@ import { WAMonitoringService } from '@api/services/monitor.service';
import { Auth, ConfigService, HttpServer, S3 } from '@config/env.config'; import { Auth, ConfigService, HttpServer, S3 } from '@config/env.config';
import { Logger } from '@config/logger.config'; import { Logger } from '@config/logger.config';
import { Dify, DifySetting, IntegrationSession, Message } from '@prisma/client'; import { Dify, DifySetting, IntegrationSession, Message } from '@prisma/client';
import { advancedOperatorsSearch } from '@utils/advancedOperatorsSearch';
import { sendTelemetry } from '@utils/sendTelemetry'; import { sendTelemetry } from '@utils/sendTelemetry';
import axios from 'axios'; import axios from 'axios';
import { Readable } from 'stream'; import { Readable } from 'stream';
@ -114,6 +115,23 @@ export class DifyService {
} }
} }
if (data.triggerType === 'advanced') {
if (!data.triggerValue) {
throw new Error('Trigger value is required');
}
const checkDuplicate = await this.prismaRepository.dify.findFirst({
where: {
triggerValue: data.triggerValue,
instanceId: instanceId,
},
});
if (checkDuplicate) {
throw new Error('Trigger already exists');
}
}
try { try {
const dify = await this.prismaRepository.dify.create({ const dify = await this.prismaRepository.dify.create({
data: { data: {
@ -239,9 +257,25 @@ export class DifyService {
where: { where: {
triggerOperator: data.triggerOperator, triggerOperator: data.triggerOperator,
triggerValue: data.triggerValue, triggerValue: data.triggerValue,
id: { id: { not: difyId },
not: difyId, instanceId: instanceId,
}, },
});
if (checkDuplicate) {
throw new Error('Trigger already exists');
}
}
if (data.triggerType === 'advanced') {
if (!data.triggerValue) {
throw new Error('Trigger value is required');
}
const checkDuplicate = await this.prismaRepository.dify.findFirst({
where: {
triggerValue: data.triggerValue,
id: { not: difyId },
instanceId: instanceId, instanceId: instanceId,
}, },
}); });
@ -727,6 +761,19 @@ export class DifyService {
if (findTriggerAll) return findTriggerAll; if (findTriggerAll) return findTriggerAll;
const findTriggerAdvanced = await this.prismaRepository.dify.findMany({
where: {
enabled: true,
triggerType: 'advanced',
instanceId: instanceId,
},
});
for (const advanced of findTriggerAdvanced) {
if (advancedOperatorsSearch(content, advanced.triggerValue)) {
return advanced;
}
}
// Check for exact match // Check for exact match
const findTriggerEquals = await this.prismaRepository.dify.findFirst({ const findTriggerEquals = await this.prismaRepository.dify.findFirst({
where: { where: {

View File

@ -29,7 +29,7 @@ export const difySchema: JSONSchema7 = {
botType: { type: 'string', enum: ['chatBot', 'textGenerator', 'agent', 'workflow'] }, botType: { type: 'string', enum: ['chatBot', 'textGenerator', 'agent', 'workflow'] },
apiUrl: { type: 'string' }, apiUrl: { type: 'string' },
apiKey: { type: 'string' }, apiKey: { type: 'string' },
triggerType: { type: 'string', enum: ['all', 'keyword', 'none'] }, triggerType: { type: 'string', enum: ['all', 'keyword', 'none', 'advanced'] },
triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith', 'regex'] }, triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith', 'regex'] },
triggerValue: { type: 'string' }, triggerValue: { type: 'string' },
expire: { type: 'integer' }, expire: { type: 'integer' },

View File

@ -10,6 +10,7 @@ import { WAMonitoringService } from '@api/services/monitor.service';
import { ConfigService, Language, S3 } from '@config/env.config'; import { ConfigService, Language, S3 } from '@config/env.config';
import { Logger } from '@config/logger.config'; import { Logger } from '@config/logger.config';
import { IntegrationSession, Message, OpenaiBot, OpenaiCreds, OpenaiSetting } from '@prisma/client'; import { IntegrationSession, Message, OpenaiBot, OpenaiCreds, OpenaiSetting } from '@prisma/client';
import { advancedOperatorsSearch } from '@utils/advancedOperatorsSearch';
import { sendTelemetry } from '@utils/sendTelemetry'; import { sendTelemetry } from '@utils/sendTelemetry';
import axios from 'axios'; import axios from 'axios';
import { downloadMediaMessage } from 'baileys'; import { downloadMediaMessage } from 'baileys';
@ -238,6 +239,23 @@ export class OpenaiService {
} }
} }
if (data.triggerType === 'advanced') {
if (!data.triggerValue) {
throw new Error('Trigger value is required');
}
const checkDuplicate = await this.prismaRepository.openaiBot.findFirst({
where: {
triggerValue: data.triggerValue,
instanceId: instanceId,
},
});
if (checkDuplicate) {
throw new Error('Trigger already exists');
}
}
try { try {
const openaiBot = await this.prismaRepository.openaiBot.create({ const openaiBot = await this.prismaRepository.openaiBot.create({
data: { data: {
@ -390,9 +408,25 @@ export class OpenaiService {
where: { where: {
triggerOperator: data.triggerOperator, triggerOperator: data.triggerOperator,
triggerValue: data.triggerValue, triggerValue: data.triggerValue,
id: { id: { not: openaiBotId },
not: openaiBotId, instanceId: instanceId,
}, },
});
if (checkDuplicate) {
throw new Error('Trigger already exists');
}
}
if (data.triggerType === 'advanced') {
if (!data.triggerValue) {
throw new Error('Trigger value is required');
}
const checkDuplicate = await this.prismaRepository.openaiBot.findFirst({
where: {
triggerValue: data.triggerValue,
id: { not: openaiBotId },
instanceId: instanceId, instanceId: instanceId,
}, },
}); });
@ -452,7 +486,7 @@ export class OpenaiService {
const openaiBots = await this.prismaRepository.openaiBot.findMany({ const openaiBots = await this.prismaRepository.openaiBot.findMany({
where: { where: {
instanceId: instanceId, instanceId,
}, },
include: { include: {
sessions: true, sessions: true,
@ -600,13 +634,14 @@ export class OpenaiService {
public async fetchDefaultSettings(instance: InstanceDto) { public async fetchDefaultSettings(instance: InstanceDto) {
try { try {
const instanceId = await this.prismaRepository.instance const instanceId = (
.findFirst({ await this.prismaRepository.instance.findFirst({
select: { id: true },
where: { where: {
name: instance.instanceName, name: instance.instanceName,
}, },
}) })
.then((instance) => instance.id); )?.id;
const settings = await this.prismaRepository.openaiSetting.findFirst({ const settings = await this.prismaRepository.openaiSetting.findFirst({
where: { where: {
@ -931,6 +966,19 @@ export class OpenaiService {
if (findTriggerAll) return findTriggerAll; if (findTriggerAll) return findTriggerAll;
const findTriggerAdvanced = await this.prismaRepository.openaiBot.findMany({
where: {
enabled: true,
triggerType: 'advanced',
instanceId: instanceId,
},
});
for (const advanced of findTriggerAdvanced) {
if (advancedOperatorsSearch(content, advanced.triggerValue)) {
return advanced;
}
}
// Check for exact match // Check for exact match
const findTriggerEquals = await this.prismaRepository.openaiBot.findFirst({ const findTriggerEquals = await this.prismaRepository.openaiBot.findFirst({
where: { where: {
@ -1070,7 +1118,7 @@ export class OpenaiService {
}, debounceTime * 1000); }, debounceTime * 1000);
} }
public async sendOpenai(instance: InstanceDto, remoteJid: string, msg: Message) { public async sendOpenai(instance: InstanceDto, remoteJid: string, pushName: string, msg: Message) {
try { try {
const settings = await this.prismaRepository.openaiSetting.findFirst({ const settings = await this.prismaRepository.openaiSetting.findFirst({
where: { where: {
@ -1193,7 +1241,7 @@ export class OpenaiService {
}; };
if (stopBotFromMe && key.fromMe && session) { if (stopBotFromMe && key.fromMe && session) {
await this.prismaRepository.integrationSession.update({ session = await this.prismaRepository.integrationSession.update({
where: { where: {
id: session.id, id: session.id,
}, },
@ -1201,7 +1249,6 @@ export class OpenaiService {
status: 'paused', status: 'paused',
}, },
}); });
return;
} }
if (!listeningFromMe && key.fromMe) { if (!listeningFromMe && key.fromMe) {
@ -1214,6 +1261,8 @@ export class OpenaiService {
await this.processOpenaiAssistant( await this.processOpenaiAssistant(
this.waMonitor.waInstances[instance.instanceName], this.waMonitor.waInstances[instance.instanceName],
remoteJid, remoteJid,
pushName,
key.fromMe,
findOpenai, findOpenai,
session, session,
settings, settings,
@ -1237,6 +1286,8 @@ export class OpenaiService {
await this.processOpenaiAssistant( await this.processOpenaiAssistant(
this.waMonitor.waInstances[instance.instanceName], this.waMonitor.waInstances[instance.instanceName],
remoteJid, remoteJid,
pushName,
key.fromMe,
findOpenai, findOpenai,
session, session,
settings, settings,
@ -1304,6 +1355,8 @@ export class OpenaiService {
private async initAssistantNewSession( private async initAssistantNewSession(
instance: any, instance: any,
remoteJid: string, remoteJid: string,
pushName: string,
fromMe: boolean,
openaiBot: OpenaiBot, openaiBot: OpenaiBot,
settings: OpenaiSetting, settings: OpenaiSetting,
session: IntegrationSession, session: IntegrationSession,
@ -1320,7 +1373,7 @@ export class OpenaiService {
} }
const messageData: any = { const messageData: any = {
role: 'user', role: fromMe ? 'assistant' : 'user',
content: [{ type: 'text', text: content }], content: [{ type: 'text', text: content }],
}; };
@ -1342,6 +1395,11 @@ export class OpenaiService {
await this.client.beta.threads.messages.create(data.session.sessionId, messageData); await this.client.beta.threads.messages.create(data.session.sessionId, messageData);
if (fromMe) {
sendTelemetry('/message/sendText');
return;
}
const runAssistant = await this.client.beta.threads.runs.create(data.session.sessionId, { const runAssistant = await this.client.beta.threads.runs.create(data.session.sessionId, {
assistant_id: openaiBot.assistantId, assistant_id: openaiBot.assistantId,
}); });
@ -1350,7 +1408,13 @@ export class OpenaiService {
await instance.client.sendPresenceUpdate('composing', remoteJid); await instance.client.sendPresenceUpdate('composing', remoteJid);
const response = await this.getAIResponse(data.session.sessionId, runAssistant.id, openaiBot.functionUrl); const response = await this.getAIResponse(
data.session.sessionId,
runAssistant.id,
openaiBot.functionUrl,
remoteJid,
pushName,
);
await instance.client.sendPresenceUpdate('paused', remoteJid); await instance.client.sendPresenceUpdate('paused', remoteJid);
@ -1426,10 +1490,15 @@ export class OpenaiService {
} }
} }
private async getAIResponse(threadId: string, runId: string, functionUrl: string) { private async getAIResponse(
threadId: string,
runId: string,
functionUrl: string,
remoteJid: string,
pushName: string,
) {
const getRun = await this.client.beta.threads.runs.retrieve(threadId, runId); const getRun = await this.client.beta.threads.runs.retrieve(threadId, runId);
let toolCalls; let toolCalls;
switch (getRun.status) { switch (getRun.status) {
case 'requires_action': case 'requires_action':
toolCalls = getRun?.required_action?.submit_tool_outputs?.tool_calls; toolCalls = getRun?.required_action?.submit_tool_outputs?.tool_calls;
@ -1447,7 +1516,7 @@ export class OpenaiService {
try { try {
const { data } = await axios.post(functionUrl, { const { data } = await axios.post(functionUrl, {
name: functionName, name: functionName,
arguments: functionArgument, arguments: { ...functionArgument, remoteJid, pushName },
}); });
output = JSON.stringify(data) output = JSON.stringify(data)
@ -1476,13 +1545,13 @@ export class OpenaiService {
} }
} }
return this.getAIResponse(threadId, runId, functionUrl); return this.getAIResponse(threadId, runId, functionUrl, remoteJid, pushName);
case 'queued': case 'queued':
await new Promise((resolve) => setTimeout(resolve, 1000)); await new Promise((resolve) => setTimeout(resolve, 1000));
return this.getAIResponse(threadId, runId, functionUrl); return this.getAIResponse(threadId, runId, functionUrl, remoteJid, pushName);
case 'in_progress': case 'in_progress':
await new Promise((resolve) => setTimeout(resolve, 1000)); await new Promise((resolve) => setTimeout(resolve, 1000));
return this.getAIResponse(threadId, runId, functionUrl); return this.getAIResponse(threadId, runId, functionUrl, remoteJid, pushName);
case 'completed': case 'completed':
return await this.client.beta.threads.messages.list(threadId, { return await this.client.beta.threads.messages.list(threadId, {
run_id: runId, run_id: runId,
@ -1498,12 +1567,14 @@ export class OpenaiService {
private async processOpenaiAssistant( private async processOpenaiAssistant(
instance: any, instance: any,
remoteJid: string, remoteJid: string,
pushName: string,
fromMe: boolean,
openaiBot: OpenaiBot, openaiBot: OpenaiBot,
session: IntegrationSession, session: IntegrationSession,
settings: OpenaiSetting, settings: OpenaiSetting,
content: string, content: string,
) { ) {
if (session && session.status !== 'opened') { if (session && session.status === 'closed') {
return; return;
} }
@ -1535,25 +1606,35 @@ export class OpenaiService {
}); });
} }
await this.initAssistantNewSession(instance, remoteJid, openaiBot, settings, session, content); await this.initAssistantNewSession(
instance,
remoteJid,
pushName,
fromMe,
openaiBot,
settings,
session,
content,
);
return; return;
} }
} }
if (!session) { if (!session) {
await this.initAssistantNewSession(instance, remoteJid, openaiBot, settings, session, content); await this.initAssistantNewSession(instance, remoteJid, pushName, fromMe, openaiBot, settings, session, content);
return; return;
} }
await this.prismaRepository.integrationSession.update({ if (session.status !== 'paused')
where: { await this.prismaRepository.integrationSession.update({
id: session.id, where: {
}, id: session.id,
data: { },
status: 'opened', data: {
awaitUser: false, status: 'opened',
}, awaitUser: false,
}); },
});
if (!content) { if (!content) {
if (settings.unknownMessage) { if (settings.unknownMessage) {
@ -1607,7 +1688,7 @@ export class OpenaiService {
const threadId = session.sessionId; const threadId = session.sessionId;
const messageData: any = { const messageData: any = {
role: 'user', role: fromMe ? 'assistant' : 'user',
content: [{ type: 'text', text: content }], content: [{ type: 'text', text: content }],
}; };
@ -1629,15 +1710,24 @@ export class OpenaiService {
await this.client.beta.threads.messages.create(threadId, messageData); await this.client.beta.threads.messages.create(threadId, messageData);
if (fromMe || session?.status === 'paused') {
sendTelemetry('/message/sendText');
return;
}
const runAssistant = await this.client.beta.threads.runs.create(threadId, { const runAssistant = await this.client.beta.threads.runs.create(threadId, {
assistant_id: openaiBot.assistantId, assistant_id: openaiBot.assistantId,
additional_instructions: `WhatsappApiInfo:
Name: ${pushName}
RemoteJid: ${remoteJid}
`,
}); });
await instance.client.presenceSubscribe(remoteJid); await instance.client.presenceSubscribe(remoteJid);
await instance.client.sendPresenceUpdate('composing', remoteJid); await instance.client.sendPresenceUpdate('composing', remoteJid);
const response = await this.getAIResponse(threadId, runAssistant.id, openaiBot.functionUrl); const response = await this.getAIResponse(threadId, runAssistant.id, openaiBot.functionUrl, remoteJid, pushName);
await instance.client.sendPresenceUpdate('paused', remoteJid); await instance.client.sendPresenceUpdate('paused', remoteJid);

View File

@ -35,7 +35,7 @@ export const openaiSchema: JSONSchema7 = {
assistantMessages: { type: 'array', items: { type: 'string' } }, assistantMessages: { type: 'array', items: { type: 'string' } },
userMessages: { type: 'array', items: { type: 'string' } }, userMessages: { type: 'array', items: { type: 'string' } },
maxTokens: { type: 'integer' }, maxTokens: { type: 'integer' },
triggerType: { type: 'string', enum: ['all', 'keyword', 'none'] }, triggerType: { type: 'string', enum: ['all', 'keyword', 'none', 'advanced'] },
triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith', 'regex'] }, triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith', 'regex'] },
triggerValue: { type: 'string' }, triggerValue: { type: 'string' },
expire: { type: 'integer' }, expire: { type: 'integer' },

View File

@ -6,6 +6,7 @@ import { Events } from '@api/types/wa.types';
import { Auth, ConfigService, HttpServer, S3, Typebot } from '@config/env.config'; import { Auth, ConfigService, HttpServer, S3, Typebot } from '@config/env.config';
import { Logger } from '@config/logger.config'; import { Logger } from '@config/logger.config';
import { Instance, IntegrationSession, Message, Typebot as TypebotModel } from '@prisma/client'; import { Instance, IntegrationSession, Message, Typebot as TypebotModel } from '@prisma/client';
import { advancedOperatorsSearch } from '@utils/advancedOperatorsSearch';
import { sendTelemetry } from '@utils/sendTelemetry'; import { sendTelemetry } from '@utils/sendTelemetry';
import axios from 'axios'; import axios from 'axios';
@ -113,6 +114,23 @@ export class TypebotService {
} }
} }
if (data.triggerType === 'advanced') {
if (!data.triggerValue) {
throw new Error('Trigger value is required');
}
const checkDuplicate = await this.prismaRepository.typebot.findFirst({
where: {
triggerValue: data.triggerValue,
instanceId: instanceId,
},
});
if (checkDuplicate) {
throw new Error('Trigger already exists');
}
}
try { try {
const typebot = await this.prismaRepository.typebot.create({ const typebot = await this.prismaRepository.typebot.create({
data: { data: {
@ -250,6 +268,24 @@ export class TypebotService {
} }
} }
if (data.triggerType === 'advanced') {
if (!data.triggerValue) {
throw new Error('Trigger value is required');
}
const checkDuplicate = await this.prismaRepository.typebot.findFirst({
where: {
triggerValue: data.triggerValue,
id: { not: typebotId },
instanceId: instanceId,
},
});
if (checkDuplicate) {
throw new Error('Trigger already exists');
}
}
try { try {
const typebot = await this.prismaRepository.typebot.update({ const typebot = await this.prismaRepository.typebot.update({
where: { where: {
@ -1287,6 +1323,19 @@ export class TypebotService {
if (findTriggerAll) return findTriggerAll; if (findTriggerAll) return findTriggerAll;
const findTriggerAdvanced = await this.prismaRepository.typebot.findMany({
where: {
enabled: true,
triggerType: 'advanced',
instanceId: instanceId,
},
});
for (const advanced of findTriggerAdvanced) {
if (advancedOperatorsSearch(content, advanced.triggerValue)) {
return advanced;
}
}
// Check for exact match // Check for exact match
const findTriggerEquals = await this.prismaRepository.typebot.findFirst({ const findTriggerEquals = await this.prismaRepository.typebot.findFirst({
where: { where: {

View File

@ -28,7 +28,7 @@ export const typebotSchema: JSONSchema7 = {
description: { type: 'string' }, description: { type: 'string' },
url: { type: 'string' }, url: { type: 'string' },
typebot: { type: 'string' }, typebot: { type: 'string' },
triggerType: { type: 'string', enum: ['all', 'keyword', 'none'] }, triggerType: { type: 'string', enum: ['all', 'keyword', 'none', 'advanced'] },
triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith', 'regex'] }, triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith', 'regex'] },
triggerValue: { type: 'string' }, triggerValue: { type: 'string' },
expire: { type: 'integer' }, expire: { type: 'integer' },

View File

@ -78,6 +78,9 @@ router
return res.status(HttpStatus.OK).json({ return res.status(HttpStatus.OK).json({
status: HttpStatus.OK, status: HttpStatus.OK,
message: 'Credentials are valid', message: 'Credentials are valid',
facebookAppId: process.env.FACEBOOK_APP_ID,
facebookConfigId: process.env.FACEBOOK_CONFIG_ID,
facebookUserToken: process.env.FACEBOOK_USER_TOKEN,
}); });
}) })
.use('/instance', new InstanceRouter(configService, ...guards).router) .use('/instance', new InstanceRouter(configService, ...guards).router)

View File

@ -1243,6 +1243,7 @@ export class BaileysStartupService extends ChannelStartupService {
await this.openaiService.sendOpenai( await this.openaiService.sendOpenai(
{ instanceName: this.instance.name, instanceId: this.instanceId }, { instanceName: this.instance.name, instanceId: this.instanceId },
messageRaw.key.remoteJid, messageRaw.key.remoteJid,
messageRaw.pushName,
messageRaw, messageRaw,
); );
} }
@ -2056,6 +2057,7 @@ export class BaileysStartupService extends ChannelStartupService {
await this.openaiService.sendOpenai( await this.openaiService.sendOpenai(
{ instanceName: this.instance.name, instanceId: this.instanceId }, { instanceName: this.instance.name, instanceId: this.instanceId },
messageRaw.key.remoteJid, messageRaw.key.remoteJid,
messageRaw.pushName,
messageRaw, messageRaw,
); );
} }

View File

@ -512,6 +512,7 @@ export class BusinessStartupService extends ChannelStartupService {
await this.openaiService.sendOpenai( await this.openaiService.sendOpenai(
{ instanceName: this.instance.name, instanceId: this.instanceId }, { instanceName: this.instance.name, instanceId: this.instanceId },
messageRaw.key.remoteJid, messageRaw.key.remoteJid,
pushName,
messageRaw, messageRaw,
); );
} }
@ -960,6 +961,7 @@ export class BusinessStartupService extends ChannelStartupService {
await this.openaiService.sendOpenai( await this.openaiService.sendOpenai(
{ instanceName: this.instance.name, instanceId: this.instanceId }, { instanceName: this.instance.name, instanceId: this.instanceId },
messageRaw.key.remoteJid, messageRaw.key.remoteJid,
messageRaw.pushName,
messageRaw, messageRaw,
); );
} }

View File

@ -0,0 +1,45 @@
function normalizeString(str: string): string {
return str
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLowerCase();
}
export function advancedOperatorsSearch(data: string, query: string): boolean {
const filters = query.split(' ').reduce((acc: Record<string, string[]>, filter) => {
const [operator, ...values] = filter.split(':');
const value = values.join(':');
if (!acc[operator]) {
acc[operator] = [];
}
acc[operator].push(value);
return acc;
}, {});
const normalizedItem = normalizeString(data);
return Object.entries(filters).every(([operator, values]) => {
return values.some((val) => {
const subValues = val.split(',');
return subValues.every((subVal) => {
const normalizedSubVal = normalizeString(subVal);
switch (operator.toLowerCase()) {
case 'contains':
return normalizedItem.includes(normalizedSubVal);
case 'notcontains':
return !normalizedItem.includes(normalizedSubVal);
case 'startswith':
return normalizedItem.startsWith(normalizedSubVal);
case 'endswith':
return normalizedItem.endsWith(normalizedSubVal);
case 'exact':
return normalizedItem === normalizedSubVal;
default:
return false;
}
});
});
});
}