Skip to content

Commit e65c66f

Browse files
authored
🖼️ feat: Avatar GIF Support & Dynamic Extensions (danny-avila#7657)
1 parent a1f8dcf commit e65c66f

File tree

7 files changed

+58
-10
lines changed

7 files changed

+58
-10
lines changed

api/server/controllers/agents/v1.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const {
1818
} = require('~/models/Agent');
1919
const { uploadImageBuffer, filterFile } = require('~/server/services/Files/process');
2020
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
21+
const { resizeAvatar } = require('~/server/services/Files/images/avatar');
2122
const { refreshS3Url } = require('~/server/services/Files/S3/crud');
2223
const { updateAction, getActions } = require('~/models/Action');
2324
const { updateAgentProjects } = require('~/models/Agent');
@@ -373,12 +374,26 @@ const uploadAgentAvatarHandler = async (req, res) => {
373374
}
374375

375376
const buffer = await fs.readFile(req.file.path);
376-
const image = await uploadImageBuffer({
377-
req,
378-
context: FileContext.avatar,
379-
metadata: { buffer },
377+
378+
const fileStrategy = req.app.locals.fileStrategy;
379+
380+
const resizedBuffer = await resizeAvatar({
381+
userId: req.user.id,
382+
input: buffer,
383+
});
384+
385+
const { processAvatar } = getStrategyFunctions(fileStrategy);
386+
const avatarUrl = await processAvatar({
387+
buffer: resizedBuffer,
388+
userId: req.user.id,
389+
manual: 'false',
380390
});
381391

392+
const image = {
393+
filepath: avatarUrl,
394+
source: fileStrategy,
395+
};
396+
382397
let _avatar;
383398
try {
384399
const agent = await getAgent({ id: agent_id });
@@ -403,7 +418,7 @@ const uploadAgentAvatarHandler = async (req, res) => {
403418
const data = {
404419
avatar: {
405420
filepath: image.filepath,
406-
source: req.app.locals.fileStrategy,
421+
source: image.source,
407422
},
408423
};
409424

api/server/services/Files/Azure/images.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,14 @@ async function prepareAzureImageURL(req, file) {
9797
*/
9898
async function processAzureAvatar({ buffer, userId, manual, basePath = 'images', containerName }) {
9999
try {
100+
const metadata = await sharp(buffer).metadata();
101+
const extension = metadata.format === 'gif' ? 'gif' : 'png';
102+
const fileName = `avatar.${extension}`;
103+
100104
const downloadURL = await saveBufferToAzure({
101105
userId,
102106
buffer,
103-
fileName: 'avatar.png',
107+
fileName,
104108
basePath,
105109
containerName,
106110
});

api/server/services/Files/Firebase/images.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,14 @@ async function prepareImageURL(req, file) {
8787
*/
8888
async function processFirebaseAvatar({ buffer, userId, manual }) {
8989
try {
90+
const metadata = await sharp(buffer).metadata();
91+
const extension = metadata.format === 'gif' ? 'gif' : 'png';
92+
const fileName = `avatar.${extension}`;
93+
9094
const downloadURL = await saveBufferToFirebase({
9195
userId,
9296
buffer,
93-
fileName: 'avatar.png',
97+
fileName,
9498
});
9599

96100
const isManual = manual === 'true';

api/server/services/Files/Local/images.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ async function processLocalAvatar({ buffer, userId, manual }) {
129129
userId,
130130
);
131131

132-
const fileName = `avatar-${new Date().getTime()}.png`;
132+
const metadata = await sharp(buffer).metadata();
133+
const extension = metadata.format === 'gif' ? 'gif' : 'png';
134+
135+
const fileName = `avatar-${new Date().getTime()}.${extension}`;
133136
const urlRoute = `/images/${userId}/${fileName}`;
134137
const avatarPath = path.join(userDir, fileName);
135138

api/server/services/Files/S3/images.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,11 @@ async function prepareImageURLS3(req, file) {
9999
*/
100100
async function processS3Avatar({ buffer, userId, manual, basePath = defaultBasePath }) {
101101
try {
102-
const downloadURL = await saveBufferToS3({ userId, buffer, fileName: 'avatar.png', basePath });
102+
const metadata = await sharp(buffer).metadata();
103+
const extension = metadata.format === 'gif' ? 'gif' : 'png';
104+
const fileName = `avatar.${extension}`;
105+
106+
const downloadURL = await saveBufferToS3({ userId, buffer, fileName, basePath });
103107
if (manual === 'true') {
104108
await updateUser(userId, { avatar: downloadURL });
105109
}

api/server/services/Files/images/avatar.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,25 @@ async function resizeAvatar({ userId, input, desiredFormat = EImageOutputType.PN
4444
throw new Error('Invalid input type. Expected URL, Buffer, or File.');
4545
}
4646

47-
const { width, height } = await sharp(imageBuffer).metadata();
47+
const metadata = await sharp(imageBuffer).metadata();
48+
const { width, height } = metadata;
4849
const minSize = Math.min(width, height);
50+
51+
if (metadata.format === 'gif') {
52+
const resizedBuffer = await sharp(imageBuffer, { animated: true })
53+
.extract({
54+
left: Math.floor((width - minSize) / 2),
55+
top: Math.floor((height - minSize) / 2),
56+
width: minSize,
57+
height: minSize,
58+
})
59+
.resize(250, 250)
60+
.gif()
61+
.toBuffer();
62+
63+
return resizedBuffer;
64+
}
65+
4966
const squaredBuffer = await sharp(imageBuffer)
5067
.extract({
5168
left: Math.floor((width - minSize) / 2),

client/src/components/SidePanel/Agents/Images.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export const AgentAvatarRender = ({
5050
width="80"
5151
height="80"
5252
style={{ opacity: progress < 1 ? 0.4 : 1 }}
53+
key={url || 'default-key'}
5354
/>
5455
{progress < 1 && (
5556
<div className="absolute inset-0 flex items-center justify-center bg-black/5 text-white">

0 commit comments

Comments
 (0)