diff --git a/api/server/controllers/agents/v1.js b/api/server/controllers/agents/v1.js index 244b6e8e23..65189a18a1 100644 --- a/api/server/controllers/agents/v1.js +++ b/api/server/controllers/agents/v1.js @@ -18,6 +18,7 @@ const { } = require('~/models/Agent'); const { uploadImageBuffer, filterFile } = require('~/server/services/Files/process'); const { getStrategyFunctions } = require('~/server/services/Files/strategies'); +const { resizeAvatar } = require('~/server/services/Files/images/avatar'); const { refreshS3Url } = require('~/server/services/Files/S3/crud'); const { updateAction, getActions } = require('~/models/Action'); const { updateAgentProjects } = require('~/models/Agent'); @@ -373,12 +374,26 @@ const uploadAgentAvatarHandler = async (req, res) => { } const buffer = await fs.readFile(req.file.path); - const image = await uploadImageBuffer({ - req, - context: FileContext.avatar, - metadata: { buffer }, + + const fileStrategy = req.app.locals.fileStrategy; + + const resizedBuffer = await resizeAvatar({ + userId: req.user.id, + input: buffer, }); + const { processAvatar } = getStrategyFunctions(fileStrategy); + const avatarUrl = await processAvatar({ + buffer: resizedBuffer, + userId: req.user.id, + manual: 'false', + }); + + const image = { + filepath: avatarUrl, + source: fileStrategy, + }; + let _avatar; try { const agent = await getAgent({ id: agent_id }); @@ -403,7 +418,7 @@ const uploadAgentAvatarHandler = async (req, res) => { const data = { avatar: { filepath: image.filepath, - source: req.app.locals.fileStrategy, + source: image.source, }, }; diff --git a/api/server/services/Files/Azure/images.js b/api/server/services/Files/Azure/images.js index 6672806dbd..80163bee05 100644 --- a/api/server/services/Files/Azure/images.js +++ b/api/server/services/Files/Azure/images.js @@ -97,10 +97,14 @@ async function prepareAzureImageURL(req, file) { */ async function processAzureAvatar({ buffer, userId, manual, basePath = 'images', containerName }) { try { + const metadata = await sharp(buffer).metadata(); + const extension = metadata.format === 'gif' ? 'gif' : 'png'; + const fileName = `avatar.${extension}`; + const downloadURL = await saveBufferToAzure({ userId, buffer, - fileName: 'avatar.png', + fileName, basePath, containerName, }); diff --git a/api/server/services/Files/Firebase/images.js b/api/server/services/Files/Firebase/images.js index 980095da3d..80bff28d89 100644 --- a/api/server/services/Files/Firebase/images.js +++ b/api/server/services/Files/Firebase/images.js @@ -87,10 +87,14 @@ async function prepareImageURL(req, file) { */ async function processFirebaseAvatar({ buffer, userId, manual }) { try { + const metadata = await sharp(buffer).metadata(); + const extension = metadata.format === 'gif' ? 'gif' : 'png'; + const fileName = `avatar.${extension}`; + const downloadURL = await saveBufferToFirebase({ userId, buffer, - fileName: 'avatar.png', + fileName, }); const isManual = manual === 'true'; diff --git a/api/server/services/Files/Local/images.js b/api/server/services/Files/Local/images.js index cb60d425c6..fc344cea88 100644 --- a/api/server/services/Files/Local/images.js +++ b/api/server/services/Files/Local/images.js @@ -129,7 +129,10 @@ async function processLocalAvatar({ buffer, userId, manual }) { userId, ); - const fileName = `avatar-${new Date().getTime()}.png`; + const metadata = await sharp(buffer).metadata(); + const extension = metadata.format === 'gif' ? 'gif' : 'png'; + + const fileName = `avatar-${new Date().getTime()}.${extension}`; const urlRoute = `/images/${userId}/${fileName}`; const avatarPath = path.join(userDir, fileName); diff --git a/api/server/services/Files/S3/images.js b/api/server/services/Files/S3/images.js index d8d9c85cf5..07faec1765 100644 --- a/api/server/services/Files/S3/images.js +++ b/api/server/services/Files/S3/images.js @@ -99,7 +99,11 @@ async function prepareImageURLS3(req, file) { */ async function processS3Avatar({ buffer, userId, manual, basePath = defaultBasePath }) { try { - const downloadURL = await saveBufferToS3({ userId, buffer, fileName: 'avatar.png', basePath }); + const metadata = await sharp(buffer).metadata(); + const extension = metadata.format === 'gif' ? 'gif' : 'png'; + const fileName = `avatar.${extension}`; + + const downloadURL = await saveBufferToS3({ userId, buffer, fileName, basePath }); if (manual === 'true') { await updateUser(userId, { avatar: downloadURL }); } diff --git a/api/server/services/Files/images/avatar.js b/api/server/services/Files/images/avatar.js index 3c1068a453..8e81dea26c 100644 --- a/api/server/services/Files/images/avatar.js +++ b/api/server/services/Files/images/avatar.js @@ -44,8 +44,25 @@ async function resizeAvatar({ userId, input, desiredFormat = EImageOutputType.PN throw new Error('Invalid input type. Expected URL, Buffer, or File.'); } - const { width, height } = await sharp(imageBuffer).metadata(); + const metadata = await sharp(imageBuffer).metadata(); + const { width, height } = metadata; const minSize = Math.min(width, height); + + if (metadata.format === 'gif') { + const resizedBuffer = await sharp(imageBuffer, { animated: true }) + .extract({ + left: Math.floor((width - minSize) / 2), + top: Math.floor((height - minSize) / 2), + width: minSize, + height: minSize, + }) + .resize(250, 250) + .gif() + .toBuffer(); + + return resizedBuffer; + } + const squaredBuffer = await sharp(imageBuffer) .extract({ left: Math.floor((width - minSize) / 2), diff --git a/client/src/components/SidePanel/Agents/Images.tsx b/client/src/components/SidePanel/Agents/Images.tsx index 2ee8b754a4..ef79982504 100644 --- a/client/src/components/SidePanel/Agents/Images.tsx +++ b/client/src/components/SidePanel/Agents/Images.tsx @@ -50,6 +50,7 @@ export const AgentAvatarRender = ({ width="80" height="80" style={{ opacity: progress < 1 ? 0.4 : 1 }} + key={url || 'default-key'} /> {progress < 1 && (