diff --git a/web/app/components/base/file-uploader/constants.ts b/web/app/components/base/file-uploader/constants.ts index f738121363..e6cc2995f9 100644 --- a/web/app/components/base/file-uploader/constants.ts +++ b/web/app/components/base/file-uploader/constants.ts @@ -1,2 +1,3 @@ export const FILE_SIZE_LIMIT = 15 * 1024 * 1024 + export const FILE_URL_REGEX = /^(https?|ftp):\/\// diff --git a/web/app/components/base/file-uploader/file-uploader-in-attachment/file-item.tsx b/web/app/components/base/file-uploader/file-uploader-in-attachment/file-item.tsx index d125514db3..45d57267aa 100644 --- a/web/app/components/base/file-uploader/file-uploader-in-attachment/file-item.tsx +++ b/web/app/components/base/file-uploader/file-uploader-in-attachment/file-item.tsx @@ -31,8 +31,8 @@ const FileInAttachmentItem = ({ onRemove, onReUpload, }: FileInAttachmentItemProps) => { - const { id, name, progress, supportFileType, base64Url, url } = file - const ext = getFileExtension(name) + const { id, name, type, progress, supportFileType, base64Url, url } = file + const ext = getFileExtension(name, type) const isImageFile = supportFileType === SupportUploadFileTypes.image return ( @@ -52,7 +52,7 @@ const FileInAttachmentItem = ({ { !isImageFile && ( ) diff --git a/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-item.tsx b/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-item.tsx index 4c35f65abc..f8c5b13474 100644 --- a/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-item.tsx +++ b/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-item.tsx @@ -29,8 +29,8 @@ const FileItem = ({ onRemove, onReUpload, }: FileItemProps) => { - const { id, name, progress } = file - const ext = getFileExtension(name) + const { id, name, type, progress } = file + const ext = getFileExtension(name, type) const uploadError = progress === -1 return ( @@ -59,7 +59,7 @@ const FileItem = ({
{ diff --git a/web/app/components/base/file-uploader/hooks.ts b/web/app/components/base/file-uploader/hooks.ts index 31a0fdbee6..5e126a87b5 100644 --- a/web/app/components/base/file-uploader/hooks.ts +++ b/web/app/components/base/file-uploader/hooks.ts @@ -11,7 +11,6 @@ import type { FileEntity } from './types' import { useFileStore } from './store' import { fileUpload, - getFileNameFromUrl, getSupportFileType, isAllowedFileExtension, } from './utils' @@ -97,16 +96,15 @@ export const useFile = (fileConfig: FileUpload) => { const handleLoadFileFromLink = useCallback((url: string) => { const allowedFileTypes = fileConfig.allowed_file_types - const fileName = getFileNameFromUrl(url) const uploadingFile = { id: uuid4(), - name: fileName, + name: url, type: '', size: 0, progress: 0, transferMethod: TransferMethod.remote_url, - supportFileType: getSupportFileType(fileName, allowedFileTypes?.includes(SupportUploadFileTypes.custom)), + supportFileType: '', url, } handleAddFile(uploadingFile) @@ -117,6 +115,7 @@ export const useFile = (fileConfig: FileUpload) => { type: res.file_type, size: res.file_length, progress: 100, + supportFileType: getSupportFileType(url, res.file_type, allowedFileTypes?.includes(SupportUploadFileTypes.custom)), } handleUpdateFile(newFile) }).catch(() => { @@ -137,7 +136,7 @@ export const useFile = (fileConfig: FileUpload) => { }, [fileStore]) const handleLocalFileUpload = useCallback((file: File) => { - if (!isAllowedFileExtension(file.name, fileConfig.allowed_file_types || [], fileConfig.allowed_file_extensions || [])) { + if (!isAllowedFileExtension(file.name, file.type, fileConfig.allowed_file_types || [], fileConfig.allowed_file_extensions || [])) { notify({ type: 'error', message: t('common.fileUploader.fileExtensionNotSupport') }) return } @@ -159,7 +158,7 @@ export const useFile = (fileConfig: FileUpload) => { size: file.size, progress: 0, transferMethod: TransferMethod.local_file, - supportFileType: getSupportFileType(file.name, allowedFileTypes?.includes(SupportUploadFileTypes.custom)), + supportFileType: getSupportFileType(file.name, file.type, allowedFileTypes?.includes(SupportUploadFileTypes.custom)), originalFile: file, base64Url: isImage ? reader.result as string : '', } diff --git a/web/app/components/base/file-uploader/utils.ts b/web/app/components/base/file-uploader/utils.ts index 78ca453073..d2e3493ce2 100644 --- a/web/app/components/base/file-uploader/utils.ts +++ b/web/app/components/base/file-uploader/utils.ts @@ -1,3 +1,4 @@ +import mime from 'mime' import { FileAppearanceTypeEnum } from './types' import type { FileEntity } from './types' import { upload } from '@/service/base' @@ -39,43 +40,65 @@ export const fileUpload: FileUpload = ({ }) } -export const getFileAppearanceType = (fileType: string) => { - if (!fileType) - return FileAppearanceTypeEnum.custom +export const getFileExtension = (fileName: string, fileMimetype: string) => { + if (fileMimetype) + return mime.getExtension(fileMimetype) || '' - if (fileType.includes('image')) - return FileAppearanceTypeEnum.image + if (fileName) { + const fileNamePair = fileName.split('.') + const fileNamePairLength = fileNamePair.length - if (fileType.includes('video')) - return FileAppearanceTypeEnum.video - - if (fileType.includes('audio')) - return FileAppearanceTypeEnum.audio - - if (fileType.includes('pdf')) - return FileAppearanceTypeEnum.pdf - - return FileAppearanceTypeEnum.custom -} - -export const getFileExtension = (fileName: string) => { - if (!fileName) - return '' - - const fileNamePair = fileName.split('.') - const fileNamePairLength = fileNamePair.length - - if (fileNamePairLength > 1) - return fileNamePair[fileNamePairLength - 1] + if (fileNamePairLength > 1) + return fileNamePair[fileNamePairLength - 1] + } return '' } -export const getSupportFileType = (fileName: string, isCustom?: boolean) => { +export const getFileAppearanceType = (fileName: string, fileMimetype: string) => { + const extension = getFileExtension(fileName, fileMimetype) + + if (extension === 'gif') + return FileAppearanceTypeEnum.gif + + if (FILE_EXTS.image.includes(extension.toUpperCase())) + return FileAppearanceTypeEnum.image + + if (FILE_EXTS.video.includes(extension.toUpperCase())) + return FileAppearanceTypeEnum.video + + if (FILE_EXTS.audio.includes(extension.toUpperCase())) + return FileAppearanceTypeEnum.audio + + if (extension === 'html') + return FileAppearanceTypeEnum.code + + if (extension === 'pdf') + return FileAppearanceTypeEnum.pdf + + if (extension === 'md' || extension === 'markdown') + return FileAppearanceTypeEnum.markdown + + if (extension === 'xlsx' || extension === 'xls') + return FileAppearanceTypeEnum.excel + + if (extension === 'docx' || extension === 'doc') + return FileAppearanceTypeEnum.word + + if (extension === 'pptx' || extension === 'ppt') + return FileAppearanceTypeEnum.ppt + + if (FILE_EXTS.document.includes(extension.toUpperCase())) + return FileAppearanceTypeEnum.document + + return FileAppearanceTypeEnum.custom +} + +export const getSupportFileType = (fileName: string, fileMimetype: string, isCustom?: boolean) => { if (isCustom) return SupportUploadFileTypes.custom - const extension = getFileExtension(fileName) + const extension = getFileExtension(fileName, fileMimetype) for (const key in FILE_EXTS) { if ((FILE_EXTS[key]).includes(extension.toUpperCase())) return key @@ -105,6 +128,6 @@ export const getSupportFileExtensionList = (allowFileTypes: string[], allowFileE return allowFileTypes.map(type => FILE_EXTS[type]).flat() } -export const isAllowedFileExtension = (fileName: string, allowFileTypes: string[], allowFileExtensions: string[]) => { - return getSupportFileExtensionList(allowFileTypes, allowFileExtensions).includes(getFileExtension(fileName).toUpperCase()) +export const isAllowedFileExtension = (fileName: string, fileMimetype: string, allowFileTypes: string[], allowFileExtensions: string[]) => { + return getSupportFileExtensionList(allowFileTypes, allowFileExtensions).includes(getFileExtension(fileName, fileMimetype).toUpperCase()) } diff --git a/web/package.json b/web/package.json index b775d87184..77fb842737 100644 --- a/web/package.json +++ b/web/package.json @@ -60,6 +60,7 @@ "lexical": "^0.16.0", "lodash-es": "^4.17.21", "mermaid": "10.4.0", + "mime": "^4.0.4", "negotiator": "^0.6.3", "next": "^14.1.1", "next-nprogress-bar": "^2.3.8", diff --git a/web/yarn.lock b/web/yarn.lock index bec2059a47..d1eede0f70 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -7183,6 +7183,11 @@ mime-types@^2.1.12: dependencies: mime-db "1.52.0" +mime@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-4.0.4.tgz#9f851b0fc3c289d063b20a7a8055b3014b25664b" + integrity sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ== + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" @@ -8816,7 +8821,14 @@ stringify-entities@^4.0.0: character-entities-html4 "^2.0.0" character-entities-legacy "^3.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -9653,8 +9665,7 @@ word-wrap@^1.2.3: resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: - name wrap-ansi-cjs +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -9672,6 +9683,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz"