mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
⚙️ fix: File Config Handling (#4664)
* chore: typing * refactor: create file filter from custom fileConfig, if provided * refactor: use logger utility to avoid overly verbose axios error logs when using RAG_API * fix(useFileHandling): use memoization/callbacks to make sure the appropriate fileConfig is used; refactor: move endpoint to first field applied to formdata * chore: update librechat-data-provider version to 0.7.54 * chore: revert type change
This commit is contained in:
parent
d60a0af878
commit
49ee88b6e8
5 changed files with 123 additions and 82 deletions
|
|
@ -30,21 +30,41 @@ const importFileFilter = (req, file, cb) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {import('librechat-data-provider').FileConfig | undefined} customFileConfig
|
||||||
|
*/
|
||||||
|
const createFileFilter = (customFileConfig) => {
|
||||||
|
/**
|
||||||
|
* @param {ServerRequest} req
|
||||||
|
* @param {Express.Multer.File}
|
||||||
|
* @param {import('multer').FileFilterCallback} cb
|
||||||
|
*/
|
||||||
const fileFilter = (req, file, cb) => {
|
const fileFilter = (req, file, cb) => {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return cb(new Error('No file provided'), false);
|
return cb(new Error('No file provided'), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defaultFileConfig.checkType(file.mimetype)) {
|
const endpoint = req.body.endpoint;
|
||||||
|
const supportedTypes =
|
||||||
|
customFileConfig?.endpoints?.[endpoint]?.supportedMimeTypes ??
|
||||||
|
customFileConfig?.endpoints?.default.supportedMimeTypes ??
|
||||||
|
defaultFileConfig?.endpoints?.[endpoint]?.supportedMimeTypes;
|
||||||
|
|
||||||
|
if (!defaultFileConfig.checkType(file.mimetype, supportedTypes)) {
|
||||||
return cb(new Error('Unsupported file type: ' + file.mimetype), false);
|
return cb(new Error('Unsupported file type: ' + file.mimetype), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
cb(null, true);
|
cb(null, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return fileFilter;
|
||||||
|
};
|
||||||
|
|
||||||
const createMulterInstance = async () => {
|
const createMulterInstance = async () => {
|
||||||
const customConfig = await getCustomConfig();
|
const customConfig = await getCustomConfig();
|
||||||
const fileConfig = mergeFileConfig(customConfig?.fileConfig);
|
const fileConfig = mergeFileConfig(customConfig?.fileConfig);
|
||||||
|
const fileFilter = createFileFilter(fileConfig);
|
||||||
return multer({
|
return multer({
|
||||||
storage,
|
storage,
|
||||||
fileFilter,
|
fileFilter,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ const fs = require('fs');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const FormData = require('form-data');
|
const FormData = require('form-data');
|
||||||
const { FileSources } = require('librechat-data-provider');
|
const { FileSources } = require('librechat-data-provider');
|
||||||
|
const { logAxiosError } = require('~/utils');
|
||||||
const { logger } = require('~/config');
|
const { logger } = require('~/config');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -32,7 +33,10 @@ const deleteVectors = async (req, file) => {
|
||||||
data: [file.file_id],
|
data: [file.file_id],
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error deleting vectors', error);
|
logAxiosError({
|
||||||
|
error,
|
||||||
|
message: 'Error deleting vectors',
|
||||||
|
});
|
||||||
throw new Error(error.message || 'An error occurred during file deletion.');
|
throw new Error(error.message || 'An error occurred during file deletion.');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -91,7 +95,10 @@ async function uploadVectors({ req, file, file_id }) {
|
||||||
embedded: Boolean(responseData.known_type),
|
embedded: Boolean(responseData.known_type),
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error embedding file', error);
|
logAxiosError({
|
||||||
|
error,
|
||||||
|
message: 'Error uploading vectors',
|
||||||
|
});
|
||||||
throw new Error(error.message || 'An error occurred during file upload.');
|
throw new Error(error.message || 'An error occurred during file upload.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
megabyte,
|
megabyte,
|
||||||
QueryKeys,
|
QueryKeys,
|
||||||
|
|
@ -47,14 +47,24 @@ const useFileHandling = (params?: UseFileHandling) => {
|
||||||
const agent_id = params?.additionalMetadata?.agent_id ?? '';
|
const agent_id = params?.additionalMetadata?.agent_id ?? '';
|
||||||
const assistant_id = params?.additionalMetadata?.assistant_id ?? '';
|
const assistant_id = params?.additionalMetadata?.assistant_id ?? '';
|
||||||
|
|
||||||
const { data: fileConfig = defaultFileConfig } = useGetFileConfig({
|
const { data: fileConfig = null } = useGetFileConfig({
|
||||||
select: (data) => mergeFileConfig(data),
|
select: (data) => mergeFileConfig(data),
|
||||||
});
|
});
|
||||||
const endpoint =
|
|
||||||
params?.overrideEndpoint ?? conversation?.endpointType ?? conversation?.endpoint ?? 'default';
|
|
||||||
|
|
||||||
const { fileLimit, fileSizeLimit, totalSizeLimit, supportedMimeTypes } =
|
const endpoint = useMemo(
|
||||||
fileConfig.endpoints[endpoint] ?? fileConfig.endpoints.default;
|
() =>
|
||||||
|
params?.overrideEndpoint ?? conversation?.endpointType ?? conversation?.endpoint ?? 'default',
|
||||||
|
[params?.overrideEndpoint, conversation?.endpointType, conversation?.endpoint],
|
||||||
|
);
|
||||||
|
|
||||||
|
const { fileLimit, fileSizeLimit, totalSizeLimit, supportedMimeTypes } = useMemo(
|
||||||
|
() =>
|
||||||
|
fileConfig?.endpoints[endpoint] ??
|
||||||
|
fileConfig?.endpoints.default ??
|
||||||
|
defaultFileConfig.endpoints[endpoint] ??
|
||||||
|
defaultFileConfig.endpoints.default,
|
||||||
|
[fileConfig, endpoint],
|
||||||
|
);
|
||||||
|
|
||||||
const displayToast = useCallback(() => {
|
const displayToast = useCallback(() => {
|
||||||
if (errors.length > 1) {
|
if (errors.length > 1) {
|
||||||
|
|
@ -146,6 +156,7 @@ const useFileHandling = (params?: UseFileHandling) => {
|
||||||
startUploadTimer(extendedFile.file_id, filename, extendedFile.size);
|
startUploadTimer(extendedFile.file_id, filename, extendedFile.size);
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
formData.append('endpoint', endpoint);
|
||||||
formData.append('file', extendedFile.file as File, encodeURIComponent(filename));
|
formData.append('file', extendedFile.file as File, encodeURIComponent(filename));
|
||||||
formData.append('file_id', extendedFile.file_id);
|
formData.append('file_id', extendedFile.file_id);
|
||||||
|
|
||||||
|
|
@ -167,8 +178,6 @@ const useFileHandling = (params?: UseFileHandling) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formData.append('endpoint', endpoint);
|
|
||||||
|
|
||||||
if (!isAssistantsEndpoint(endpoint)) {
|
if (!isAssistantsEndpoint(endpoint)) {
|
||||||
uploadFile.mutate(formData);
|
uploadFile.mutate(formData);
|
||||||
return;
|
return;
|
||||||
|
|
@ -203,7 +212,8 @@ const useFileHandling = (params?: UseFileHandling) => {
|
||||||
uploadFile.mutate(formData);
|
uploadFile.mutate(formData);
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateFiles = (fileList: File[]) => {
|
const validateFiles = useCallback(
|
||||||
|
(fileList: File[]) => {
|
||||||
const existingFiles = Array.from(files.values());
|
const existingFiles = Array.from(files.values());
|
||||||
const incomingTotalSize = fileList.reduce((total, file) => total + file.size, 0);
|
const incomingTotalSize = fileList.reduce((total, file) => total + file.size, 0);
|
||||||
if (incomingTotalSize === 0) {
|
if (incomingTotalSize === 0) {
|
||||||
|
|
@ -261,7 +271,9 @@ const useFileHandling = (params?: UseFileHandling) => {
|
||||||
const combinedFilesInfo = [
|
const combinedFilesInfo = [
|
||||||
...existingFiles.map(
|
...existingFiles.map(
|
||||||
(file) =>
|
(file) =>
|
||||||
`${file.file?.name ?? file.filename}-${file.size}-${file.type?.split('/')[0] ?? 'file'}`,
|
`${file.file?.name ?? file.filename}-${file.size}-${
|
||||||
|
file.type?.split('/')[0] ?? 'file'
|
||||||
|
}`,
|
||||||
),
|
),
|
||||||
...fileList.map(
|
...fileList.map(
|
||||||
(file: File | undefined) =>
|
(file: File | undefined) =>
|
||||||
|
|
@ -277,7 +289,9 @@ const useFileHandling = (params?: UseFileHandling) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
},
|
||||||
|
[files, fileLimit, fileSizeLimit, totalSizeLimit, supportedMimeTypes],
|
||||||
|
);
|
||||||
|
|
||||||
const loadImage = (extendedFile: ExtendedFile, preview: string) => {
|
const loadImage = (extendedFile: ExtendedFile, preview: string) => {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
|
|
|
||||||
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -36283,7 +36283,7 @@
|
||||||
},
|
},
|
||||||
"packages/data-provider": {
|
"packages/data-provider": {
|
||||||
"name": "librechat-data-provider",
|
"name": "librechat-data-provider",
|
||||||
"version": "0.7.53",
|
"version": "0.7.54",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "librechat-data-provider",
|
"name": "librechat-data-provider",
|
||||||
"version": "0.7.53",
|
"version": "0.7.54",
|
||||||
"description": "data services for librechat apps",
|
"description": "data services for librechat apps",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"module": "dist/index.es.js",
|
"module": "dist/index.es.js",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue