🤖 Assistants V2 Support: Part 2

🎹 fix: Autocompletion Chrome Bug on Action API Key Input

chore: remove `useOriginNavigate`

chore: set correct OpenAI Storage Source

fix: azure file deletions, instantiate clients by source for deletion

update code interpret files info

feat: deleteResourceFileId

chore: increase poll interval as azure easily rate limits

fix: openai file deletions, TODO: evaluate rejected deletion settled promises to determine which to delete from db records

file source icons

update table file filters

chore: file search info and versioning

fix: retrieval update with necessary tool_resources if specified

fix(useMentions): add optional chaining in case listMap value is undefined

fix: force assistant avatar roundedness

fix: azure assistants, check correct flag

chore: bump data-provider
This commit is contained in:
Danny Avila 2024-05-18 08:01:02 -04:00
parent 2bdbff5141
commit bc46ccdcad
No known key found for this signature in database
GPG key ID: 2DD9CC89B9B50364
44 changed files with 420 additions and 174 deletions

View file

@ -2,6 +2,7 @@ import type { TFile } from 'librechat-data-provider';
import type { ExtendedFile } from '~/common';
import FileIcon from '~/components/svg/Files/FileIcon';
import ProgressCircle from './ProgressCircle';
import SourceIcon from './SourceIcon';
import { useProgress } from '~/hooks';
import { cn } from '~/utils';
@ -21,7 +22,6 @@ const FilePreview = ({
const radius = 55; // Radius of the SVG circle
const circumference = 2 * Math.PI * radius;
const progress = useProgress(file?.['progress'] ?? 1, 0.001, (file as ExtendedFile)?.size ?? 1);
console.log(progress);
// Calculate the offset based on the loading progress
const offset = circumference - progress * circumference;
@ -32,6 +32,7 @@ const FilePreview = ({
return (
<div className={cn('h-10 w-10 shrink-0 overflow-hidden rounded-md', className)}>
<FileIcon file={file} fileType={fileType} />
<SourceIcon source={file?.source} />
{progress < 1 && (
<ProgressCircle
circumference={circumference}

View file

@ -1,4 +1,5 @@
import { useEffect } from 'react';
import { EToolResources } from 'librechat-data-provider';
import type { ExtendedFile } from '~/common';
import { useDeleteFilesMutation } from '~/data-provider';
import { useFileDeletion } from '~/hooks/Files';
@ -10,6 +11,7 @@ export default function FileRow({
setFiles,
setFilesLoading,
assistant_id,
tool_resource,
fileFilter,
Wrapper,
}: {
@ -18,6 +20,7 @@ export default function FileRow({
setFilesLoading: React.Dispatch<React.SetStateAction<boolean>>;
fileFilter?: (file: ExtendedFile) => boolean;
assistant_id?: string;
tool_resource?: EToolResources;
Wrapper?: React.FC<{ children: React.ReactNode }>;
}) {
const files = Array.from(_files.values()).filter((file) =>
@ -25,7 +28,8 @@ export default function FileRow({
);
const { mutateAsync } = useDeleteFilesMutation({
onMutate: async () => console.log('Deleting files: assistant_id', assistant_id),
onMutate: async () =>
console.log('Deleting files: assistant_id, tool_resource', assistant_id, tool_resource),
onSuccess: () => {
console.log('Files deleted');
},
@ -34,7 +38,7 @@ export default function FileRow({
},
});
const { deleteFile } = useFileDeletion({ mutateAsync, assistant_id });
const { deleteFile } = useFileDeletion({ mutateAsync, assistant_id, tool_resource });
useEffect(() => {
if (!files) {
@ -82,6 +86,7 @@ export default function FileRow({
url={file.preview}
onDelete={handleDelete}
progress={file.progress}
source={file.source}
/>
);
}

View file

@ -12,16 +12,9 @@ export default function Files({ open, onOpenChange }) {
const { data: files = [] } = useGetFiles<TFile[]>({
select: (files) =>
files.map((file) => {
if (file.source === FileSources.local || file.source === FileSources.openai) {
file.context = file.context ?? FileContext.unknown;
return file;
} else {
return {
...file,
context: file.context ?? FileContext.unknown,
source: FileSources.local,
};
}
file.context = file.context ?? FileContext.unknown;
file.filterSource = file.source === FileSources.firebase ? FileSources.local : file.source;
return file;
}),
});

View file

@ -1,3 +1,4 @@
import { FileSources } from 'librechat-data-provider';
import ImagePreview from './ImagePreview';
import RemoveFile from './RemoveFile';
@ -6,16 +7,18 @@ const Image = ({
url,
onDelete,
progress = 1,
source = FileSources.local,
}: {
imageBase64?: string;
url?: string;
onDelete: () => void;
progress: number; // between 0 and 1
source?: FileSources;
}) => {
return (
<div className="group relative inline-block text-sm text-black/70 dark:text-white/90">
<div className="relative overflow-hidden rounded-xl border border-gray-200 dark:border-gray-600">
<ImagePreview imageBase64={imageBase64} url={url} progress={progress} />
<ImagePreview source={source} imageBase64={imageBase64} url={url} progress={progress} />
</div>
<RemoveFile onRemove={onDelete} />
</div>

View file

@ -1,4 +1,6 @@
import { FileSources } from 'librechat-data-provider';
import ProgressCircle from './ProgressCircle';
import SourceIcon from './SourceIcon';
import { cn } from '~/utils';
type styleProps = {
@ -13,11 +15,13 @@ const ImagePreview = ({
url,
progress = 1,
className = '',
source,
}: {
imageBase64?: string;
url?: string;
progress?: number; // between 0 and 1
className?: string;
source?: FileSources;
}) => {
let style: styleProps = {
backgroundSize: 'cover',
@ -65,6 +69,7 @@ const ImagePreview = ({
circleCSSProperties={circleCSSProperties}
/>
)}
<SourceIcon source={source} />
</div>
);
};

View file

@ -0,0 +1,45 @@
import { EModelEndpoint, FileSources } from 'librechat-data-provider';
import { MinimalIcon } from '~/components/Endpoints';
import { cn } from '~/utils';
const sourceToEndpoint = {
[FileSources.openai]: EModelEndpoint.openAI,
[FileSources.azure]: EModelEndpoint.azureOpenAI,
};
const sourceToClassname = {
[FileSources.openai]: 'bg-black/65',
[FileSources.azure]: 'azure-bg-color opacity-85',
};
const defaultClassName =
'absolute right-0 bottom-0 rounded-full p-[0.15rem] text-gray-600 transition-colors';
export default function SourceIcon({
source,
className = defaultClassName,
}: {
source?: FileSources;
className?: string;
}) {
if (source === FileSources.local || source === FileSources.firebase) {
return null;
}
const endpoint = sourceToEndpoint[source ?? ''];
if (!endpoint) {
return null;
}
return (
<button type="button" className={cn(className, sourceToClassname[source ?? ''] ?? '')}>
<span className="flex items-center justify-center">
<MinimalIcon
endpoint={endpoint}
size={14}
isCreatedByUser={false}
iconClassName="h-3 w-3"
/>
</span>
</button>
);
}

View file

@ -7,6 +7,7 @@ import ImagePreview from '~/components/Chat/Input/Files/ImagePreview';
import FilePreview from '~/components/Chat/Input/Files/FilePreview';
import { SortFilterHeader } from './SortFilterHeader';
import { OpenAIMinimalIcon } from '~/components/svg';
import { AzureMinimalIcon } from '~/components/svg';
import { Button, Checkbox } from '~/components/ui';
import { formatDate, getFileType } from '~/utils';
import useLocalize from '~/hooks/useLocalize';
@ -71,10 +72,11 @@ export const columns: ColumnDef<TFile>[] = [
const file = row.original;
if (file.type?.startsWith('image')) {
return (
<div className="flex gap-2 ">
<div className="flex gap-2">
<ImagePreview
url={file.filepath}
className="h-10 w-10 shrink-0 overflow-hidden rounded-md"
className="relative h-10 w-10 shrink-0 overflow-hidden rounded-md"
source={file?.source}
/>
<span className="self-center truncate ">{file.filename}</span>
</div>
@ -84,7 +86,7 @@ export const columns: ColumnDef<TFile>[] = [
const fileType = getFileType(file.type);
return (
<div className="flex gap-2">
{fileType && <FilePreview fileType={fileType} />}
{fileType && <FilePreview fileType={fileType} className="relative" file={file} />}
<span className="self-center truncate">{file.filename}</span>
</div>
);
@ -108,7 +110,7 @@ export const columns: ColumnDef<TFile>[] = [
cell: ({ row }) => formatDate(row.original.updatedAt),
},
{
accessorKey: 'source',
accessorKey: 'filterSource',
header: ({ column }) => {
const localize = useLocalize();
return (
@ -117,10 +119,14 @@ export const columns: ColumnDef<TFile>[] = [
title={localize('com_ui_storage')}
filters={{
Storage: Object.values(FileSources).filter(
(value) => value === FileSources.local || value === FileSources.openai,
(value) =>
value === FileSources.local ||
value === FileSources.openai ||
value === FileSources.azure,
),
}}
valueMap={{
[FileSources.azure]: 'Azure',
[FileSources.openai]: 'OpenAI',
[FileSources.local]: 'com_ui_host',
}}
@ -137,6 +143,13 @@ export const columns: ColumnDef<TFile>[] = [
{'OpenAI'}
</div>
);
} else if (source === FileSources.azure) {
return (
<div className="flex flex-wrap items-center gap-2">
<AzureMinimalIcon className="icon-sm text-cyan-700" />
{'Azure'}
</div>
);
}
return (
<div className="flex flex-wrap items-center gap-2">

View file

@ -48,7 +48,12 @@ const contextMap = {
[FileContext.bytes]: 'com_ui_size',
};
type Style = { width?: number | string; maxWidth?: number | string; minWidth?: number | string };
type Style = {
width?: number | string;
maxWidth?: number | string;
minWidth?: number | string;
zIndex?: number;
};
export default function DataTable<TData, TValue>({ columns, data }: DataTableProps<TData, TValue>) {
const localize = useLocalize();
@ -142,7 +147,7 @@ export default function DataTable<TData, TValue>({ columns, data }: DataTablePro
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header, index) => {
const style: Style = { maxWidth: '32px', minWidth: '125px' };
const style: Style = { maxWidth: '32px', minWidth: '125px', zIndex: 50 };
if (header.id === 'filename') {
style.maxWidth = '50%';
style.width = '50%';