Advanced operators trigger fro OpenAI/Dify/Typebot

This commit is contained in:
Judson Cairo 2024-08-17 08:32:05 -03:00
parent a77fa414e5
commit fcd038924d
10 changed files with 205 additions and 12 deletions

View File

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

View File

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

View File

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

View File

@ -5,6 +5,7 @@ import { WAMonitoringService } from '@api/services/monitor.service';
import { Auth, ConfigService, HttpServer, S3 } from '@config/env.config';
import { Logger } from '@config/logger.config';
import { Dify, DifySetting, IntegrationSession, Message } from '@prisma/client';
import { advancedOperatorsSearch } from '@utils/advancedOperatorsSearch';
import { sendTelemetry } from '@utils/sendTelemetry';
import axios from 'axios';
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 {
const dify = await this.prismaRepository.dify.create({
data: {
@ -239,9 +257,25 @@ export class DifyService {
where: {
triggerOperator: data.triggerOperator,
triggerValue: data.triggerValue,
id: {
not: difyId,
id: { 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,
},
});
@ -727,6 +761,19 @@ export class DifyService {
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
const findTriggerEquals = await this.prismaRepository.dify.findFirst({
where: {

View File

@ -29,7 +29,7 @@ export const difySchema: JSONSchema7 = {
botType: { type: 'string', enum: ['chatBot', 'textGenerator', 'agent', 'workflow'] },
apiUrl: { 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'] },
triggerValue: { type: 'string' },
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 { Logger } from '@config/logger.config';
import { IntegrationSession, Message, OpenaiBot, OpenaiCreds, OpenaiSetting } from '@prisma/client';
import { advancedOperatorsSearch } from '@utils/advancedOperatorsSearch';
import { sendTelemetry } from '@utils/sendTelemetry';
import axios from 'axios';
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 {
const openaiBot = await this.prismaRepository.openaiBot.create({
data: {
@ -390,9 +408,25 @@ export class OpenaiService {
where: {
triggerOperator: data.triggerOperator,
triggerValue: data.triggerValue,
id: {
not: openaiBotId,
id: { 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,
},
});
@ -600,13 +634,14 @@ export class OpenaiService {
public async fetchDefaultSettings(instance: InstanceDto) {
try {
const instanceId = await this.prismaRepository.instance
.findFirst({
const instanceId = (
await this.prismaRepository.instance.findFirst({
select: { id: true },
where: {
name: instance.instanceName,
},
})
.then((instance) => instance.id);
)?.id;
const settings = await this.prismaRepository.openaiSetting.findFirst({
where: {
@ -931,6 +966,19 @@ export class OpenaiService {
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
const findTriggerEquals = await this.prismaRepository.openaiBot.findFirst({
where: {

View File

@ -35,7 +35,7 @@ export const openaiSchema: JSONSchema7 = {
assistantMessages: { type: 'array', items: { type: 'string' } },
userMessages: { type: 'array', items: { type: 'string' } },
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'] },
triggerValue: { type: 'string' },
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 { Logger } from '@config/logger.config';
import { Instance, IntegrationSession, Message, Typebot as TypebotModel } from '@prisma/client';
import { advancedOperatorsSearch } from '@utils/advancedOperatorsSearch';
import { sendTelemetry } from '@utils/sendTelemetry';
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 {
const typebot = await this.prismaRepository.typebot.create({
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 {
const typebot = await this.prismaRepository.typebot.update({
where: {
@ -1287,6 +1323,19 @@ export class TypebotService {
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
const findTriggerEquals = await this.prismaRepository.typebot.findFirst({
where: {

View File

@ -28,7 +28,7 @@ export const typebotSchema: JSONSchema7 = {
description: { type: 'string' },
url: { 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'] },
triggerValue: { type: 'string' },
expire: { type: 'integer' },

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;
}
});
});
});
}