Skip to content

Commit 1a1d9fc

Browse files
committed
refactor: add validation for media content in Evolution and Business services to enhance error handling
1 parent 8ea4d65 commit 1a1d9fc

File tree

2 files changed

+124
-110
lines changed

2 files changed

+124
-110
lines changed

src/api/integrations/channel/evolution/evolution.channel.service.ts

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -455,39 +455,46 @@ export class EvolutionStartupService extends ChannelStartupService {
455455
if (base64 || file || audioFile) {
456456
if (this.configService.get<S3>('S3').ENABLE) {
457457
try {
458-
const fileBuffer = audioFile?.buffer || file?.buffer;
459-
const buffer = base64 ? Buffer.from(base64, 'base64') : fileBuffer;
460-
461-
let mediaType: string;
462-
let mimetype = audioFile?.mimetype || file.mimetype;
463-
464-
if (messageRaw.messageType === 'documentMessage') {
465-
mediaType = 'document';
466-
mimetype = !mimetype ? 'application/pdf' : mimetype;
467-
} else if (messageRaw.messageType === 'imageMessage') {
468-
mediaType = 'image';
469-
mimetype = !mimetype ? 'image/png' : mimetype;
470-
} else if (messageRaw.messageType === 'audioMessage') {
471-
mediaType = 'audio';
472-
mimetype = !mimetype ? 'audio/mp4' : mimetype;
473-
} else if (messageRaw.messageType === 'videoMessage') {
474-
mediaType = 'video';
475-
mimetype = !mimetype ? 'video/mp4' : mimetype;
476-
}
458+
// Verificação adicional para garantir que há conteúdo de mídia real
459+
const hasRealMedia = this.hasValidMediaContent(messageRaw);
460+
461+
if (!hasRealMedia) {
462+
this.logger.warn('Message detected as media but contains no valid media content');
463+
} else {
464+
const fileBuffer = audioFile?.buffer || file?.buffer;
465+
const buffer = base64 ? Buffer.from(base64, 'base64') : fileBuffer;
466+
467+
let mediaType: string;
468+
let mimetype = audioFile?.mimetype || file.mimetype;
477469

478-
const fileName = `${messageRaw.key.id}.${mimetype.split('/')[1]}`;
470+
if (messageRaw.messageType === 'documentMessage') {
471+
mediaType = 'document';
472+
mimetype = !mimetype ? 'application/pdf' : mimetype;
473+
} else if (messageRaw.messageType === 'imageMessage') {
474+
mediaType = 'image';
475+
mimetype = !mimetype ? 'image/png' : mimetype;
476+
} else if (messageRaw.messageType === 'audioMessage') {
477+
mediaType = 'audio';
478+
mimetype = !mimetype ? 'audio/mp4' : mimetype;
479+
} else if (messageRaw.messageType === 'videoMessage') {
480+
mediaType = 'video';
481+
mimetype = !mimetype ? 'video/mp4' : mimetype;
482+
}
479483

480-
const size = buffer.byteLength;
484+
const fileName = `${messageRaw.key.id}.${mimetype.split('/')[1]}`;
481485

482-
const fullName = join(`${this.instance.id}`, messageRaw.key.remoteJid, mediaType, fileName);
486+
const size = buffer.byteLength;
483487

484-
await s3Service.uploadFile(fullName, buffer, size, {
485-
'Content-Type': mimetype,
486-
});
488+
const fullName = join(`${this.instance.id}`, messageRaw.key.remoteJid, mediaType, fileName);
487489

488-
const mediaUrl = await s3Service.getObjectUrl(fullName);
490+
await s3Service.uploadFile(fullName, buffer, size, {
491+
'Content-Type': mimetype,
492+
});
489493

490-
messageRaw.message.mediaUrl = mediaUrl;
494+
const mediaUrl = await s3Service.getObjectUrl(fullName);
495+
496+
messageRaw.message.mediaUrl = mediaUrl;
497+
}
491498
} catch (error) {
492499
this.logger.error(['Error on upload file to minio', error?.message, error?.stack]);
493500
}

src/api/integrations/channel/meta/whatsapp.business.service.ts

Lines changed: 90 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -429,107 +429,114 @@ export class BusinessStartupService extends ChannelStartupService {
429429
try {
430430
const message: any = received;
431431

432-
const id = message.messages[0][message.messages[0].type].id;
433-
let urlServer = this.configService.get<WaBusiness>('WA_BUSINESS').URL;
434-
const version = this.configService.get<WaBusiness>('WA_BUSINESS').VERSION;
435-
urlServer = `${urlServer}/${version}/${id}`;
436-
const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${this.token}` };
437-
const result = await axios.get(urlServer, { headers });
438-
439-
const buffer = await axios.get(result.data.url, {
440-
headers: { Authorization: `Bearer ${this.token}` }, // Use apenas o token de autorização para download
441-
responseType: 'arraybuffer',
442-
});
443-
444-
let mediaType;
432+
// Verificação adicional para garantir que há conteúdo de mídia real
433+
const hasRealMedia = this.hasValidMediaContent(messageRaw);
445434

446-
if (message.messages[0].document) {
447-
mediaType = 'document';
448-
} else if (message.messages[0].image) {
449-
mediaType = 'image';
450-
} else if (message.messages[0].audio) {
451-
mediaType = 'audio';
435+
if (!hasRealMedia) {
436+
this.logger.warn('Message detected as media but contains no valid media content');
452437
} else {
453-
mediaType = 'video';
454-
}
438+
const id = message.messages[0][message.messages[0].type].id;
439+
let urlServer = this.configService.get<WaBusiness>('WA_BUSINESS').URL;
440+
const version = this.configService.get<WaBusiness>('WA_BUSINESS').VERSION;
441+
urlServer = `${urlServer}/${version}/${id}`;
442+
const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${this.token}` };
443+
const result = await axios.get(urlServer, { headers });
444+
445+
const buffer = await axios.get(result.data.url, {
446+
headers: { Authorization: `Bearer ${this.token}` }, // Use apenas o token de autorização para download
447+
responseType: 'arraybuffer',
448+
});
455449

456-
const mimetype = result.data?.mime_type || result.headers['content-type'];
450+
let mediaType;
457451

458-
const contentDisposition = result.headers['content-disposition'];
459-
let fileName = `${message.messages[0].id}.${mimetype.split('/')[1]}`;
460-
if (contentDisposition) {
461-
const match = contentDisposition.match(/filename="(.+?)"/);
462-
if (match) {
463-
fileName = match[1];
452+
if (message.messages[0].document) {
453+
mediaType = 'document';
454+
} else if (message.messages[0].image) {
455+
mediaType = 'image';
456+
} else if (message.messages[0].audio) {
457+
mediaType = 'audio';
458+
} else {
459+
mediaType = 'video';
464460
}
465-
}
466461

467-
// Para áudio, garantir extensão correta baseada no mimetype
468-
if (mediaType === 'audio') {
469-
if (mimetype.includes('ogg')) {
470-
fileName = `${message.messages[0].id}.ogg`;
471-
} else if (mimetype.includes('mp3')) {
472-
fileName = `${message.messages[0].id}.mp3`;
473-
} else if (mimetype.includes('m4a')) {
474-
fileName = `${message.messages[0].id}.m4a`;
475-
}
476-
}
462+
const mimetype = result.data?.mime_type || result.headers['content-type'];
477463

478-
const size = result.headers['content-length'] || buffer.data.byteLength;
464+
const contentDisposition = result.headers['content-disposition'];
465+
let fileName = `${message.messages[0].id}.${mimetype.split('/')[1]}`;
466+
if (contentDisposition) {
467+
const match = contentDisposition.match(/filename="(.+?)"/);
468+
if (match) {
469+
fileName = match[1];
470+
}
471+
}
479472

480-
const fullName = join(`${this.instance.id}`, key.remoteJid, mediaType, fileName);
473+
// Para áudio, garantir extensão correta baseada no mimetype
474+
if (mediaType === 'audio') {
475+
if (mimetype.includes('ogg')) {
476+
fileName = `${message.messages[0].id}.ogg`;
477+
} else if (mimetype.includes('mp3')) {
478+
fileName = `${message.messages[0].id}.mp3`;
479+
} else if (mimetype.includes('m4a')) {
480+
fileName = `${message.messages[0].id}.m4a`;
481+
}
482+
}
481483

482-
await s3Service.uploadFile(fullName, buffer.data, size, {
483-
'Content-Type': mimetype,
484-
});
484+
const size = result.headers['content-length'] || buffer.data.byteLength;
485485

486-
const createdMessage = await this.prismaRepository.message.create({
487-
data: messageRaw,
488-
});
486+
const fullName = join(`${this.instance.id}`, key.remoteJid, mediaType, fileName);
489487

490-
await this.prismaRepository.media.create({
491-
data: {
492-
messageId: createdMessage.id,
493-
instanceId: this.instanceId,
494-
type: mediaType,
495-
fileName: fullName,
496-
mimetype,
497-
},
498-
});
499-
500-
const mediaUrl = await s3Service.getObjectUrl(fullName);
488+
await s3Service.uploadFile(fullName, buffer.data, size, {
489+
'Content-Type': mimetype,
490+
});
501491

502-
messageRaw.message.mediaUrl = mediaUrl;
503-
messageRaw.message.base64 = buffer.data.toString('base64');
492+
const createdMessage = await this.prismaRepository.message.create({
493+
data: messageRaw,
494+
});
504495

505-
// Processar OpenAI speech-to-text para áudio após o mediaUrl estar disponível
506-
if (this.configService.get<Openai>('OPENAI').ENABLED && mediaType === 'audio') {
507-
const openAiDefaultSettings = await this.prismaRepository.openaiSetting.findFirst({
508-
where: {
496+
await this.prismaRepository.media.create({
497+
data: {
498+
messageId: createdMessage.id,
509499
instanceId: this.instanceId,
510-
},
511-
include: {
512-
OpenaiCreds: true,
500+
type: mediaType,
501+
fileName: fullName,
502+
mimetype,
513503
},
514504
});
515505

516-
if (
517-
openAiDefaultSettings &&
518-
openAiDefaultSettings.openaiCredsId &&
519-
openAiDefaultSettings.speechToText
520-
) {
521-
try {
522-
messageRaw.message.speechToText = `[audio] ${await this.openaiService.speechToText(
523-
openAiDefaultSettings.OpenaiCreds,
524-
{
525-
message: {
526-
mediaUrl: messageRaw.message.mediaUrl,
527-
...messageRaw,
506+
const mediaUrl = await s3Service.getObjectUrl(fullName);
507+
508+
messageRaw.message.mediaUrl = mediaUrl;
509+
messageRaw.message.base64 = buffer.data.toString('base64');
510+
511+
// Processar OpenAI speech-to-text para áudio após o mediaUrl estar disponível
512+
if (this.configService.get<Openai>('OPENAI').ENABLED && mediaType === 'audio') {
513+
const openAiDefaultSettings = await this.prismaRepository.openaiSetting.findFirst({
514+
where: {
515+
instanceId: this.instanceId,
516+
},
517+
include: {
518+
OpenaiCreds: true,
519+
},
520+
});
521+
522+
if (
523+
openAiDefaultSettings &&
524+
openAiDefaultSettings.openaiCredsId &&
525+
openAiDefaultSettings.speechToText
526+
) {
527+
try {
528+
messageRaw.message.speechToText = `[audio] ${await this.openaiService.speechToText(
529+
openAiDefaultSettings.OpenaiCreds,
530+
{
531+
message: {
532+
mediaUrl: messageRaw.message.mediaUrl,
533+
...messageRaw,
534+
},
528535
},
529-
},
530-
)}`;
531-
} catch (speechError) {
532-
this.logger.error(`Error processing speech-to-text: ${speechError}`);
536+
)}`;
537+
} catch (speechError) {
538+
this.logger.error(`Error processing speech-to-text: ${speechError}`);
539+
}
533540
}
534541
}
535542
}

0 commit comments

Comments
 (0)