mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-14 01:41:24 -06:00
feat: Fixes and implementation of regex and fallback in typebot
This commit is contained in:
parent
a52a687493
commit
480cc67927
@ -10,6 +10,8 @@
|
||||
* Organization configuration and logo in chatwoot bot contact
|
||||
* Added debounce time for typebot messages
|
||||
* Tagging in chatwoot contact by instance
|
||||
* Add support for managing WhatsApp templates via official API
|
||||
* Fixes and implementation of regex and fallback in typebot
|
||||
|
||||
### Fixed
|
||||
|
||||
@ -19,6 +21,8 @@
|
||||
* Correction of audio sending, now we can speed it up and have the audio wireframe
|
||||
* Reply with media message on Chatwoot
|
||||
* improvements in sending status and groups
|
||||
* Correction in response returns from buttons, lists and templates
|
||||
* EvolutionAPI/Baileys implemented
|
||||
|
||||
### Break changes
|
||||
|
||||
@ -35,6 +39,7 @@
|
||||
- Session search by typebot or remoteJid
|
||||
- KeepOpen configuration (keeps the session even when the bot ends, to run once per contact)
|
||||
- StopBotFromMe configuration, allows me to stop the bot if I send a chat message.
|
||||
* Changed the way the goal webhook is configured
|
||||
|
||||
# 1.8.2 (2024-07-03 13:50)
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
-- AlterEnum
|
||||
ALTER TYPE "TriggerOperator" ADD VALUE 'regex';
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "TypebotSetting" ADD COLUMN "typebotIdFallback" VARCHAR(100);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TypebotSetting" ADD CONSTRAINT "TypebotSetting_typebotIdFallback_fkey" FOREIGN KEY ("typebotIdFallback") REFERENCES "Typebot"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
@ -43,6 +43,7 @@ enum TriggerOperator {
|
||||
equals
|
||||
startsWith
|
||||
endsWith
|
||||
regex
|
||||
}
|
||||
|
||||
model Instance {
|
||||
@ -271,6 +272,7 @@ model Typebot {
|
||||
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
|
||||
instanceId String
|
||||
sessions TypebotSession[]
|
||||
TypebotSetting TypebotSetting[]
|
||||
}
|
||||
|
||||
model TypebotSession {
|
||||
@ -300,8 +302,10 @@ model TypebotSetting {
|
||||
stopBotFromMe Boolean? @default(false) @db.Boolean
|
||||
keepOpen Boolean? @default(false) @db.Boolean
|
||||
debounceTime Int? @db.Integer
|
||||
typebotIdFallback String? @db.VarChar(100)
|
||||
createdAt DateTime? @default(now()) @db.Timestamp
|
||||
updatedAt DateTime @updatedAt @db.Timestamp
|
||||
Fallback Typebot? @relation(fields: [typebotIdFallback], references: [id])
|
||||
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
|
||||
instanceId String @unique
|
||||
}
|
||||
|
@ -42,4 +42,5 @@ export class TypebotSettingDto {
|
||||
stopBotFromMe?: boolean;
|
||||
keepOpen?: boolean;
|
||||
debounceTime?: number;
|
||||
typebotIdFallback?: string;
|
||||
}
|
||||
|
@ -45,24 +45,34 @@ export class TypebotService {
|
||||
},
|
||||
});
|
||||
|
||||
if (!defaultSettingCheck) {
|
||||
throw new Error('Default settings not found');
|
||||
}
|
||||
if (!data.expire) data.expire = defaultSettingCheck?.expire || 0;
|
||||
if (!data.keywordFinish) data.keywordFinish = defaultSettingCheck?.keywordFinish || '#SAIR';
|
||||
if (!data.delayMessage) data.delayMessage = defaultSettingCheck?.delayMessage || 1000;
|
||||
if (!data.unknownMessage) data.unknownMessage = defaultSettingCheck?.unknownMessage || 'Desculpe, não entendi';
|
||||
if (!data.listeningFromMe) data.listeningFromMe = defaultSettingCheck?.listeningFromMe || false;
|
||||
if (!data.stopBotFromMe) data.stopBotFromMe = defaultSettingCheck?.stopBotFromMe || false;
|
||||
if (!data.keepOpen) data.keepOpen = defaultSettingCheck?.keepOpen || false;
|
||||
if (!data.debounceTime) data.debounceTime = defaultSettingCheck?.debounceTime || 0;
|
||||
|
||||
if (!data.expire) data.expire = defaultSettingCheck.expire;
|
||||
if (!data.keywordFinish) data.keywordFinish = defaultSettingCheck.keywordFinish;
|
||||
if (!data.delayMessage) data.delayMessage = defaultSettingCheck.delayMessage;
|
||||
if (!data.unknownMessage) data.unknownMessage = defaultSettingCheck.unknownMessage;
|
||||
if (!data.listeningFromMe) data.listeningFromMe = defaultSettingCheck.listeningFromMe;
|
||||
if (!data.stopBotFromMe) data.stopBotFromMe = defaultSettingCheck.stopBotFromMe;
|
||||
if (!data.keepOpen) data.keepOpen = defaultSettingCheck.keepOpen;
|
||||
if (!data.debounceTime) data.debounceTime = defaultSettingCheck.debounceTime;
|
||||
if (!defaultSettingCheck) {
|
||||
await this.setDefaultSettings(instance, {
|
||||
expire: data.expire,
|
||||
keywordFinish: data.keywordFinish,
|
||||
delayMessage: data.delayMessage,
|
||||
unknownMessage: data.unknownMessage,
|
||||
listeningFromMe: data.listeningFromMe,
|
||||
stopBotFromMe: data.stopBotFromMe,
|
||||
keepOpen: data.keepOpen,
|
||||
debounceTime: data.debounceTime,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const checkTriggerAll = await this.prismaRepository.typebot.findFirst({
|
||||
where: {
|
||||
enabled: true,
|
||||
triggerType: 'all',
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
@ -74,6 +84,7 @@ export class TypebotService {
|
||||
where: {
|
||||
url: data.url,
|
||||
typebot: data.typebot,
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
@ -90,6 +101,7 @@ export class TypebotService {
|
||||
where: {
|
||||
triggerOperator: data.triggerOperator,
|
||||
triggerValue: data.triggerValue,
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
@ -186,6 +198,7 @@ export class TypebotService {
|
||||
id: {
|
||||
not: typebotId,
|
||||
},
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
@ -203,6 +216,7 @@ export class TypebotService {
|
||||
id: {
|
||||
not: typebotId,
|
||||
},
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
@ -222,6 +236,7 @@ export class TypebotService {
|
||||
id: {
|
||||
not: typebotId,
|
||||
},
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
@ -358,6 +373,7 @@ export class TypebotService {
|
||||
stopBotFromMe: data.stopBotFromMe,
|
||||
keepOpen: data.keepOpen,
|
||||
debounceTime: data.debounceTime,
|
||||
typebotIdFallback: data.typebotIdFallback,
|
||||
},
|
||||
});
|
||||
|
||||
@ -370,6 +386,7 @@ export class TypebotService {
|
||||
stopBotFromMe: updateSettings.stopBotFromMe,
|
||||
keepOpen: updateSettings.keepOpen,
|
||||
debounceTime: updateSettings.debounceTime,
|
||||
typebotIdFallback: updateSettings.typebotIdFallback,
|
||||
};
|
||||
}
|
||||
|
||||
@ -383,6 +400,7 @@ export class TypebotService {
|
||||
stopBotFromMe: data.stopBotFromMe,
|
||||
keepOpen: data.keepOpen,
|
||||
debounceTime: data.debounceTime,
|
||||
typebotIdFallback: data.typebotIdFallback,
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
@ -396,6 +414,7 @@ export class TypebotService {
|
||||
stopBotFromMe: newSetttings.stopBotFromMe,
|
||||
keepOpen: newSetttings.keepOpen,
|
||||
debounceTime: newSetttings.debounceTime,
|
||||
typebotIdFallback: newSetttings.typebotIdFallback,
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
@ -417,6 +436,9 @@ export class TypebotService {
|
||||
where: {
|
||||
instanceId: instanceId,
|
||||
},
|
||||
include: {
|
||||
Fallback: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!settings) {
|
||||
@ -431,6 +453,8 @@ export class TypebotService {
|
||||
listeningFromMe: settings.listeningFromMe,
|
||||
stopBotFromMe: settings.stopBotFromMe,
|
||||
keepOpen: settings.keepOpen,
|
||||
typebotIdFallback: settings.typebotIdFallback,
|
||||
fallback: settings.Fallback,
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error(error);
|
||||
@ -573,17 +597,25 @@ export class TypebotService {
|
||||
},
|
||||
});
|
||||
|
||||
if (!defaultSettingCheck) {
|
||||
throw new Error('Default settings not found');
|
||||
}
|
||||
if (!expire) expire = defaultSettingCheck?.expire || 0;
|
||||
if (!keywordFinish) keywordFinish = defaultSettingCheck?.keywordFinish || '#SAIR';
|
||||
if (!delayMessage) delayMessage = defaultSettingCheck?.delayMessage || 1000;
|
||||
if (!unknownMessage) unknownMessage = defaultSettingCheck?.unknownMessage || 'Desculpe, não entendi';
|
||||
if (!listeningFromMe) listeningFromMe = defaultSettingCheck?.listeningFromMe || false;
|
||||
if (!stopBotFromMe) stopBotFromMe = defaultSettingCheck?.stopBotFromMe || false;
|
||||
if (!keepOpen) keepOpen = defaultSettingCheck?.keepOpen || false;
|
||||
|
||||
if (!expire) expire = defaultSettingCheck.expire;
|
||||
if (!keywordFinish) keywordFinish = defaultSettingCheck.keywordFinish;
|
||||
if (!delayMessage) delayMessage = defaultSettingCheck.delayMessage;
|
||||
if (!unknownMessage) unknownMessage = defaultSettingCheck.unknownMessage;
|
||||
if (!listeningFromMe) listeningFromMe = defaultSettingCheck.listeningFromMe;
|
||||
if (!stopBotFromMe) stopBotFromMe = defaultSettingCheck.stopBotFromMe;
|
||||
if (!keepOpen) keepOpen = defaultSettingCheck.keepOpen;
|
||||
if (!defaultSettingCheck) {
|
||||
await this.setDefaultSettings(instance, {
|
||||
expire: expire,
|
||||
keywordFinish: keywordFinish,
|
||||
delayMessage: delayMessage,
|
||||
unknownMessage: unknownMessage,
|
||||
listeningFromMe: listeningFromMe,
|
||||
stopBotFromMe: stopBotFromMe,
|
||||
keepOpen: keepOpen,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const prefilledVariables = {
|
||||
@ -1062,73 +1094,148 @@ export class TypebotService {
|
||||
}
|
||||
}
|
||||
|
||||
public async findTypebotByTrigger(content: string) {
|
||||
let typebot = null;
|
||||
public async findTypebotByTrigger(content: string, instanceId: string) {
|
||||
console.log('Check for triggerType all');
|
||||
|
||||
// Check for triggerType 'all'
|
||||
const findTriggerAll = await this.prismaRepository.typebot.findFirst({
|
||||
where: {
|
||||
enabled: true,
|
||||
triggerType: 'all',
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (findTriggerAll) {
|
||||
typebot = findTriggerAll;
|
||||
} else {
|
||||
console.log('findTriggerAll', findTriggerAll);
|
||||
|
||||
if (findTriggerAll) return findTriggerAll;
|
||||
|
||||
console.log('Check for exact match');
|
||||
|
||||
// Check for exact match
|
||||
const findTriggerEquals = await this.prismaRepository.typebot.findFirst({
|
||||
where: {
|
||||
enabled: true,
|
||||
triggerType: 'keyword',
|
||||
triggerOperator: 'equals',
|
||||
triggerValue: content,
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (findTriggerEquals) {
|
||||
typebot = findTriggerEquals;
|
||||
} else {
|
||||
console.log('findTriggerEquals', findTriggerEquals);
|
||||
|
||||
if (findTriggerEquals) return findTriggerEquals;
|
||||
|
||||
console.log('Check for regex match');
|
||||
|
||||
// Check for regex match
|
||||
const findRegex = await this.prismaRepository.typebot.findMany({
|
||||
where: {
|
||||
enabled: true,
|
||||
triggerType: 'keyword',
|
||||
triggerOperator: 'regex',
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
let findTriggerRegex = null;
|
||||
|
||||
for (const regex of findRegex) {
|
||||
const regexValue = new RegExp(regex.triggerValue);
|
||||
|
||||
if (regexValue.test(content)) {
|
||||
findTriggerRegex = regex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('findTriggerRegex', findTriggerRegex);
|
||||
|
||||
if (findTriggerRegex) return findTriggerRegex;
|
||||
|
||||
console.log('Check for startsWith match');
|
||||
|
||||
// Check for startsWith match
|
||||
const findTriggerStartsWith = await this.prismaRepository.typebot.findFirst({
|
||||
where: {
|
||||
enabled: true,
|
||||
triggerType: 'keyword',
|
||||
triggerOperator: 'startsWith',
|
||||
triggerValue: { startsWith: content },
|
||||
triggerValue: {
|
||||
startsWith: content,
|
||||
},
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (findTriggerStartsWith) {
|
||||
typebot = findTriggerStartsWith;
|
||||
} else {
|
||||
console.log('findTriggerStartsWith', findTriggerStartsWith);
|
||||
|
||||
if (findTriggerStartsWith) return findTriggerStartsWith;
|
||||
|
||||
console.log('Check for endsWith match');
|
||||
|
||||
// Check for endsWith match
|
||||
const findTriggerEndsWith = await this.prismaRepository.typebot.findFirst({
|
||||
where: {
|
||||
enabled: true,
|
||||
triggerType: 'keyword',
|
||||
triggerOperator: 'endsWith',
|
||||
triggerValue: { endsWith: content },
|
||||
triggerValue: {
|
||||
endsWith: content,
|
||||
},
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (findTriggerEndsWith) {
|
||||
typebot = findTriggerEndsWith;
|
||||
} else {
|
||||
console.log('findTriggerEndsWith', findTriggerEndsWith);
|
||||
|
||||
if (findTriggerEndsWith) return findTriggerEndsWith;
|
||||
|
||||
console.log('Check for contains match');
|
||||
|
||||
// Check for contains match
|
||||
const findTriggerContains = await this.prismaRepository.typebot.findFirst({
|
||||
where: {
|
||||
enabled: true,
|
||||
triggerType: 'keyword',
|
||||
triggerOperator: 'contains',
|
||||
triggerValue: { contains: content },
|
||||
triggerValue: {
|
||||
contains: content,
|
||||
},
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (findTriggerContains) {
|
||||
typebot = findTriggerContains;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('findTriggerContains', findTriggerContains);
|
||||
|
||||
if (findTriggerContains) return findTriggerContains;
|
||||
|
||||
console.log('Check for fallback');
|
||||
|
||||
const fallback = await this.prismaRepository.typebotSetting.findFirst({
|
||||
where: {
|
||||
instanceId: instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
console.log('fallback', fallback);
|
||||
|
||||
if (fallback?.typebotIdFallback) {
|
||||
console.log('Check for fallback typebot');
|
||||
|
||||
const findFallback = await this.prismaRepository.typebot.findFirst({
|
||||
where: {
|
||||
id: fallback.typebotIdFallback,
|
||||
},
|
||||
});
|
||||
|
||||
console.log('findFallback', findFallback);
|
||||
|
||||
if (findFallback) return findFallback;
|
||||
}
|
||||
|
||||
return typebot;
|
||||
return null;
|
||||
}
|
||||
|
||||
private processDebounce(content: string, remoteJid: string, debounceTime: number, callback: any) {
|
||||
@ -1160,12 +1267,20 @@ export class TypebotService {
|
||||
},
|
||||
});
|
||||
|
||||
const settings = await this.prismaRepository.typebotSetting.findFirst({
|
||||
where: {
|
||||
instanceId: instance.instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
const content = this.getConversationMessage(msg);
|
||||
|
||||
let findTypebot = null;
|
||||
|
||||
console.log('content', content);
|
||||
|
||||
if (!session) {
|
||||
findTypebot = await this.findTypebotByTrigger(content);
|
||||
findTypebot = await this.findTypebotByTrigger(content, instance.instanceId);
|
||||
|
||||
if (!findTypebot) {
|
||||
return;
|
||||
@ -1198,12 +1313,6 @@ export class TypebotService {
|
||||
!stopBotFromMe ||
|
||||
!keepOpen
|
||||
) {
|
||||
const settings = await this.prismaRepository.typebotSetting.findFirst({
|
||||
where: {
|
||||
instanceId: instance.instanceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!expire) expire = settings.expire;
|
||||
|
||||
if (!keywordFinish) keywordFinish = settings.keywordFinish;
|
||||
@ -1242,6 +1351,7 @@ export class TypebotService {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(debounceTime);
|
||||
if (debounceTime && debounceTime > 0) {
|
||||
this.processDebounce(content, remoteJid, debounceTime, async (debouncedContent) => {
|
||||
await this.processTypebot(
|
||||
@ -1469,7 +1579,7 @@ export class TypebotService {
|
||||
typebotId: findTypebot.id,
|
||||
});
|
||||
|
||||
if (data.session) {
|
||||
if (data?.session) {
|
||||
session = data.session;
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ export const typebotSchema: JSONSchema7 = {
|
||||
url: { type: 'string' },
|
||||
typebot: { type: 'string' },
|
||||
triggerType: { type: 'string', enum: ['all', 'keyword'] },
|
||||
triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith'] },
|
||||
triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith', 'regex'] },
|
||||
triggerValue: { type: 'string' },
|
||||
expire: { type: 'integer' },
|
||||
keywordFinish: { type: 'string' },
|
||||
@ -76,6 +76,7 @@ export const typebotSettingSchema: JSONSchema7 = {
|
||||
stopBotFromMe: { type: 'boolean' },
|
||||
keepOpen: { type: 'boolean' },
|
||||
debounceTime: { type: 'integer' },
|
||||
typebotIdFallback: { type: 'string' },
|
||||
},
|
||||
required: ['expire', 'keywordFinish', 'delayMessage', 'unknownMessage', 'listeningFromMe', 'stopBotFromMe'],
|
||||
...isNotEmpty('expire', 'keywordFinish', 'delayMessage', 'unknownMessage', 'listeningFromMe', 'stopBotFromMe'),
|
||||
|
Loading…
Reference in New Issue
Block a user