| import mime from 'mime' | |
| import { flatten } from 'lodash-es' | |
| import { FileAppearanceTypeEnum } from './types' | |
| import type { FileEntity } from './types' | |
| import { upload } from '@/service/base' | |
| import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants' | |
| import { SupportUploadFileTypes } from '@/app/components/workflow/types' | |
| import type { FileResponse } from '@/types/workflow' | |
| import { TransferMethod } from '@/types/app' | |
| type FileUploadParams = { | |
| file: File | |
| onProgressCallback: (progress: number) => void | |
| onSuccessCallback: (res: { id: string }) => void | |
| onErrorCallback: () => void | |
| } | |
| type FileUpload = (v: FileUploadParams, isPublic?: boolean, url?: string) => void | |
| export const fileUpload: FileUpload = ({ | |
| file, | |
| onProgressCallback, | |
| onSuccessCallback, | |
| onErrorCallback, | |
| }, isPublic, url) => { | |
| const formData = new FormData() | |
| formData.append('file', file) | |
| const onProgress = (e: ProgressEvent) => { | |
| if (e.lengthComputable) { | |
| const percent = Math.floor(e.loaded / e.total * 100) | |
| onProgressCallback(percent) | |
| } | |
| } | |
| upload({ | |
| xhr: new XMLHttpRequest(), | |
| data: formData, | |
| onprogress: onProgress, | |
| }, isPublic, url) | |
| .then((res: { id: string }) => { | |
| onSuccessCallback(res) | |
| }) | |
| .catch(() => { | |
| onErrorCallback() | |
| }) | |
| } | |
| export const getFileExtension = (fileName: string, fileMimetype: string, isRemote?: boolean) => { | |
| if (fileMimetype) | |
| return mime.getExtension(fileMimetype) || '' | |
| if (isRemote) | |
| return '' | |
| if (fileName) { | |
| const fileNamePair = fileName.split('.') | |
| const fileNamePairLength = fileNamePair.length | |
| if (fileNamePairLength > 1) | |
| return fileNamePair[fileNamePairLength - 1] | |
| } | |
| return '' | |
| } | |
| 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, fileMimetype) | |
| for (const key in FILE_EXTS) { | |
| if ((FILE_EXTS[key]).includes(extension.toUpperCase())) | |
| return key | |
| } | |
| return '' | |
| } | |
| export const getProcessedFiles = (files: FileEntity[]) => { | |
| return files.filter(file => file.progress !== -1).map(fileItem => ({ | |
| type: fileItem.supportFileType, | |
| transfer_method: fileItem.transferMethod, | |
| url: fileItem.url || '', | |
| upload_file_id: fileItem.uploadedId || '', | |
| })) | |
| } | |
| export const getProcessedFilesFromResponse = (files: FileResponse[]) => { | |
| return files.map((fileItem) => { | |
| return { | |
| id: fileItem.related_id, | |
| name: fileItem.filename, | |
| size: fileItem.size || 0, | |
| type: fileItem.mime_type, | |
| progress: 100, | |
| transferMethod: fileItem.transfer_method, | |
| supportFileType: fileItem.type, | |
| uploadedId: fileItem.related_id, | |
| url: fileItem.url, | |
| } | |
| }) | |
| } | |
| export const getFileNameFromUrl = (url: string) => { | |
| const urlParts = url.split('/') | |
| return urlParts[urlParts.length - 1] || '' | |
| } | |
| export const getSupportFileExtensionList = (allowFileTypes: string[], allowFileExtensions: string[]) => { | |
| if (allowFileTypes.includes(SupportUploadFileTypes.custom)) | |
| return allowFileExtensions.map(item => item.toUpperCase()) | |
| return allowFileTypes.map(type => FILE_EXTS[type]).flat() | |
| } | |
| export const isAllowedFileExtension = (fileName: string, fileMimetype: string, allowFileTypes: string[], allowFileExtensions: string[]) => { | |
| return getSupportFileExtensionList(allowFileTypes, allowFileExtensions).includes(getFileExtension(fileName, fileMimetype).toUpperCase()) | |
| } | |
| export const getFilesInLogs = (rawData: any) => { | |
| const originalFiles = flatten(Object.keys(rawData || {}).map((key) => { | |
| if (typeof rawData[key] === 'object' || Array.isArray(rawData[key])) | |
| return rawData[key] | |
| return undefined | |
| }).filter(Boolean)).filter(item => item?.model_identity === '__dify__file__') | |
| return getProcessedFilesFromResponse(originalFiles) | |
| } | |
| export const fileIsUploaded = (file: FileEntity) => { | |
| if (file.uploadedId) | |
| return true | |
| if (file.transferMethod === TransferMethod.remote_url && file.progress === 100) | |
| return true | |
| } | |
| export const downloadFile = (url: string, filename: string) => { | |
| const anchor = document.createElement('a') | |
| anchor.href = url | |
| anchor.download = filename | |
| anchor.style.display = 'none' | |
| anchor.target = '_blank' | |
| anchor.title = filename | |
| document.body.appendChild(anchor) | |
| anchor.click() | |
| document.body.removeChild(anchor) | |
| } | |