mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-22 08:12:00 +02:00
🖼️ 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:
parent
ec922986a9
commit
ebe3e7f796
5 changed files with 37 additions and 35 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue