| import React, { useMemo } from 'react'; |
| import { useRecoilValue } from 'recoil'; |
| import { OGDialog, OGDialogTemplate } from '@librechat/client'; |
| import { |
| inferMimeType, |
| EToolResources, |
| EModelEndpoint, |
| defaultAgentCapabilities, |
| isDocumentSupportedProvider, |
| } from 'librechat-data-provider'; |
| import { |
| ImageUpIcon, |
| FileSearch, |
| FileType2Icon, |
| FileImageIcon, |
| TerminalSquareIcon, |
| } from 'lucide-react'; |
| import { |
| useAgentToolPermissions, |
| useAgentCapabilities, |
| useGetAgentsConfig, |
| useLocalize, |
| } from '~/hooks'; |
| import { ephemeralAgentByConvoId } from '~/store'; |
| import { useDragDropContext } from '~/Providers'; |
|
|
| interface DragDropModalProps { |
| onOptionSelect: (option: EToolResources | undefined) => void; |
| files: File[]; |
| isVisible: boolean; |
| setShowModal: (showModal: boolean) => void; |
| } |
|
|
| interface FileOption { |
| label: string; |
| value?: EToolResources; |
| icon: React.JSX.Element; |
| condition?: boolean; |
| } |
|
|
| const DragDropModal = ({ onOptionSelect, setShowModal, files, isVisible }: DragDropModalProps) => { |
| const localize = useLocalize(); |
| const { agentsConfig } = useGetAgentsConfig(); |
| |
| |
| |
| |
| const capabilities = useAgentCapabilities(agentsConfig?.capabilities ?? defaultAgentCapabilities); |
| const { conversationId, agentId, endpoint, endpointType } = useDragDropContext(); |
| const ephemeralAgent = useRecoilValue(ephemeralAgentByConvoId(conversationId ?? '')); |
| const { fileSearchAllowedByAgent, codeAllowedByAgent, provider } = useAgentToolPermissions( |
| agentId, |
| ephemeralAgent, |
| ); |
|
|
| const options = useMemo(() => { |
| const _options: FileOption[] = []; |
| const currentProvider = provider || endpoint; |
|
|
| |
| const getFileType = (file: File) => inferMimeType(file.name, file.type); |
|
|
| |
| if (isDocumentSupportedProvider(endpointType) || isDocumentSupportedProvider(currentProvider)) { |
| const isGoogleProvider = currentProvider === EModelEndpoint.google; |
| const validFileTypes = isGoogleProvider |
| ? files.every((file) => { |
| const type = getFileType(file); |
| return ( |
| type?.startsWith('image/') || |
| type?.startsWith('video/') || |
| type?.startsWith('audio/') || |
| type === 'application/pdf' |
| ); |
| }) |
| : files.every((file) => { |
| const type = getFileType(file); |
| return type?.startsWith('image/') || type === 'application/pdf'; |
| }); |
|
|
| _options.push({ |
| label: localize('com_ui_upload_provider'), |
| value: undefined, |
| icon: <FileImageIcon className="icon-md" />, |
| condition: validFileTypes, |
| }); |
| } else { |
| |
| _options.push({ |
| label: localize('com_ui_upload_image_input'), |
| value: undefined, |
| icon: <ImageUpIcon className="icon-md" />, |
| condition: files.every((file) => getFileType(file)?.startsWith('image/')), |
| }); |
| } |
| if (capabilities.fileSearchEnabled && fileSearchAllowedByAgent) { |
| _options.push({ |
| label: localize('com_ui_upload_file_search'), |
| value: EToolResources.file_search, |
| icon: <FileSearch className="icon-md" />, |
| }); |
| } |
| if (capabilities.codeEnabled && codeAllowedByAgent) { |
| _options.push({ |
| label: localize('com_ui_upload_code_files'), |
| value: EToolResources.execute_code, |
| icon: <TerminalSquareIcon className="icon-md" />, |
| }); |
| } |
| if (capabilities.contextEnabled) { |
| _options.push({ |
| label: localize('com_ui_upload_ocr_text'), |
| value: EToolResources.context, |
| icon: <FileType2Icon className="icon-md" />, |
| }); |
| } |
|
|
| return _options; |
| }, [ |
| files, |
| localize, |
| provider, |
| endpoint, |
| endpointType, |
| capabilities, |
| codeAllowedByAgent, |
| fileSearchAllowedByAgent, |
| ]); |
|
|
| if (!isVisible) { |
| return null; |
| } |
|
|
| return ( |
| <OGDialog open={isVisible} onOpenChange={setShowModal}> |
| <OGDialogTemplate |
| title={localize('com_ui_upload_type')} |
| className="w-11/12 sm:w-[440px] md:w-[400px] lg:w-[360px]" |
| main={ |
| <div className="flex flex-col gap-2"> |
| {options.map( |
| (option, index) => |
| option.condition !== false && ( |
| <button |
| key={index} |
| onClick={() => onOptionSelect(option.value)} |
| className="flex items-center gap-2 rounded-lg p-2 hover:bg-surface-active-alt" |
| > |
| {option.icon} |
| <span>{option.label}</span> |
| </button> |
| ), |
| )} |
| </div> |
| } |
| /> |
| </OGDialog> |
| ); |
| }; |
|
|
| export default DragDropModal; |
|
|