mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-21 02:40:14 +01:00
🛠️ refactor: Handle .webp, Improve File Life Cycle 📁 (#1213)
* fix: handle webp images correctly * refactor: use the userPath from the start of the filecycle to avoid handling the blob, whose loading may fail upon user request * refactor: delete temp files on reload and new chat
This commit is contained in:
parent
650759306d
commit
cc39074e0a
15 changed files with 160 additions and 66 deletions
|
|
@ -29,4 +29,5 @@ export { default as useMessageHandler } from './useMessageHandler';
|
|||
export { default as useOriginNavigate } from './useOriginNavigate';
|
||||
export { default as useNavigateToConvo } from './useNavigateToConvo';
|
||||
export { default as useSetIndexOptions } from './useSetIndexOptions';
|
||||
export { default as useSetFilesToDelete } from './useSetFilesToDelete';
|
||||
export { default as useGenerationsByLatest } from './useGenerationsByLatest';
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ import type {
|
|||
TConversation,
|
||||
TGetConversationsResponse,
|
||||
} from 'librechat-data-provider';
|
||||
import type { TAskFunction, ExtendedFile } from '~/common';
|
||||
import type { TAskFunction } from '~/common';
|
||||
import useSetFilesToDelete from './useSetFilesToDelete';
|
||||
import { useAuthContext } from './AuthContext';
|
||||
import useNewConvo from './useNewConvo';
|
||||
import useUserKey from './useUserKey';
|
||||
|
|
@ -23,8 +24,9 @@ import store from '~/store';
|
|||
|
||||
// this to be set somewhere else
|
||||
export default function useChatHelpers(index = 0, paramId: string | undefined) {
|
||||
const [files, setFiles] = useState(new Map<string, ExtendedFile>());
|
||||
const [files, setFiles] = useRecoilState(store.filesByIndex(index));
|
||||
const [filesLoading, setFilesLoading] = useState(false);
|
||||
const setFilesToDelete = useSetFilesToDelete();
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const { isAuthenticated } = useAuthContext();
|
||||
|
|
@ -190,6 +192,7 @@ export default function useChatHelpers(index = 0, paramId: string | undefined) {
|
|||
if (reuseFiles && parentMessage.files?.length) {
|
||||
currentMsg.files = parentMessage.files;
|
||||
setFiles(new Map());
|
||||
setFilesToDelete({});
|
||||
} else if (files.size > 0) {
|
||||
currentMsg.files = Array.from(files.values()).map((file) => ({
|
||||
file_id: file.file_id,
|
||||
|
|
@ -199,6 +202,7 @@ export default function useChatHelpers(index = 0, paramId: string | undefined) {
|
|||
width: file.width,
|
||||
}));
|
||||
setFiles(new Map());
|
||||
setFilesToDelete({});
|
||||
}
|
||||
|
||||
// construct the placeholder response message
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import type { ExtendedFile } from '~/common';
|
|||
import { useToastContext } from '~/Providers/ToastContext';
|
||||
import { useChatContext } from '~/Providers/ChatContext';
|
||||
import { useUploadImageMutation } from '~/data-provider';
|
||||
import useSetFilesToDelete from './useSetFilesToDelete';
|
||||
import { NotificationSeverity } from '~/common';
|
||||
|
||||
const sizeMB = 20;
|
||||
|
|
@ -19,6 +20,7 @@ const useFileHandling = () => {
|
|||
const [errors, setErrors] = useState<string[]>([]);
|
||||
const setError = (error: string) => setErrors((prevErrors) => [...prevErrors, error]);
|
||||
const { files, setFiles, setFilesLoading } = useChatContext();
|
||||
const setFilesToDelete = useSetFilesToDelete();
|
||||
|
||||
const displayToast = useCallback(() => {
|
||||
if (errors.length > 1) {
|
||||
|
|
@ -82,6 +84,11 @@ const useFileHandling = () => {
|
|||
}
|
||||
updatedFiles.set(fileId, { ...currentFile, ...updates });
|
||||
|
||||
if (updates['filepath'] && updates['progress'] !== 1) {
|
||||
const files = Object.fromEntries(updatedFiles);
|
||||
setFilesToDelete(files);
|
||||
}
|
||||
|
||||
return updatedFiles;
|
||||
});
|
||||
};
|
||||
|
|
@ -94,6 +101,9 @@ const useFileHandling = () => {
|
|||
} else {
|
||||
console.warn(`File with id ${fileId} not found.`);
|
||||
}
|
||||
|
||||
const files = Object.fromEntries(updatedFiles);
|
||||
setFilesToDelete(files);
|
||||
return updatedFiles;
|
||||
});
|
||||
};
|
||||
|
|
@ -107,14 +117,11 @@ const useFileHandling = () => {
|
|||
});
|
||||
|
||||
setTimeout(() => {
|
||||
const file = files.get(data.temp_file_id);
|
||||
updateFileById(data.temp_file_id, {
|
||||
progress: 1,
|
||||
file_id: data.file_id,
|
||||
temp_file_id: data.temp_file_id,
|
||||
filepath: data.filepath,
|
||||
// filepath: file?.preview,
|
||||
preview: file?.preview,
|
||||
type: data.type,
|
||||
height: data.height,
|
||||
width: data.width,
|
||||
|
|
@ -231,8 +238,7 @@ const useFileHandling = () => {
|
|||
replaceFile(extendedFile);
|
||||
|
||||
await uploadFile(extendedFile);
|
||||
// This gets cleaned up in the Image component, after receiving the server image
|
||||
// URL.revokeObjectURL(preview);
|
||||
URL.revokeObjectURL(preview);
|
||||
};
|
||||
img.src = preview;
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { useCallback } from 'react';
|
||||
import { useSetRecoilState, useResetRecoilState, useRecoilCallback } from 'recoil';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider';
|
||||
import { useSetRecoilState, useResetRecoilState, useRecoilCallback, useRecoilState } from 'recoil';
|
||||
import type { TConversation, TSubmission, TPreset, TModelsConfig } from 'librechat-data-provider';
|
||||
import { buildDefaultConvo, getDefaultEndpoint } from '~/utils';
|
||||
import { useDeleteFilesMutation } from '~/data-provider';
|
||||
import useOriginNavigate from './useOriginNavigate';
|
||||
import useSetStorage from './useSetStorage';
|
||||
import store from '~/store';
|
||||
|
|
@ -10,12 +11,21 @@ import store from '~/store';
|
|||
const useNewConvo = (index = 0) => {
|
||||
const setStorage = useSetStorage();
|
||||
const navigate = useOriginNavigate();
|
||||
// const setConversation = useSetRecoilState(store.conversationByIndex(index));
|
||||
const { setConversation } = store.useCreateConversationAtom(index);
|
||||
const [files, setFiles] = useRecoilState(store.filesByIndex(index));
|
||||
const setSubmission = useSetRecoilState<TSubmission | null>(store.submissionByIndex(index));
|
||||
const resetLatestMessage = useResetRecoilState(store.latestMessageFamily(index));
|
||||
const { data: endpointsConfig = {} } = useGetEndpointsQuery();
|
||||
|
||||
const { mutateAsync } = useDeleteFilesMutation({
|
||||
onSuccess: () => {
|
||||
console.log('Files deleted');
|
||||
},
|
||||
onError: (error) => {
|
||||
console.log('Error deleting files:', error);
|
||||
},
|
||||
});
|
||||
|
||||
const switchToConversation = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async (
|
||||
|
|
@ -66,21 +76,34 @@ const useNewConvo = (index = 0) => {
|
|||
modelsData?: TModelsConfig;
|
||||
buildDefault?: boolean;
|
||||
} = {}) => {
|
||||
switchToConversation(
|
||||
{
|
||||
conversationId: 'new',
|
||||
title: 'New Chat',
|
||||
endpoint: null,
|
||||
...template,
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
},
|
||||
preset,
|
||||
modelsData,
|
||||
buildDefault,
|
||||
);
|
||||
const conversation = {
|
||||
conversationId: 'new',
|
||||
title: 'New Chat',
|
||||
endpoint: null,
|
||||
...template,
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
};
|
||||
|
||||
if (conversation.conversationId === 'new' && !modelsData) {
|
||||
const filesToDelete = Array.from(files.values())
|
||||
.filter((file) => file.filepath)
|
||||
.map((file) => ({
|
||||
file_id: file.file_id,
|
||||
filepath: file.filepath as string,
|
||||
}));
|
||||
|
||||
setFiles(new Map());
|
||||
localStorage.setItem('filesToDelete', JSON.stringify({}));
|
||||
|
||||
if (filesToDelete.length > 0) {
|
||||
mutateAsync({ files: filesToDelete });
|
||||
}
|
||||
}
|
||||
|
||||
switchToConversation(conversation, preset, modelsData, buildDefault);
|
||||
},
|
||||
[switchToConversation],
|
||||
[switchToConversation, files, mutateAsync, setFiles],
|
||||
);
|
||||
|
||||
return {
|
||||
|
|
|
|||
5
client/src/hooks/useSetFilesToDelete.ts
Normal file
5
client/src/hooks/useSetFilesToDelete.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export default function useSetFilesToDelete() {
|
||||
const setFilesToDelete = (files: Record<string, unknown>) =>
|
||||
localStorage.setItem('filesToDelete', JSON.stringify(files));
|
||||
return setFilesToDelete;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue