mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-23 20:00:15 +01:00
⬆️ feat: Cancel chat file uploads; fix: Assistant uploads (#4433)
* refactor: move file mutations to dedicated file, improve typing * refactor(ChatForm): utilize FileFormWrapper to consolidate file upload logic/rendering to single parent * refactor: better TSX heirarchies between AttachFile and FileFormWrapper * refactor: `abortUpload` WIP * fix: file debugging and file upload issues * refactor: reject promise outright if axios intercepted error does not include response property * chore: bump data-provider version to 0.7.428 * refactor: Add return type to localize function in Translation.ts * refactor: allow message file attachment upload request cancellations, and add localizations for file upload errors * refactor: include Azure OpenAI in paramEndpoints set * fix: assistant form uploads and better typing * refactor: consolidate logic
This commit is contained in:
parent
0870acd086
commit
65888c274a
20 changed files with 419 additions and 311 deletions
|
|
@ -1,37 +1,20 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
EModelEndpoint,
|
||||
supportsFiles,
|
||||
fileConfig as defaultFileConfig,
|
||||
mergeFileConfig,
|
||||
} from 'librechat-data-provider';
|
||||
import { FileUpload, TooltipAnchor } from '~/components/ui';
|
||||
import { useFileHandling, useLocalize } from '~/hooks';
|
||||
import { useGetFileConfig } from '~/data-provider';
|
||||
import { AttachmentIcon } from '~/components/svg';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
const AttachFile = ({
|
||||
endpoint,
|
||||
endpointType,
|
||||
isRTL,
|
||||
disabled = false,
|
||||
disabled,
|
||||
handleFileChange,
|
||||
}: {
|
||||
endpoint: EModelEndpoint | '';
|
||||
endpointType?: EModelEndpoint;
|
||||
isRTL: boolean;
|
||||
disabled?: boolean | null;
|
||||
handleFileChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
}) => {
|
||||
const localize = useLocalize();
|
||||
const { handleFileChange } = useFileHandling();
|
||||
const { data: fileConfig = defaultFileConfig } = useGetFileConfig({
|
||||
select: (data) => mergeFileConfig(data),
|
||||
});
|
||||
const endpointFileConfig = fileConfig.endpoints[endpoint ?? ''];
|
||||
|
||||
if (!supportsFiles[endpointType ?? endpoint ?? ''] || endpointFileConfig?.disabled) {
|
||||
return null;
|
||||
}
|
||||
const isUploadDisabled = disabled ?? false;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -45,8 +28,8 @@ const AttachFile = ({
|
|||
<FileUpload handleFileChange={handleFileChange} className="flex">
|
||||
<TooltipAnchor
|
||||
id="audio-recorder"
|
||||
disabled={isUploadDisabled}
|
||||
aria-label={localize('com_sidepanel_attach_files')}
|
||||
disabled={!!disabled}
|
||||
className="btn relative text-black focus:outline-none focus:ring-2 focus:ring-border-xheavy focus:ring-opacity-50 dark:text-white"
|
||||
style={{ padding: 0 }}
|
||||
description={localize('com_sidepanel_attach_files')}
|
||||
|
|
|
|||
62
client/src/components/Chat/Input/Files/FileFormWrapper.tsx
Normal file
62
client/src/components/Chat/Input/Files/FileFormWrapper.tsx
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import { memo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import {
|
||||
supportsFiles,
|
||||
mergeFileConfig,
|
||||
EndpointFileConfig,
|
||||
fileConfig as defaultFileConfig,
|
||||
} from 'librechat-data-provider';
|
||||
import { useGetFileConfig } from '~/data-provider';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import { useFileHandling } from '~/hooks';
|
||||
import AttachFile from './AttachFile';
|
||||
import FileRow from './FileRow';
|
||||
import store from '~/store';
|
||||
|
||||
function FileFormWrapper({ children, disableInputs } : {
|
||||
disableInputs: boolean;
|
||||
children?: React.ReactNode;
|
||||
}) {
|
||||
const { handleFileChange, abortUpload } = useFileHandling();
|
||||
const chatDirection = useRecoilValue(store.chatDirection).toLowerCase();
|
||||
|
||||
const {
|
||||
files,
|
||||
setFiles,
|
||||
conversation,
|
||||
setFilesLoading,
|
||||
} = useChatContext();
|
||||
const { data: fileConfig = defaultFileConfig } = useGetFileConfig({
|
||||
select: (data) => mergeFileConfig(data),
|
||||
});
|
||||
|
||||
const isRTL = chatDirection === 'rtl';
|
||||
|
||||
const { endpoint: _endpoint, endpointType } = conversation ?? { endpoint: null };
|
||||
const endpointFileConfig = fileConfig.endpoints[_endpoint ?? ''] as EndpointFileConfig | undefined;
|
||||
const endpointSupportsFiles: boolean = supportsFiles[endpointType ?? _endpoint ?? ''] ?? false;
|
||||
const isUploadDisabled = (disableInputs || endpointFileConfig?.disabled) ?? false;
|
||||
|
||||
return (<>
|
||||
<FileRow
|
||||
files={files}
|
||||
setFiles={setFiles}
|
||||
abortUpload={abortUpload}
|
||||
setFilesLoading={setFilesLoading}
|
||||
isRTL={isRTL}
|
||||
Wrapper={({ children }) => (
|
||||
<div className="mx-2 mt-2 flex flex-wrap gap-2 px-2.5 md:pl-0 md:pr-4">
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
{children}
|
||||
{endpointSupportsFiles && !isUploadDisabled && <AttachFile
|
||||
isRTL={isRTL}
|
||||
disabled={disableInputs}
|
||||
handleFileChange={handleFileChange}
|
||||
/>}
|
||||
</>);
|
||||
}
|
||||
|
||||
export default memo(FileFormWrapper);
|
||||
|
|
@ -4,11 +4,13 @@ import type { ExtendedFile } from '~/common';
|
|||
import { useDeleteFilesMutation } from '~/data-provider';
|
||||
import { useFileDeletion } from '~/hooks/Files';
|
||||
import FileContainer from './FileContainer';
|
||||
import { logger } from '~/utils';
|
||||
import Image from './Image';
|
||||
|
||||
export default function FileRow({
|
||||
files: _files,
|
||||
setFiles,
|
||||
abortUpload,
|
||||
setFilesLoading,
|
||||
assistant_id,
|
||||
agent_id,
|
||||
|
|
@ -18,6 +20,7 @@ export default function FileRow({
|
|||
Wrapper,
|
||||
}: {
|
||||
files: Map<string, ExtendedFile> | undefined;
|
||||
abortUpload?: () => void;
|
||||
setFiles: React.Dispatch<React.SetStateAction<Map<string, ExtendedFile>>>;
|
||||
setFilesLoading: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
fileFilter?: (file: ExtendedFile) => boolean;
|
||||
|
|
@ -33,7 +36,8 @@ export default function FileRow({
|
|||
|
||||
const { mutateAsync } = useDeleteFilesMutation({
|
||||
onMutate: async () =>
|
||||
console.log(
|
||||
logger.log(
|
||||
'agents',
|
||||
'Deleting files: agent_id, assistant_id, tool_resource',
|
||||
agent_id,
|
||||
assistant_id,
|
||||
|
|
@ -86,7 +90,12 @@ export default function FileRow({
|
|||
{ map: new Map(), uniqueFiles: [] as ExtendedFile[] },
|
||||
)
|
||||
.uniqueFiles.map((file: ExtendedFile, index: number) => {
|
||||
const handleDelete = () => deleteFile({ file, setFiles });
|
||||
const handleDelete = () => {
|
||||
if (abortUpload && file.progress < 1) {
|
||||
abortUpload();
|
||||
}
|
||||
deleteFile({ file, setFiles });
|
||||
};
|
||||
const isImage = file.type?.startsWith('image') ?? false;
|
||||
if (isImage) {
|
||||
return (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue