mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-16 04:02:54 -06:00
refactor: add validation for media content in Evolution and Business services to enhance error handling
This commit is contained in:
parent
8ea4d65bc2
commit
1a1d9fc957
@ -455,39 +455,46 @@ export class EvolutionStartupService extends ChannelStartupService {
|
|||||||
if (base64 || file || audioFile) {
|
if (base64 || file || audioFile) {
|
||||||
if (this.configService.get<S3>('S3').ENABLE) {
|
if (this.configService.get<S3>('S3').ENABLE) {
|
||||||
try {
|
try {
|
||||||
const fileBuffer = audioFile?.buffer || file?.buffer;
|
// Verificação adicional para garantir que há conteúdo de mídia real
|
||||||
const buffer = base64 ? Buffer.from(base64, 'base64') : fileBuffer;
|
const hasRealMedia = this.hasValidMediaContent(messageRaw);
|
||||||
|
|
||||||
let mediaType: string;
|
if (!hasRealMedia) {
|
||||||
let mimetype = audioFile?.mimetype || file.mimetype;
|
this.logger.warn('Message detected as media but contains no valid media content');
|
||||||
|
} else {
|
||||||
|
const fileBuffer = audioFile?.buffer || file?.buffer;
|
||||||
|
const buffer = base64 ? Buffer.from(base64, 'base64') : fileBuffer;
|
||||||
|
|
||||||
if (messageRaw.messageType === 'documentMessage') {
|
let mediaType: string;
|
||||||
mediaType = 'document';
|
let mimetype = audioFile?.mimetype || file.mimetype;
|
||||||
mimetype = !mimetype ? 'application/pdf' : mimetype;
|
|
||||||
} else if (messageRaw.messageType === 'imageMessage') {
|
if (messageRaw.messageType === 'documentMessage') {
|
||||||
mediaType = 'image';
|
mediaType = 'document';
|
||||||
mimetype = !mimetype ? 'image/png' : mimetype;
|
mimetype = !mimetype ? 'application/pdf' : mimetype;
|
||||||
} else if (messageRaw.messageType === 'audioMessage') {
|
} else if (messageRaw.messageType === 'imageMessage') {
|
||||||
mediaType = 'audio';
|
mediaType = 'image';
|
||||||
mimetype = !mimetype ? 'audio/mp4' : mimetype;
|
mimetype = !mimetype ? 'image/png' : mimetype;
|
||||||
} else if (messageRaw.messageType === 'videoMessage') {
|
} else if (messageRaw.messageType === 'audioMessage') {
|
||||||
mediaType = 'video';
|
mediaType = 'audio';
|
||||||
mimetype = !mimetype ? 'video/mp4' : mimetype;
|
mimetype = !mimetype ? 'audio/mp4' : mimetype;
|
||||||
|
} else if (messageRaw.messageType === 'videoMessage') {
|
||||||
|
mediaType = 'video';
|
||||||
|
mimetype = !mimetype ? 'video/mp4' : mimetype;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileName = `${messageRaw.key.id}.${mimetype.split('/')[1]}`;
|
||||||
|
|
||||||
|
const size = buffer.byteLength;
|
||||||
|
|
||||||
|
const fullName = join(`${this.instance.id}`, messageRaw.key.remoteJid, mediaType, fileName);
|
||||||
|
|
||||||
|
await s3Service.uploadFile(fullName, buffer, size, {
|
||||||
|
'Content-Type': mimetype,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mediaUrl = await s3Service.getObjectUrl(fullName);
|
||||||
|
|
||||||
|
messageRaw.message.mediaUrl = mediaUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileName = `${messageRaw.key.id}.${mimetype.split('/')[1]}`;
|
|
||||||
|
|
||||||
const size = buffer.byteLength;
|
|
||||||
|
|
||||||
const fullName = join(`${this.instance.id}`, messageRaw.key.remoteJid, mediaType, fileName);
|
|
||||||
|
|
||||||
await s3Service.uploadFile(fullName, buffer, size, {
|
|
||||||
'Content-Type': mimetype,
|
|
||||||
});
|
|
||||||
|
|
||||||
const mediaUrl = await s3Service.getObjectUrl(fullName);
|
|
||||||
|
|
||||||
messageRaw.message.mediaUrl = mediaUrl;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(['Error on upload file to minio', error?.message, error?.stack]);
|
this.logger.error(['Error on upload file to minio', error?.message, error?.stack]);
|
||||||
}
|
}
|
||||||
|
@ -429,107 +429,114 @@ export class BusinessStartupService extends ChannelStartupService {
|
|||||||
try {
|
try {
|
||||||
const message: any = received;
|
const message: any = received;
|
||||||
|
|
||||||
const id = message.messages[0][message.messages[0].type].id;
|
// Verificação adicional para garantir que há conteúdo de mídia real
|
||||||
let urlServer = this.configService.get<WaBusiness>('WA_BUSINESS').URL;
|
const hasRealMedia = this.hasValidMediaContent(messageRaw);
|
||||||
const version = this.configService.get<WaBusiness>('WA_BUSINESS').VERSION;
|
|
||||||
urlServer = `${urlServer}/${version}/${id}`;
|
|
||||||
const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${this.token}` };
|
|
||||||
const result = await axios.get(urlServer, { headers });
|
|
||||||
|
|
||||||
const buffer = await axios.get(result.data.url, {
|
if (!hasRealMedia) {
|
||||||
headers: { Authorization: `Bearer ${this.token}` }, // Use apenas o token de autorização para download
|
this.logger.warn('Message detected as media but contains no valid media content');
|
||||||
responseType: 'arraybuffer',
|
|
||||||
});
|
|
||||||
|
|
||||||
let mediaType;
|
|
||||||
|
|
||||||
if (message.messages[0].document) {
|
|
||||||
mediaType = 'document';
|
|
||||||
} else if (message.messages[0].image) {
|
|
||||||
mediaType = 'image';
|
|
||||||
} else if (message.messages[0].audio) {
|
|
||||||
mediaType = 'audio';
|
|
||||||
} else {
|
} else {
|
||||||
mediaType = 'video';
|
const id = message.messages[0][message.messages[0].type].id;
|
||||||
}
|
let urlServer = this.configService.get<WaBusiness>('WA_BUSINESS').URL;
|
||||||
|
const version = this.configService.get<WaBusiness>('WA_BUSINESS').VERSION;
|
||||||
|
urlServer = `${urlServer}/${version}/${id}`;
|
||||||
|
const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${this.token}` };
|
||||||
|
const result = await axios.get(urlServer, { headers });
|
||||||
|
|
||||||
const mimetype = result.data?.mime_type || result.headers['content-type'];
|
const buffer = await axios.get(result.data.url, {
|
||||||
|
headers: { Authorization: `Bearer ${this.token}` }, // Use apenas o token de autorização para download
|
||||||
|
responseType: 'arraybuffer',
|
||||||
|
});
|
||||||
|
|
||||||
const contentDisposition = result.headers['content-disposition'];
|
let mediaType;
|
||||||
let fileName = `${message.messages[0].id}.${mimetype.split('/')[1]}`;
|
|
||||||
if (contentDisposition) {
|
if (message.messages[0].document) {
|
||||||
const match = contentDisposition.match(/filename="(.+?)"/);
|
mediaType = 'document';
|
||||||
if (match) {
|
} else if (message.messages[0].image) {
|
||||||
fileName = match[1];
|
mediaType = 'image';
|
||||||
|
} else if (message.messages[0].audio) {
|
||||||
|
mediaType = 'audio';
|
||||||
|
} else {
|
||||||
|
mediaType = 'video';
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Para áudio, garantir extensão correta baseada no mimetype
|
const mimetype = result.data?.mime_type || result.headers['content-type'];
|
||||||
if (mediaType === 'audio') {
|
|
||||||
if (mimetype.includes('ogg')) {
|
const contentDisposition = result.headers['content-disposition'];
|
||||||
fileName = `${message.messages[0].id}.ogg`;
|
let fileName = `${message.messages[0].id}.${mimetype.split('/')[1]}`;
|
||||||
} else if (mimetype.includes('mp3')) {
|
if (contentDisposition) {
|
||||||
fileName = `${message.messages[0].id}.mp3`;
|
const match = contentDisposition.match(/filename="(.+?)"/);
|
||||||
} else if (mimetype.includes('m4a')) {
|
if (match) {
|
||||||
fileName = `${message.messages[0].id}.m4a`;
|
fileName = match[1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const size = result.headers['content-length'] || buffer.data.byteLength;
|
// Para áudio, garantir extensão correta baseada no mimetype
|
||||||
|
if (mediaType === 'audio') {
|
||||||
|
if (mimetype.includes('ogg')) {
|
||||||
|
fileName = `${message.messages[0].id}.ogg`;
|
||||||
|
} else if (mimetype.includes('mp3')) {
|
||||||
|
fileName = `${message.messages[0].id}.mp3`;
|
||||||
|
} else if (mimetype.includes('m4a')) {
|
||||||
|
fileName = `${message.messages[0].id}.m4a`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fullName = join(`${this.instance.id}`, key.remoteJid, mediaType, fileName);
|
const size = result.headers['content-length'] || buffer.data.byteLength;
|
||||||
|
|
||||||
await s3Service.uploadFile(fullName, buffer.data, size, {
|
const fullName = join(`${this.instance.id}`, key.remoteJid, mediaType, fileName);
|
||||||
'Content-Type': mimetype,
|
|
||||||
});
|
|
||||||
|
|
||||||
const createdMessage = await this.prismaRepository.message.create({
|
await s3Service.uploadFile(fullName, buffer.data, size, {
|
||||||
data: messageRaw,
|
'Content-Type': mimetype,
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.prismaRepository.media.create({
|
const createdMessage = await this.prismaRepository.message.create({
|
||||||
data: {
|
data: messageRaw,
|
||||||
messageId: createdMessage.id,
|
});
|
||||||
instanceId: this.instanceId,
|
|
||||||
type: mediaType,
|
|
||||||
fileName: fullName,
|
|
||||||
mimetype,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const mediaUrl = await s3Service.getObjectUrl(fullName);
|
await this.prismaRepository.media.create({
|
||||||
|
data: {
|
||||||
messageRaw.message.mediaUrl = mediaUrl;
|
messageId: createdMessage.id,
|
||||||
messageRaw.message.base64 = buffer.data.toString('base64');
|
|
||||||
|
|
||||||
// Processar OpenAI speech-to-text para áudio após o mediaUrl estar disponível
|
|
||||||
if (this.configService.get<Openai>('OPENAI').ENABLED && mediaType === 'audio') {
|
|
||||||
const openAiDefaultSettings = await this.prismaRepository.openaiSetting.findFirst({
|
|
||||||
where: {
|
|
||||||
instanceId: this.instanceId,
|
instanceId: this.instanceId,
|
||||||
},
|
type: mediaType,
|
||||||
include: {
|
fileName: fullName,
|
||||||
OpenaiCreds: true,
|
mimetype,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (
|
const mediaUrl = await s3Service.getObjectUrl(fullName);
|
||||||
openAiDefaultSettings &&
|
|
||||||
openAiDefaultSettings.openaiCredsId &&
|
messageRaw.message.mediaUrl = mediaUrl;
|
||||||
openAiDefaultSettings.speechToText
|
messageRaw.message.base64 = buffer.data.toString('base64');
|
||||||
) {
|
|
||||||
try {
|
// Processar OpenAI speech-to-text para áudio após o mediaUrl estar disponível
|
||||||
messageRaw.message.speechToText = `[audio] ${await this.openaiService.speechToText(
|
if (this.configService.get<Openai>('OPENAI').ENABLED && mediaType === 'audio') {
|
||||||
openAiDefaultSettings.OpenaiCreds,
|
const openAiDefaultSettings = await this.prismaRepository.openaiSetting.findFirst({
|
||||||
{
|
where: {
|
||||||
message: {
|
instanceId: this.instanceId,
|
||||||
mediaUrl: messageRaw.message.mediaUrl,
|
},
|
||||||
...messageRaw,
|
include: {
|
||||||
|
OpenaiCreds: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
openAiDefaultSettings &&
|
||||||
|
openAiDefaultSettings.openaiCredsId &&
|
||||||
|
openAiDefaultSettings.speechToText
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
messageRaw.message.speechToText = `[audio] ${await this.openaiService.speechToText(
|
||||||
|
openAiDefaultSettings.OpenaiCreds,
|
||||||
|
{
|
||||||
|
message: {
|
||||||
|
mediaUrl: messageRaw.message.mediaUrl,
|
||||||
|
...messageRaw,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
)}`;
|
||||||
)}`;
|
} catch (speechError) {
|
||||||
} catch (speechError) {
|
this.logger.error(`Error processing speech-to-text: ${speechError}`);
|
||||||
this.logger.error(`Error processing speech-to-text: ${speechError}`);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user