From 2c780089aa06ab47d86ffab97d7f8505641ca29d Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Wed, 25 Jun 2025 19:30:15 -0300 Subject: [PATCH 01/19] remove open ai key validation --- .../openai/controllers/openai.controller.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/api/integrations/chatbot/openai/controllers/openai.controller.ts b/src/api/integrations/chatbot/openai/controllers/openai.controller.ts index 1d9910d1f..5822139cb 100644 --- a/src/api/integrations/chatbot/openai/controllers/openai.controller.ts +++ b/src/api/integrations/chatbot/openai/controllers/openai.controller.ts @@ -236,15 +236,15 @@ export class OpenaiController extends BaseChatbotController Date: Mon, 23 Jun 2025 15:35:56 -0300 Subject: [PATCH 02/19] Merge pull request #1633 from VCalazans/FIX/ISSUE-28 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🐛 fix: Phone number as message ID for Evo AI #ISSUE 28 --- src/api/integrations/chatbot/evoai/services/evoai.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/integrations/chatbot/evoai/services/evoai.service.ts b/src/api/integrations/chatbot/evoai/services/evoai.service.ts index 616676743..173ebe34d 100644 --- a/src/api/integrations/chatbot/evoai/services/evoai.service.ts +++ b/src/api/integrations/chatbot/evoai/services/evoai.service.ts @@ -70,7 +70,7 @@ export class EvoaiService extends BaseChatbotService { } const callId = `req-${uuidv4().substring(0, 8)}`; - const messageId = msg?.key?.id || uuidv4(); + const messageId = remoteJid.split('@')[0] || uuidv4(); // Use phone number as messageId // Prepare message parts const parts = [ From edb1dcf41fc74a361f8d68801b377fdd37bd3bbc Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Wed, 9 Jul 2025 18:54:01 -0300 Subject: [PATCH 03/19] feat: speech to text default true --- .../migration.sql | 5 +++++ prisma/mysql-schema.prisma | 2 +- .../migration.sql | 5 +++++ prisma/postgresql-schema.prisma | 2 +- .../chatbot/openai/controllers/openai.controller.ts | 2 +- 5 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 prisma/mysql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql create mode 100644 prisma/postgresql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql diff --git a/prisma/mysql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql b/prisma/mysql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql new file mode 100644 index 000000000..2dbc595ff --- /dev/null +++ b/prisma/mysql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE `OpenaiSetting` MODIFY COLUMN `speechToText` BOOLEAN NULL DEFAULT true; + +-- Update existing records to use the new default +UPDATE `OpenaiSetting` SET `speechToText` = true WHERE `speechToText` IS NULL OR `speechToText` = false; diff --git a/prisma/mysql-schema.prisma b/prisma/mysql-schema.prisma index 782e4d855..ec4514bbd 100644 --- a/prisma/mysql-schema.prisma +++ b/prisma/mysql-schema.prisma @@ -469,7 +469,7 @@ model OpenaiSetting { ignoreJids Json? splitMessages Boolean? @default(false) timePerChar Int? @default(50) @db.Int - speechToText Boolean? @default(false) + speechToText Boolean? @default(true) createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp updatedAt DateTime @updatedAt @db.Timestamp OpenaiCreds OpenaiCreds? @relation(fields: [openaiCredsId], references: [id]) diff --git a/prisma/postgresql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql b/prisma/postgresql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql new file mode 100644 index 000000000..7fb18428b --- /dev/null +++ b/prisma/postgresql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "OpenaiSetting" ALTER COLUMN "speechToText" SET DEFAULT true; + +-- Update existing records to use the new default +UPDATE "OpenaiSetting" SET "speechToText" = true WHERE "speechToText" IS NULL OR "speechToText" = false; diff --git a/prisma/postgresql-schema.prisma b/prisma/postgresql-schema.prisma index 7d2410e9c..ada14059b 100644 --- a/prisma/postgresql-schema.prisma +++ b/prisma/postgresql-schema.prisma @@ -476,7 +476,7 @@ model OpenaiSetting { ignoreJids Json? splitMessages Boolean? @default(false) @db.Boolean timePerChar Int? @default(50) @db.Integer - speechToText Boolean? @default(false) @db.Boolean + speechToText Boolean? @default(true) @db.Boolean createdAt DateTime? @default(now()) @db.Timestamp updatedAt DateTime @updatedAt @db.Timestamp OpenaiCreds OpenaiCreds? @relation(fields: [openaiCredsId], references: [id]) diff --git a/src/api/integrations/chatbot/openai/controllers/openai.controller.ts b/src/api/integrations/chatbot/openai/controllers/openai.controller.ts index 5822139cb..12f560cf9 100644 --- a/src/api/integrations/chatbot/openai/controllers/openai.controller.ts +++ b/src/api/integrations/chatbot/openai/controllers/openai.controller.ts @@ -184,7 +184,7 @@ export class OpenaiController extends BaseChatbotController Date: Wed, 9 Jul 2025 21:14:13 -0300 Subject: [PATCH 04/19] update lib --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a6eb24701..d2621aa03 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "form-data": "^4.0.1", "https-proxy-agent": "^7.0.6", "i18next": "^23.7.19", - "jimp": "^0.16.13", + "jimp": "^1.6.0", "json-schema": "^0.4.0", "jsonschema": "^1.4.1", "jsonwebtoken": "^9.0.2", From 7960f0de7a50b42ba264a3a1076d240cd49cae9e Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Wed, 9 Jul 2025 21:15:55 -0300 Subject: [PATCH 05/19] update lib sharp --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d2621aa03..d3d957cfe 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "qrcode": "^1.5.4", "qrcode-terminal": "^0.12.0", "redis": "^4.7.0", - "sharp": "^0.32.6", + "sharp": "^0.34.2", "socket.io": "^4.8.1", "socket.io-client": "^4.8.1", "tsup": "^8.3.5" From f58e792506385a6ab3c1734cf85b7c4ccd081536 Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Wed, 9 Jul 2025 22:07:48 -0300 Subject: [PATCH 06/19] =?UTF-8?q?Corre=C3=A7=C3=A3o=20com=20chatwoot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chatbot/chatwoot/services/chatwoot.service.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts index 190184735..18b78965e 100644 --- a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts +++ b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts @@ -2100,10 +2100,10 @@ export class ChatwootService { const nameFile = `${random}.${mimeTypes.extension(mimeType)}`; const fileData = Buffer.from(imgBuffer.data, 'binary'); - const img = await Jimp.read(fileData); - await img.cover(320, 180); + const img = await Jimp.fromBuffer(fileData); + img.cover(320, 180); - const processedBuffer = await img.getBufferAsync(Jimp.MIME_PNG); + const processedBuffer = await img.getBuffer('image/png'); const fileStream = new Readable(); fileStream._read = () => {}; // _read is required but you can noop it From abe25d2c77c50188f5148a167e624423a054a0d1 Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Wed, 9 Jul 2025 22:16:19 -0300 Subject: [PATCH 07/19] fix jimp 2 --- .../chatbot/chatwoot/services/chatwoot.service.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts index 18b78965e..aaa10fbbc 100644 --- a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts +++ b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts @@ -2100,10 +2100,9 @@ export class ChatwootService { const nameFile = `${random}.${mimeTypes.extension(mimeType)}`; const fileData = Buffer.from(imgBuffer.data, 'binary'); - const img = await Jimp.fromBuffer(fileData); + const img = await Jimp.read(fileData); img.cover(320, 180); - - const processedBuffer = await img.getBuffer('image/png'); + const processedBuffer = await img.getBufferAsync(Jimp.MIME_PNG || 'image/png'); const fileStream = new Readable(); fileStream._read = () => {}; // _read is required but you can noop it From fe1a93da10e86881089ca5752774741bb919f410 Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Wed, 9 Jul 2025 22:38:22 -0300 Subject: [PATCH 08/19] Revert "fix jimp 2" This reverts commit abe25d2c77c50188f5148a167e624423a054a0d1. --- .../chatbot/chatwoot/services/chatwoot.service.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts index aaa10fbbc..18b78965e 100644 --- a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts +++ b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts @@ -2100,9 +2100,10 @@ export class ChatwootService { const nameFile = `${random}.${mimeTypes.extension(mimeType)}`; const fileData = Buffer.from(imgBuffer.data, 'binary'); - const img = await Jimp.read(fileData); + const img = await Jimp.fromBuffer(fileData); img.cover(320, 180); - const processedBuffer = await img.getBufferAsync(Jimp.MIME_PNG || 'image/png'); + + const processedBuffer = await img.getBuffer('image/png'); const fileStream = new Readable(); fileStream._read = () => {}; // _read is required but you can noop it From 811e369c996209f5de6cd63af0a2faced45bf33b Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Wed, 9 Jul 2025 22:38:29 -0300 Subject: [PATCH 09/19] =?UTF-8?q?Revert=20"Corre=C3=A7=C3=A3o=20com=20chat?= =?UTF-8?q?woot"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit f58e792506385a6ab3c1734cf85b7c4ccd081536. --- .../chatbot/chatwoot/services/chatwoot.service.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts index 18b78965e..190184735 100644 --- a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts +++ b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts @@ -2100,10 +2100,10 @@ export class ChatwootService { const nameFile = `${random}.${mimeTypes.extension(mimeType)}`; const fileData = Buffer.from(imgBuffer.data, 'binary'); - const img = await Jimp.fromBuffer(fileData); - img.cover(320, 180); + const img = await Jimp.read(fileData); + await img.cover(320, 180); - const processedBuffer = await img.getBuffer('image/png'); + const processedBuffer = await img.getBufferAsync(Jimp.MIME_PNG); const fileStream = new Readable(); fileStream._read = () => {}; // _read is required but you can noop it From 996972743e207809b5046b2fa5af0e587e6d3477 Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Wed, 9 Jul 2025 22:38:34 -0300 Subject: [PATCH 10/19] Revert "update lib sharp" This reverts commit 7960f0de7a50b42ba264a3a1076d240cd49cae9e. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d3d957cfe..d2621aa03 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "qrcode": "^1.5.4", "qrcode-terminal": "^0.12.0", "redis": "^4.7.0", - "sharp": "^0.34.2", + "sharp": "^0.32.6", "socket.io": "^4.8.1", "socket.io-client": "^4.8.1", "tsup": "^8.3.5" From 49b174d3decc98b89531f3104754efa13349d015 Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Wed, 9 Jul 2025 22:38:37 -0300 Subject: [PATCH 11/19] Revert "update lib" This reverts commit 20b5066b56413c63485f989e08165fd7a80dda37. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d2621aa03..a6eb24701 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "form-data": "^4.0.1", "https-proxy-agent": "^7.0.6", "i18next": "^23.7.19", - "jimp": "^1.6.0", + "jimp": "^0.16.13", "json-schema": "^0.4.0", "jsonschema": "^1.4.1", "jsonwebtoken": "^9.0.2", From fe93353da1330451a8153bca967c5d19adeb82f4 Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Wed, 9 Jul 2025 22:38:41 -0300 Subject: [PATCH 12/19] Revert "feat: speech to text default true" This reverts commit edb1dcf41fc74a361f8d68801b377fdd37bd3bbc. --- .../migration.sql | 5 ----- prisma/mysql-schema.prisma | 2 +- .../migration.sql | 5 ----- prisma/postgresql-schema.prisma | 2 +- .../chatbot/openai/controllers/openai.controller.ts | 2 +- 5 files changed, 3 insertions(+), 13 deletions(-) delete mode 100644 prisma/mysql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql delete mode 100644 prisma/postgresql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql diff --git a/prisma/mysql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql b/prisma/mysql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql deleted file mode 100644 index 2dbc595ff..000000000 --- a/prisma/mysql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql +++ /dev/null @@ -1,5 +0,0 @@ --- AlterTable -ALTER TABLE `OpenaiSetting` MODIFY COLUMN `speechToText` BOOLEAN NULL DEFAULT true; - --- Update existing records to use the new default -UPDATE `OpenaiSetting` SET `speechToText` = true WHERE `speechToText` IS NULL OR `speechToText` = false; diff --git a/prisma/mysql-schema.prisma b/prisma/mysql-schema.prisma index ec4514bbd..782e4d855 100644 --- a/prisma/mysql-schema.prisma +++ b/prisma/mysql-schema.prisma @@ -469,7 +469,7 @@ model OpenaiSetting { ignoreJids Json? splitMessages Boolean? @default(false) timePerChar Int? @default(50) @db.Int - speechToText Boolean? @default(true) + speechToText Boolean? @default(false) createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp updatedAt DateTime @updatedAt @db.Timestamp OpenaiCreds OpenaiCreds? @relation(fields: [openaiCredsId], references: [id]) diff --git a/prisma/postgresql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql b/prisma/postgresql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql deleted file mode 100644 index 7fb18428b..000000000 --- a/prisma/postgresql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql +++ /dev/null @@ -1,5 +0,0 @@ --- AlterTable -ALTER TABLE "OpenaiSetting" ALTER COLUMN "speechToText" SET DEFAULT true; - --- Update existing records to use the new default -UPDATE "OpenaiSetting" SET "speechToText" = true WHERE "speechToText" IS NULL OR "speechToText" = false; diff --git a/prisma/postgresql-schema.prisma b/prisma/postgresql-schema.prisma index ada14059b..7d2410e9c 100644 --- a/prisma/postgresql-schema.prisma +++ b/prisma/postgresql-schema.prisma @@ -476,7 +476,7 @@ model OpenaiSetting { ignoreJids Json? splitMessages Boolean? @default(false) @db.Boolean timePerChar Int? @default(50) @db.Integer - speechToText Boolean? @default(true) @db.Boolean + speechToText Boolean? @default(false) @db.Boolean createdAt DateTime? @default(now()) @db.Timestamp updatedAt DateTime @updatedAt @db.Timestamp OpenaiCreds OpenaiCreds? @relation(fields: [openaiCredsId], references: [id]) diff --git a/src/api/integrations/chatbot/openai/controllers/openai.controller.ts b/src/api/integrations/chatbot/openai/controllers/openai.controller.ts index 12f560cf9..5822139cb 100644 --- a/src/api/integrations/chatbot/openai/controllers/openai.controller.ts +++ b/src/api/integrations/chatbot/openai/controllers/openai.controller.ts @@ -184,7 +184,7 @@ export class OpenaiController extends BaseChatbotController Date: Wed, 9 Jul 2025 22:52:33 -0300 Subject: [PATCH 13/19] force npm install --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index fc535aa27..5f7fd9338 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ WORKDIR /evolution COPY ./package.json ./tsconfig.json ./ -RUN npm install +RUN npm install --force --legacy-peer-deps COPY ./src ./src COPY ./public ./public From 205ea817950d0d605784115b4d95b1b6bc17e65c Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Wed, 9 Jul 2025 22:53:18 -0300 Subject: [PATCH 14/19] Reapply "feat: speech to text default true" This reverts commit fe93353da1330451a8153bca967c5d19adeb82f4. --- .../migration.sql | 5 +++++ prisma/mysql-schema.prisma | 2 +- .../migration.sql | 5 +++++ prisma/postgresql-schema.prisma | 2 +- .../chatbot/openai/controllers/openai.controller.ts | 2 +- 5 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 prisma/mysql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql create mode 100644 prisma/postgresql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql diff --git a/prisma/mysql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql b/prisma/mysql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql new file mode 100644 index 000000000..2dbc595ff --- /dev/null +++ b/prisma/mysql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE `OpenaiSetting` MODIFY COLUMN `speechToText` BOOLEAN NULL DEFAULT true; + +-- Update existing records to use the new default +UPDATE `OpenaiSetting` SET `speechToText` = true WHERE `speechToText` IS NULL OR `speechToText` = false; diff --git a/prisma/mysql-schema.prisma b/prisma/mysql-schema.prisma index 782e4d855..ec4514bbd 100644 --- a/prisma/mysql-schema.prisma +++ b/prisma/mysql-schema.prisma @@ -469,7 +469,7 @@ model OpenaiSetting { ignoreJids Json? splitMessages Boolean? @default(false) timePerChar Int? @default(50) @db.Int - speechToText Boolean? @default(false) + speechToText Boolean? @default(true) createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp updatedAt DateTime @updatedAt @db.Timestamp OpenaiCreds OpenaiCreds? @relation(fields: [openaiCredsId], references: [id]) diff --git a/prisma/postgresql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql b/prisma/postgresql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql new file mode 100644 index 000000000..7fb18428b --- /dev/null +++ b/prisma/postgresql-migrations/20250709000000_change_speech_to_text_default_to_true/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "OpenaiSetting" ALTER COLUMN "speechToText" SET DEFAULT true; + +-- Update existing records to use the new default +UPDATE "OpenaiSetting" SET "speechToText" = true WHERE "speechToText" IS NULL OR "speechToText" = false; diff --git a/prisma/postgresql-schema.prisma b/prisma/postgresql-schema.prisma index 7d2410e9c..ada14059b 100644 --- a/prisma/postgresql-schema.prisma +++ b/prisma/postgresql-schema.prisma @@ -476,7 +476,7 @@ model OpenaiSetting { ignoreJids Json? splitMessages Boolean? @default(false) @db.Boolean timePerChar Int? @default(50) @db.Integer - speechToText Boolean? @default(false) @db.Boolean + speechToText Boolean? @default(true) @db.Boolean createdAt DateTime? @default(now()) @db.Timestamp updatedAt DateTime @updatedAt @db.Timestamp OpenaiCreds OpenaiCreds? @relation(fields: [openaiCredsId], references: [id]) diff --git a/src/api/integrations/chatbot/openai/controllers/openai.controller.ts b/src/api/integrations/chatbot/openai/controllers/openai.controller.ts index 5822139cb..12f560cf9 100644 --- a/src/api/integrations/chatbot/openai/controllers/openai.controller.ts +++ b/src/api/integrations/chatbot/openai/controllers/openai.controller.ts @@ -184,7 +184,7 @@ export class OpenaiController extends BaseChatbotController Date: Wed, 9 Jul 2025 23:56:27 -0300 Subject: [PATCH 15/19] Credenciais default openai --- .../openai/controllers/openai.controller.ts | 63 ++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/api/integrations/chatbot/openai/controllers/openai.controller.ts b/src/api/integrations/chatbot/openai/controllers/openai.controller.ts index 12f560cf9..563567b0c 100644 --- a/src/api/integrations/chatbot/openai/controllers/openai.controller.ts +++ b/src/api/integrations/chatbot/openai/controllers/openai.controller.ts @@ -267,6 +267,9 @@ export class OpenaiController extends BaseChatbotController Date: Sat, 26 Jul 2025 17:14:40 -0300 Subject: [PATCH 16/19] =?UTF-8?q?Corre=C3=A7=C3=A3o=20lId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../whatsapp/whatsapp.baileys.service.ts | 55 ++++++++++++++++--- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index de31b503d..be075a383 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -151,6 +151,28 @@ import { useVoiceCallsBaileys } from './voiceCalls/useVoiceCallsBaileys'; const groupMetadataCache = new CacheService(new CacheEngine(configService, 'groups').getEngine()); +// Function to normalize JID and handle LID/JID conversion +function normalizeJid(jid: string): string { + if (!jid) return jid; + + // Remove LID suffix and convert to standard JID format + if (jid.includes(':lid')) { + return jid.split(':')[0] + '@s.whatsapp.net'; + } + + // Remove participant suffix from group messages + if (jid.includes(':') && jid.includes('@g.us')) { + return jid.split(':')[0] + '@g.us'; + } + + // Remove any other participant suffixes + if (jid.includes(':') && !jid.includes('@g.us')) { + return jid.split(':')[0] + '@s.whatsapp.net'; + } + + return jid; +} + // Adicione a função getVideoDuration no início do arquivo async function getVideoDuration(input: Buffer | string | Readable): Promise { const MediaInfoFactory = (await import('mediainfo.js')).default; @@ -1091,7 +1113,8 @@ export class BaileysStartupService extends ChannelStartupService { } } - const messageKey = `${this.instance.id}_${received.key.id}`; + const normalizedJid = normalizeJid(received.key.remoteJid); + const messageKey = `${this.instance.id}_${normalizedJid}_${received.key.id}`; const cached = await this.baileysCache.get(messageKey); if (cached && !editedMessage) { @@ -1118,8 +1141,9 @@ export class BaileysStartupService extends ChannelStartupService { continue; } + const normalizedRemoteJid = normalizeJid(received.key.remoteJid); const existingChat = await this.prismaRepository.chat.findFirst({ - where: { instanceId: this.instanceId, remoteJid: received.key.remoteJid }, + where: { instanceId: this.instanceId, remoteJid: normalizedRemoteJid }, select: { id: true, name: true }, }); @@ -1198,7 +1222,8 @@ export class BaileysStartupService extends ChannelStartupService { const { remoteJid } = received.key; const timestamp = msg.messageTimestamp; const fromMe = received.key.fromMe.toString(); - const messageKey = `${remoteJid}_${timestamp}_${fromMe}`; + const normalizedRemoteJid = normalizeJid(remoteJid); + const messageKey = `${normalizedRemoteJid}_${timestamp}_${fromMe}`; const cachedTimestamp = await this.baileysCache.get(messageKey); @@ -1303,13 +1328,13 @@ export class BaileysStartupService extends ChannelStartupService { }); const contact = await this.prismaRepository.contact.findFirst({ - where: { remoteJid: received.key.remoteJid, instanceId: this.instanceId }, + where: { remoteJid: normalizedRemoteJid, instanceId: this.instanceId }, }); const contactRaw: { remoteJid: string; pushName: string; profilePicUrl?: string; instanceId: string } = { - remoteJid: received.key.remoteJid, + remoteJid: normalizedRemoteJid, pushName: received.key.fromMe ? '' : received.key.fromMe == null ? '' : received.pushName, - profilePicUrl: (await this.profilePicture(received.key.remoteJid)).profilePictureUrl, + profilePicUrl: (await this.profilePicture(normalizedRemoteJid)).profilePictureUrl, instanceId: this.instanceId, }; @@ -1366,7 +1391,11 @@ export class BaileysStartupService extends ChannelStartupService { continue; } - const updateKey = `${this.instance.id}_${key.id}_${update.status}`; + // Normalize JID and ensure we have valid key components + const normalizedJid = normalizeJid(key.remoteJid); + const messageId = key.id || 'unknown'; + const status = update.status || 'unknown'; + const updateKey = `${this.instance.id}_${normalizedJid}_${messageId}_${status}`; const cached = await this.baileysCache.get(updateKey); @@ -1442,7 +1471,8 @@ export class BaileysStartupService extends ChannelStartupService { const { remoteJid } = key; const timestamp = findMessage.messageTimestamp; const fromMe = key.fromMe.toString(); - const messageKey = `${remoteJid}_${timestamp}_${fromMe}`; + const normalizedRemoteJid = normalizeJid(remoteJid); + const messageKey = `${normalizedRemoteJid}_${timestamp}_${fromMe}`; const cachedTimestamp = await this.baileysCache.get(messageKey); @@ -4130,8 +4160,15 @@ export class BaileysStartupService extends ChannelStartupService { const contentType = getContentType(message.message); const contentMsg = message?.message[contentType] as any; + // Normalize JID to handle LID/JID conversion + const normalizedKey = { + ...message.key, + remoteJid: normalizeJid(message.key.remoteJid), + participant: message.key.participant ? normalizeJid(message.key.participant) : undefined, + }; + const messageRaw = { - key: message.key, + key: normalizedKey, pushName: message.pushName || (message.key.fromMe From 3fa9d103dfd2357899d7ce5b7be14007db75fd38 Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Sat, 26 Jul 2025 17:36:06 -0300 Subject: [PATCH 17/19] =?UTF-8?q?Novas=20corre=C3=A7=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../whatsapp/whatsapp.baileys.service.ts | 59 +++++++++++++++++-- src/utils/onWhatsappCache.ts | 14 +++-- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index be075a383..ef5ab8ca9 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -138,6 +138,7 @@ import Long from 'long'; import mimeTypes from 'mime-types'; import NodeCache from 'node-cache'; import cron from 'node-cron'; +import dayjs from 'dayjs'; import { release } from 'os'; import { join } from 'path'; import P from 'pino'; @@ -173,6 +174,30 @@ function normalizeJid(jid: string): string { return jid; } +// Function to clear corrupted session data +async function clearCorruptedSessionData(instanceId: string, baileysCache: CacheService) { + try { + // Clear all baileys cache for this instance + await baileysCache.deleteAll(instanceId); + + // Clear session-related cache patterns + const patterns = [ + `${instanceId}_*`, + `*${instanceId}*`, + `*session*${instanceId}*`, + `*prekey*${instanceId}*` + ]; + + for (const pattern of patterns) { + await baileysCache.deleteAll(pattern); + } + + console.log(`Cleared corrupted session data for instance: ${instanceId}`); + } catch (error) { + console.error('Error clearing session data:', error); + } +} + // Adicione a função getVideoDuration no início do arquivo async function getVideoDuration(input: Buffer | string | Readable): Promise { const MediaInfoFactory = (await import('mediainfo.js')).default; @@ -675,6 +700,9 @@ export class BaileysStartupService extends ChannelStartupService { this.endSession = false; + // Clear any corrupted session data before connecting + await clearCorruptedSessionData(this.instanceId, this.baileysCache); + this.client = makeWASocket(socketConfig); if (this.localSettings.wavoipToken && this.localSettings.wavoipToken.length > 0) { @@ -3188,12 +3216,35 @@ export class BaileysStartupService extends ChannelStartupService { const cachedNumbers = await getOnWhatsappCache(numbersToVerify); console.log('cachedNumbers', cachedNumbers); - const filteredNumbers = numbersToVerify.filter( - (jid) => !cachedNumbers.some((cached) => cached.jidOptions.includes(jid)), - ); + // Filter numbers that are not cached OR should be re-verified + const filteredNumbers = numbersToVerify.filter((jid) => { + const cached = cachedNumbers.find((cached) => cached.jidOptions.includes(jid)); + // If not cached, we should verify + if (!cached) return true; + + // For Brazilian numbers, force verification if both formats exist in cache + // to ensure we're using the correct format + const isBrazilian = jid.startsWith('55') && jid.includes('@s.whatsapp.net'); + if (isBrazilian) { + const numberPart = jid.replace('@s.whatsapp.net', ''); + const hasDigit9 = numberPart.length === 13 && numberPart.slice(4, 5) === '9'; + const altFormat = hasDigit9 + ? numberPart.slice(0, 4) + numberPart.slice(5) + : numberPart.slice(0, 4) + '9' + numberPart.slice(4); + const altJid = altFormat + '@s.whatsapp.net'; + + // If both formats exist in cache, prefer the one with 9 + const altCached = cachedNumbers.find((c) => c.jidOptions.includes(altJid)); + if (cached && altCached && !hasDigit9) { + return true; // Force verification to get the correct format + } + } + + return false; // Use cached result + }); console.log('filteredNumbers', filteredNumbers); - const verify = await this.client.onWhatsApp(...filteredNumbers); + const verify = filteredNumbers.length > 0 ? await this.client.onWhatsApp(...filteredNumbers) : []; console.log('verify', verify); normalVerifiedUsers = await Promise.all( normalUsers.map(async (user) => { diff --git a/src/utils/onWhatsappCache.ts b/src/utils/onWhatsappCache.ts index 68f88ba46..a82b96b85 100644 --- a/src/utils/onWhatsappCache.ts +++ b/src/utils/onWhatsappCache.ts @@ -11,14 +11,16 @@ function getAvailableNumbers(remoteJid: string) { const [number, domain] = remoteJid.split('@'); - // Brazilian numbers + // Brazilian numbers - prioritize format with 9 if (remoteJid.startsWith('55')) { const numberWithDigit = number.slice(4, 5) === '9' && number.length === 13 ? number : `${number.slice(0, 4)}9${number.slice(4)}`; const numberWithoutDigit = number.length === 12 ? number : number.slice(0, 4) + number.slice(5); - numbersAvailable.push(numberWithDigit); - numbersAvailable.push(numberWithoutDigit); + // Add the format WITH 9 first (prioritized) + numbersAvailable.push(`${numberWithDigit}@${domain || 's.whatsapp.net'}`); + // Add the format WITHOUT 9 second (fallback) + numbersAvailable.push(`${numberWithoutDigit}@${domain || 's.whatsapp.net'}`); } // Mexican/Argentina numbers @@ -38,8 +40,8 @@ function getAvailableNumbers(remoteJid: string) { : `${number.slice(0, 2)}${prefix}${number.slice(2)}`; const numberWithoutDigit = number.length === 12 ? number : number.slice(0, 2) + number.slice(3); - numbersAvailable.push(numberWithDigit); - numbersAvailable.push(numberWithoutDigit); + numbersAvailable.push(`${numberWithDigit}@${domain || 's.whatsapp.net'}`); + numbersAvailable.push(`${numberWithoutDigit}@${domain || 's.whatsapp.net'}`); } // Other countries @@ -47,7 +49,7 @@ function getAvailableNumbers(remoteJid: string) { numbersAvailable.push(remoteJid); } - return numbersAvailable.map((number) => `${number}@${domain}`); + return numbersAvailable; } interface ISaveOnWhatsappCacheParams { From 7df26eaa252dec8f9d5b653211831a7cea38ce4b Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Sat, 26 Jul 2025 18:04:23 -0300 Subject: [PATCH 18/19] =?UTF-8?q?Novas=20corre=C3=A7=C3=B5es,=20e=20logs?= =?UTF-8?q?=20de=20erro=20com=20lID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../whatsapp/whatsapp.baileys.service.ts | 119 +++++++++++++----- src/utils/onWhatsappCache.ts | 2 +- 2 files changed, 89 insertions(+), 32 deletions(-) diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index ef5ab8ca9..50e862eb6 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -422,6 +422,11 @@ export class BaileysStartupService extends ChannelStartupService { state: connection, statusReason: (lastDisconnect?.error as Boom)?.output?.statusCode ?? 200, }; + + this.logger.log(`Connection state changed to: ${connection}, instance: ${this.instance.id}`); + if (lastDisconnect?.error) { + this.logger.warn(`Connection error:`, lastDisconnect.error); + } } if (connection === 'close') { @@ -1348,6 +1353,41 @@ export class BaileysStartupService extends ChannelStartupService { this.sendDataWebhook(Events.MESSAGES_UPSERT, messageRaw); + // Schedule automatic status update for PENDING sent messages + if (messageRaw.key.fromMe && messageRaw.status === 'PENDING') { + setTimeout(async () => { + try { + const stillPendingMessage = await this.prismaRepository.message.findFirst({ + where: { + instanceId: this.instanceId, + key: { path: ['id'], equals: messageRaw.key.id }, + status: 'PENDING' + } + }); + + if (stillPendingMessage) { + this.logger.warn(`Forcing status update for PENDING message after timeout: ${messageRaw.key.id}`); + await this.prismaRepository.message.update({ + where: { id: stillPendingMessage.id }, + data: { status: 'SERVER_ACK' } + }); + + // Emit webhook for the status change + this.sendDataWebhook(Events.MESSAGES_UPDATE, { + messageId: stillPendingMessage.id, + keyId: messageRaw.key.id, + remoteJid: messageRaw.key.remoteJid, + fromMe: messageRaw.key.fromMe, + status: 'SERVER_ACK', + instanceId: this.instanceId + }); + } + } catch (error) { + this.logger.error(`Error updating PENDING message status: ${error.message}`); + } + }, 30000); // 30 seconds timeout + } + await chatbotController.emit({ instance: { instanceName: this.instance.name, instanceId: this.instanceId }, remoteJid: messageRaw.key.remoteJid, @@ -1493,33 +1533,34 @@ export class BaileysStartupService extends ChannelStartupService { continue; } else if (update.status !== undefined && status[update.status] !== findMessage.status) { - if (!key.fromMe && key.remoteJid) { - readChatToUpdate[key.remoteJid] = true; + const { remoteJid } = key; + const timestamp = findMessage.messageTimestamp; + const fromMe = key.fromMe.toString(); + const normalizedRemoteJid = normalizeJid(remoteJid); + const messageKey = `${normalizedRemoteJid}_${timestamp}_${fromMe}`; - const { remoteJid } = key; - const timestamp = findMessage.messageTimestamp; - const fromMe = key.fromMe.toString(); - const normalizedRemoteJid = normalizeJid(remoteJid); - const messageKey = `${normalizedRemoteJid}_${timestamp}_${fromMe}`; + const cachedTimestamp = await this.baileysCache.get(messageKey); - const cachedTimestamp = await this.baileysCache.get(messageKey); + if (!cachedTimestamp) { + // Handle read status for received messages + if (!key.fromMe && key.remoteJid && status[update.status] === status[4]) { + readChatToUpdate[key.remoteJid] = true; + this.logger.log(`Update as read in message.update ${remoteJid} - ${timestamp}`); + await this.updateMessagesReadedByTimestamp(remoteJid, timestamp); + await this.baileysCache.set(messageKey, true, 5 * 60); + } - if (!cachedTimestamp) { - if (status[update.status] === status[4]) { - this.logger.log(`Update as read in message.update ${remoteJid} - ${timestamp}`); - await this.updateMessagesReadedByTimestamp(remoteJid, timestamp); - await this.baileysCache.set(messageKey, true, 5 * 60); - } + // Update message status for all messages (sent and received) + await this.prismaRepository.message.update({ + where: { id: findMessage.id }, + data: { status: status[update.status] }, + }); - await this.prismaRepository.message.update({ - where: { id: findMessage.id }, - data: { status: status[update.status] }, - }); - } else { - this.logger.info( - `Update readed messages duplicated ignored in message.update [avoid deadlock]: ${messageKey}`, - ); - } + this.logger.log(`Message status updated from ${findMessage.status} to ${status[update.status]} for message ${key.id}`); + } else { + this.logger.info( + `Update messages duplicated ignored in message.update [avoid deadlock]: ${messageKey}`, + ); } } @@ -1946,11 +1987,19 @@ export class BaileysStartupService extends ChannelStartupService { } if (message['conversation']) { - return await this.client.sendMessage( - sender, - { text: message['conversation'], mentions, linkPreview: linkPreview } as unknown as AnyMessageContent, - option as unknown as MiscMessageGenerationOptions, - ); + try { + this.logger.log(`Attempting to send conversation message to ${sender}: ${message['conversation']}`); + const result = await this.client.sendMessage( + sender, + { text: message['conversation'], mentions, linkPreview: linkPreview } as unknown as AnyMessageContent, + option as unknown as MiscMessageGenerationOptions, + ); + this.logger.log(`Message sent successfully with ID: ${result.key.id}`); + return result; + } catch (error) { + this.logger.error(`Failed to send message to ${sender}:`, error); + throw error; + } } if (!message['audio'] && !message['poll'] && !message['sticker'] && sender != 'status@broadcast') { @@ -3340,7 +3389,6 @@ export class BaileysStartupService extends ChannelStartupService { .filter((user) => user.exists) .map((user) => ({ remoteJid: user.jid, - jidOptions: user.jid.replace('+', ''), lid: user.lid, })), ); @@ -4234,8 +4282,17 @@ export class BaileysStartupService extends ChannelStartupService { source: getDevice(message.key.id), }; - if (!messageRaw.status && message.key.fromMe === false) { - messageRaw.status = status[3]; // DELIVERED MESSAGE + // Log for debugging PENDING status + if (message.key.fromMe && (!message.status || message.status === 1)) { + this.logger.warn(`Message sent with PENDING status - ID: ${message.key.id}, Instance: ${this.instance.id}, Status: ${message.status}, RemoteJid: ${message.key.remoteJid}`); + } + + if (!messageRaw.status) { + if (message.key.fromMe === false) { + messageRaw.status = status[3]; // DELIVERED MESSAGE for received messages + } else { + messageRaw.status = status[2]; // SERVER_ACK for sent messages without status + } } if (messageRaw.message.extendedTextMessage) { diff --git a/src/utils/onWhatsappCache.ts b/src/utils/onWhatsappCache.ts index a82b96b85..b3310f3ec 100644 --- a/src/utils/onWhatsappCache.ts +++ b/src/utils/onWhatsappCache.ts @@ -54,7 +54,7 @@ function getAvailableNumbers(remoteJid: string) { interface ISaveOnWhatsappCacheParams { remoteJid: string; - lid?: string; + lid?: string | null; } export async function saveOnWhatsappCache(data: ISaveOnWhatsappCacheParams[]) { From e430d9e3e1c65084b3382aa2e26cc7ce6fd1f2bc Mon Sep 17 00:00:00 2001 From: Victor Calazans Date: Sat, 26 Jul 2025 18:12:02 -0300 Subject: [PATCH 19/19] Fix error json --- .../integrations/channel/whatsapp/whatsapp.baileys.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 50e862eb6..1e6741f40 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -425,7 +425,7 @@ export class BaileysStartupService extends ChannelStartupService { this.logger.log(`Connection state changed to: ${connection}, instance: ${this.instance.id}`); if (lastDisconnect?.error) { - this.logger.warn(`Connection error:`, lastDisconnect.error); + this.logger.warn(`Connection error: ${JSON.stringify(lastDisconnect.error)}`); } } @@ -1997,7 +1997,7 @@ export class BaileysStartupService extends ChannelStartupService { this.logger.log(`Message sent successfully with ID: ${result.key.id}`); return result; } catch (error) { - this.logger.error(`Failed to send message to ${sender}:`, error); + this.logger.error(`Failed to send message to ${sender}: ${error.message || JSON.stringify(error)}`); throw error; } }