🖼️ fix: Avatar Handling for Agents and Assistants (#4507)

The changes include:
- In the agent controller:
  - Removed the parsing of the avatar metadata from the request body.
  - Fetched the avatar data from the agent object using the agent ID.
  - Updated the error logging when fetching the agent.
  - Updated the deleteFileByFilter function to include the user ID when deleting the old avatar file.

- In the assistant controller:
  - Removed the parsing of the metadata from the request body.
  - Fetched the metadata from the assistant object using the assistant ID.
  - Updated the error logging when fetching the assistant.
  - Updated the deleteFileByFilter function to include the user ID when deleting the old avatar file.
This commit is contained in:
Danny Avila 2024-10-22 14:53:45 -04:00 committed by GitHub
parent ec922986a9
commit ebe3e7f796
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 37 additions and 35 deletions

View file

@ -226,8 +226,6 @@ const uploadAgentAvatarHandler = async (req, res) => {
return res.status(400).json({ message: 'Agent ID is required' }); return res.status(400).json({ message: 'Agent ID is required' });
} }
let { avatar: _avatar = '{}' } = req.body;
const image = await uploadImageBuffer({ const image = await uploadImageBuffer({
req, req,
context: FileContext.avatar, context: FileContext.avatar,
@ -236,10 +234,12 @@ const uploadAgentAvatarHandler = async (req, res) => {
}, },
}); });
let _avatar;
try { try {
_avatar = JSON.parse(_avatar); const agent = await getAgent({ id: agent_id });
_avatar = agent.avatar;
} catch (error) { } catch (error) {
logger.error('[/avatar/:agent_id] Error parsing avatar', error); logger.error('[/avatar/:agent_id] Error fetching agent', error);
_avatar = {}; _avatar = {};
} }
@ -247,7 +247,7 @@ const uploadAgentAvatarHandler = async (req, res) => {
const { deleteFile } = getStrategyFunctions(_avatar.source); const { deleteFile } = getStrategyFunctions(_avatar.source);
try { try {
await deleteFile(req, { filepath: _avatar.filepath }); await deleteFile(req, { filepath: _avatar.filepath });
await deleteFileByFilter({ filepath: _avatar.filepath }); await deleteFileByFilter({ user: req.user.id, filepath: _avatar.filepath });
} catch (error) { } catch (error) {
logger.error('[/avatar/:agent_id] Error deleting old avatar', error); logger.error('[/avatar/:agent_id] Error deleting old avatar', error);
} }

View file

@ -241,7 +241,6 @@ const getAssistantDocuments = async (req, res) => {
* @param {string} req.params.assistant_id - The ID of the assistant. * @param {string} req.params.assistant_id - The ID of the assistant.
* @param {Express.Multer.File} req.file - The avatar image file. * @param {Express.Multer.File} req.file - The avatar image file.
* @param {object} req.body - Request body * @param {object} req.body - Request body
* @param {string} [req.body.metadata] - Optional metadata for the assistant's avatar.
* @returns {Object} 200 - success response - application/json * @returns {Object} 200 - success response - application/json
*/ */
const uploadAssistantAvatar = async (req, res) => { const uploadAssistantAvatar = async (req, res) => {
@ -251,7 +250,6 @@ const uploadAssistantAvatar = async (req, res) => {
return res.status(400).json({ message: 'Assistant ID is required' }); return res.status(400).json({ message: 'Assistant ID is required' });
} }
let { metadata: _metadata = '{}' } = req.body;
const { openai } = await getOpenAIClient({ req, res }); const { openai } = await getOpenAIClient({ req, res });
await validateAuthor({ req, openai }); await validateAuthor({ req, openai });
@ -263,10 +261,15 @@ const uploadAssistantAvatar = async (req, res) => {
}, },
}); });
let _metadata;
try { try {
_metadata = JSON.parse(_metadata); const assistant = await openai.beta.assistants.retrieve(assistant_id);
if (assistant) {
_metadata = assistant.metadata;
}
} catch (error) { } catch (error) {
logger.error('[/avatar/:assistant_id] Error parsing metadata', error); logger.error('[/avatar/:assistant_id] Error fetching assistant', error);
_metadata = {}; _metadata = {};
} }
@ -274,7 +277,7 @@ const uploadAssistantAvatar = async (req, res) => {
const { deleteFile } = getStrategyFunctions(_metadata.avatar_source); const { deleteFile } = getStrategyFunctions(_metadata.avatar_source);
try { try {
await deleteFile(req, { filepath: _metadata.avatar }); await deleteFile(req, { filepath: _metadata.avatar });
await deleteFileByFilter({ filepath: _metadata.avatar }); await deleteFileByFilter({ user: req.user.id, filepath: _metadata.avatar });
} catch (error) { } catch (error) {
logger.error('[/avatar/:assistant_id] Error deleting old avatar', error); logger.error('[/avatar/:assistant_id] Error deleting old avatar', error);
} }

View file

@ -202,8 +202,20 @@ const deleteLocalFile = async (req, file) => {
} }
if (file.filepath.startsWith(`/uploads/${req.user.id}`)) { if (file.filepath.startsWith(`/uploads/${req.user.id}`)) {
const basePath = file.filepath.split('/uploads/')[1]; const userUploadDir = path.join(uploads, req.user.id);
const filepath = path.join(uploads, basePath); const basePath = file.filepath.split(`/uploads/${req.user.id}/`)[1];
if (!basePath) {
throw new Error(`Invalid file path: ${file.filepath}`);
}
const filepath = path.join(userUploadDir, basePath);
const rel = path.relative(userUploadDir, filepath);
if (rel.startsWith('..') || path.isAbsolute(rel) || rel.includes(`..${path.sep}`)) {
throw new Error(`Invalid file path: ${file.filepath}`);
}
await fs.promises.unlink(filepath); await fs.promises.unlink(filepath);
return; return;
} }

View file

@ -135,10 +135,6 @@ function Avatar({
formData.append('file', input, input.name); formData.append('file', input, input.name);
formData.append('agent_id', createMutation.data.id); formData.append('agent_id', createMutation.data.id);
if (typeof createMutation.data.avatar === 'object') {
formData.append('avatar', JSON.stringify(createMutation.data.avatar));
}
uploadAvatar({ uploadAvatar({
agent_id: createMutation.data.id, agent_id: createMutation.data.id,
postCreation: true, postCreation: true,

View file

@ -68,7 +68,7 @@ function Avatar({
setInput(null); setInput(null);
setPreviewUrl(data.metadata?.avatar as string | null); setPreviewUrl(data.metadata?.avatar as string | null);
const res = queryClient.getQueryData<AssistantListResponse>([ const res = queryClient.getQueryData<AssistantListResponse | undefined>([
QueryKeys.assistants, QueryKeys.assistants,
endpoint, endpoint,
defaultOrderQuery, defaultOrderQuery,
@ -78,16 +78,15 @@ function Avatar({
return; return;
} }
const assistants = const assistants = res.data.map((assistant) => {
res.data.map((assistant) => { if (assistant.id === assistant_id) {
if (assistant.id === assistant_id) { return {
return { ...assistant,
...assistant, ...data,
...data, };
}; }
} return assistant;
return assistant; });
}) ?? [];
queryClient.setQueryData<AssistantListResponse>( queryClient.setQueryData<AssistantListResponse>(
[QueryKeys.assistants, endpoint, defaultOrderQuery], [QueryKeys.assistants, endpoint, defaultOrderQuery],
@ -149,10 +148,6 @@ function Avatar({
formData.append('file', input, input.name); formData.append('file', input, input.name);
formData.append('assistant_id', createMutation.data.id); formData.append('assistant_id', createMutation.data.id);
if (typeof createMutation.data.metadata === 'object') {
formData.append('metadata', JSON.stringify(createMutation.data.metadata));
}
uploadAvatar({ uploadAvatar({
assistant_id: createMutation.data.id, assistant_id: createMutation.data.id,
model: activeModel, model: activeModel,
@ -195,10 +190,6 @@ function Avatar({
formData.append('file', file, file.name); formData.append('file', file, file.name);
formData.append('assistant_id', assistant_id); formData.append('assistant_id', assistant_id);
if (typeof metadata === 'object') {
formData.append('metadata', JSON.stringify(metadata));
}
uploadAvatar({ uploadAvatar({
assistant_id, assistant_id,
model: activeModel, model: activeModel,