diff --git a/web/app/components/base/chat/chat/chat-input-area/index.tsx b/web/app/components/base/chat/chat/chat-input-area/index.tsx index 2d1f868a26..34175bac01 100644 --- a/web/app/components/base/chat/chat/chat-input-area/index.tsx +++ b/web/app/components/base/chat/chat/chat-input-area/index.tsx @@ -63,7 +63,7 @@ const ChatInputArea = ({ const handleSend = () => { if (onSend) { - if (files.find(item => item.type === TransferMethod.local_file && !item.fileStorageId)) { + if (files.find(item => item.transferMethod === TransferMethod.local_file && !item.uploadedId)) { notify({ type: 'info', message: t('appDebug.errorMessage.waitForImgUpload') }) return } diff --git a/web/app/components/base/file-uploader/file-from-link-or-local/index.tsx b/web/app/components/base/file-uploader/file-from-link-or-local/index.tsx index 940cff2f08..d876c7a5c4 100644 --- a/web/app/components/base/file-uploader/file-from-link-or-local/index.tsx +++ b/web/app/components/base/file-uploader/file-from-link-or-local/index.tsx @@ -61,7 +61,7 @@ const FileFromLinkOrLocal = ({ size='small' variant='primary' disabled={!url || disabled} - onClick={() => handleLoadFileFromLink()} + onClick={() => handleLoadFileFromLink(url)} > {t('common.operation.ok')} 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 00fbf402dc..7facb39871 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 @@ -7,37 +7,33 @@ import FileTypeIcon from '../file-type-icon' import { getFileAppearanceType, getFileExtension, - isImage, } from '../utils' import FileImageRender from '../file-image-render' +import type { FileEntity } from '../types' import ActionButton from '@/app/components/base/action-button' import ProgressCircle from '@/app/components/base/progress-bar/progress-circle' import { formatFileSize } from '@/utils/format' import cn from '@/utils/classnames' import { ReplayLine } from '@/app/components/base/icons/src/vender/other' +import { SupportUploadFileTypes } from '@/app/components/workflow/types' type FileInAttachmentItemProps = { - fileId: string - file: File - imageUrl?: string - progress?: number + file: FileEntity showDeleteAction?: boolean showDownloadAction?: boolean onRemove?: (fileId: string) => void onReUpload?: (fileId: string) => void } const FileInAttachmentItem = ({ - fileId, file, - imageUrl, - progress = 0, showDeleteAction, showDownloadAction = true, onRemove, onReUpload, }: FileInAttachmentItemProps) => { - const isImageFile = isImage(file) - const ext = getFileExtension(file) + const { id, name, progress, supportFileType, base64Url, url } = file + const ext = getFileExtension(name) + const isImageFile = supportFileType === SupportUploadFileTypes.image return (
) } { !isImageFile && ( ) @@ -92,7 +88,7 @@ const FileInAttachmentItem = ({ progress === -1 && ( onReUpload?.(fileId)} + onClick={() => onReUpload?.(id)} > @@ -100,7 +96,7 @@ const FileInAttachmentItem = ({ } { showDeleteAction && ( - onRemove?.(fileId)}> + onRemove?.(id)}> ) diff --git a/web/app/components/base/file-uploader/file-uploader-in-attachment/index.tsx b/web/app/components/base/file-uploader/file-uploader-in-attachment/index.tsx index facc037b03..fb8f5f8f60 100644 --- a/web/app/components/base/file-uploader/file-uploader-in-attachment/index.tsx +++ b/web/app/components/base/file-uploader/file-uploader-in-attachment/index.tsx @@ -96,15 +96,12 @@ const FileUploaderInAttachment = ({ { files.map(file => ( handleRemoveFile(file.fileId)} - onReUpload={() => handleReUploadFile(file.fileId)} + onRemove={() => handleRemoveFile(file.id)} + onReUpload={() => handleReUploadFile(file.id)} /> )) } diff --git a/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-image-item.tsx b/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-image-item.tsx index 906c322991..cde868f618 100644 --- a/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-image-item.tsx +++ b/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-image-item.tsx @@ -1,32 +1,31 @@ import { RiCloseLine } from '@remixicon/react' import FileImageRender from '../file-image-render' +import type { FileEntity } from '../types' import Button from '@/app/components/base/button' import ProgressCircle from '@/app/components/base/progress-bar/progress-circle' import { ReplayLine } from '@/app/components/base/icons/src/vender/other' type FileImageItemProps = { - fileId: string - imageUrl?: string - progress?: number + file: FileEntity showDeleteAction?: boolean onRemove?: (fileId: string) => void onReUpload?: (fileId: string) => void } const FileImageItem = ({ - fileId, - imageUrl, - progress = 0, + file, showDeleteAction, onRemove, onReUpload, }: FileImageItemProps) => { + const { id, progress, base64Url, url } = file + return (
{ showDeleteAction && ( @@ -34,7 +33,7 @@ const FileImageItem = ({ } { progress > 0 && progress < 100 && ( @@ -54,7 +53,7 @@ const FileImageItem = ({
onReUpload?.(fileId)} + onClick={() => onReUpload?.(id)} />
) 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 38af9d0136..4c35f65abc 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 @@ -7,6 +7,7 @@ import { getFileExtension, } from '../utils' import FileTypeIcon from '../file-type-icon' +import type { FileEntity } from '../types' import cn from '@/utils/classnames' import { formatFileSize } from '@/utils/format' import ProgressCircle from '@/app/components/base/progress-bar/progress-circle' @@ -15,24 +16,21 @@ import ActionButton from '@/app/components/base/action-button' import Button from '@/app/components/base/button' type FileItemProps = { - fileId: string - file: File - progress?: number + file: FileEntity showDeleteAction?: boolean showDownloadAction?: boolean onRemove?: (fileId: string) => void onReUpload?: (fileId: string) => void } const FileItem = ({ - fileId, file, - progress = 0, showDeleteAction, showDownloadAction = true, onRemove, onReUpload, }: FileItemProps) => { - const ext = getFileExtension(file) + const { id, name, progress } = file + const ext = getFileExtension(name) const uploadError = progress === -1 return ( @@ -48,20 +46,20 @@ const FileItem = ({ showDeleteAction && ( ) }
- {file.name} + {name}
{ @@ -95,7 +93,7 @@ const FileItem = ({ uploadError && ( onReUpload?.(fileId)} + onClick={() => onReUpload?.(id)} /> ) } diff --git a/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-list.tsx b/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-list.tsx index 8ca422e911..c84a058763 100644 --- a/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-list.tsx +++ b/web/app/components/base/file-uploader/file-uploader-in-chat-input/file-list.tsx @@ -1,10 +1,10 @@ -import { isImage } from '../utils' import { useFile } from '../hooks' import { useStore } from '../store' import type { FileEntity } from '../types' import FileImageItem from './file-image-item' import FileItem from './file-item' import type { FileUpload } from '@/app/components/base/features/types' +import { SupportUploadFileTypes } from '@/app/components/workflow/types' type FileListProps = { files: FileEntity[] @@ -24,13 +24,11 @@ export const FileList = ({
{ files.map((file) => { - if (isImage(file.file)) { + if (file.supportFileType === SupportUploadFileTypes.image) { return ( { } = fileStore.getState() const newFiles = produce(files, (draft) => { - const index = draft.findIndex(file => file.fileId === newFile.fileId) + const index = draft.findIndex(file => file.id === newFile.id) if (index > -1) draft[index] = newFile @@ -59,7 +59,7 @@ export const useFile = (fileConfig: FileUpload) => { setFiles, } = fileStore.getState() - const newFiles = files.filter(file => file.fileId !== fileId) + const newFiles = files.filter(file => file.id !== fileId) setFiles(newFiles) }, [fileStore]) @@ -68,7 +68,7 @@ export const useFile = (fileConfig: FileUpload) => { files, setFiles, } = fileStore.getState() - const index = files.findIndex(file => file.fileId === fileId) + const index = files.findIndex(file => file.id === fileId) if (index > -1) { const uploadingFile = files[index] @@ -77,12 +77,12 @@ export const useFile = (fileConfig: FileUpload) => { }) setFiles(newFiles) fileUpload({ - file: uploadingFile.file!, + file: uploadingFile.originalFile!, onProgressCallback: (progress) => { handleUpdateFile({ ...uploadingFile, progress }) }, onSuccessCallback: (res) => { - handleUpdateFile({ ...uploadingFile, fileId: res.id, progress: 100 }) + handleUpdateFile({ ...uploadingFile, uploadedId: res.id, progress: 100 }) }, onErrorCallback: () => { notify({ type: 'error', message: t('common.imageUploader.uploadFromComputerUploadError') }) @@ -92,7 +92,20 @@ export const useFile = (fileConfig: FileUpload) => { } }, [fileStore, notify, t, handleUpdateFile, params]) - const handleLoadFileFromLink = useCallback(() => {}, []) + const handleLoadFileFromLink = useCallback((url: string) => { + const uploadingFile = { + id: uuid4(), + name: 'remote file (todo)', + type: '', + size: 0, + progress: 0, + transferMethod: TransferMethod.remote_url, + supportFileType: '', + url, + base64Url: '', + } + handleAddFile(uploadingFile) + }, [handleAddFile]) const handleLoadFileFromLinkSuccess = useCallback(() => { }, []) @@ -113,28 +126,29 @@ export const useFile = (fileConfig: FileUpload) => { const reader = new FileReader() const isImage = file.type.startsWith('image') const allowedFileTypes = fileConfig.allowed_file_types - const isCustomFileType = allowedFileTypes?.includes(SupportUploadFileTypes.custom) reader.addEventListener( 'load', () => { const uploadingFile = { - fileId: uuid4(), - file, - url: '', + id: uuid4(), + name: file.name, + type: file.type, + size: file.size, progress: 0, + transferMethod: TransferMethod.local_file, + supportFileType: getSupportFileType(file.name, allowedFileTypes?.includes(SupportUploadFileTypes.custom)), + originalFile: file, base64Url: isImage ? reader.result as string : '', - fileType: isCustomFileType ? SupportUploadFileTypes.custom : getFileType(file), - type: TransferMethod.local_file, } handleAddFile(uploadingFile) fileUpload({ - file: uploadingFile.file, + file: uploadingFile.originalFile, onProgressCallback: (progress) => { handleUpdateFile({ ...uploadingFile, progress }) }, onSuccessCallback: (res) => { - handleUpdateFile({ ...uploadingFile, fileStorageId: res.id, progress: 100 }) + handleUpdateFile({ ...uploadingFile, uploadedId: res.id, progress: 100 }) }, onErrorCallback: () => { notify({ type: 'error', message: t('common.fileUploader.uploadFromComputerUploadError') }) diff --git a/web/app/components/base/file-uploader/types.ts b/web/app/components/base/file-uploader/types.ts index b84986e06b..ac4584bb4c 100644 --- a/web/app/components/base/file-uploader/types.ts +++ b/web/app/components/base/file-uploader/types.ts @@ -18,12 +18,15 @@ export enum FileAppearanceTypeEnum { export type FileAppearanceType = keyof typeof FileAppearanceTypeEnum export type FileEntity = { - fileId: string - file: File - fileStorageId?: string + id: string + name: string + size: number + type: string progress: number - url?: string + transferMethod: TransferMethod + supportFileType: string + originalFile?: File + uploadedId?: string base64Url?: string - type: TransferMethod - fileType: string + url?: string } diff --git a/web/app/components/base/file-uploader/utils.ts b/web/app/components/base/file-uploader/utils.ts index b9b6f73fcd..bf70bc4664 100644 --- a/web/app/components/base/file-uploader/utils.ts +++ b/web/app/components/base/file-uploader/utils.ts @@ -2,6 +2,7 @@ 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' type FileUploadParams = { file: File @@ -38,35 +39,30 @@ export const fileUpload: FileUpload = ({ }) } -export const getFileAppearanceType = (file?: File) => { - if (!file) +export const getFileAppearanceType = (fileType: string) => { + if (!fileType) return FileAppearanceTypeEnum.custom - const mimeType = file.type - if (mimeType.includes('image')) + if (fileType.includes('image')) return FileAppearanceTypeEnum.image - if (mimeType.includes('video')) + if (fileType.includes('video')) return FileAppearanceTypeEnum.video - if (mimeType.includes('audio')) + if (fileType.includes('audio')) return FileAppearanceTypeEnum.audio - if (mimeType.includes('pdf')) + if (fileType.includes('pdf')) return FileAppearanceTypeEnum.pdf return FileAppearanceTypeEnum.custom } -export const isImage = (file?: File) => { - return file?.type.startsWith('image') -} - -export const getFileExtension = (file?: File) => { - if (!file) +export const getFileExtension = (fileName: string) => { + if (!fileName) return '' - const fileNamePair = file.name.split('.') + const fileNamePair = fileName.split('.') const fileNamePairLength = fileNamePair.length if (fileNamePairLength > 1) @@ -75,8 +71,11 @@ export const getFileExtension = (file?: File) => { return '' } -export const getFileType = (file?: File) => { - const extension = getFileExtension(file) +export const getSupportFileType = (fileName: string, isCustom?: boolean) => { + if (isCustom) + return SupportUploadFileTypes.custom + + const extension = getFileExtension(fileName) for (const key in FILE_EXTS) { if ((FILE_EXTS[key]).includes(extension.toUpperCase())) return key @@ -87,9 +86,9 @@ export const getFileType = (file?: File) => { export const getProcessedFiles = (files: FileEntity[]) => { return files.filter(file => file.progress !== -1).map(fileItem => ({ - type: fileItem.fileType, - transfer_method: fileItem.type, + type: fileItem.supportFileType, + transfer_method: fileItem.transferMethod, url: fileItem.url || '', - upload_file_id: fileItem.fileStorageId || '', + upload_file_id: fileItem.uploadedId || '', })) } diff --git a/web/app/components/share/text-generation/run-once/index.tsx b/web/app/components/share/text-generation/run-once/index.tsx index 0e850b5d05..89f235eee5 100644 --- a/web/app/components/share/text-generation/run-once/index.tsx +++ b/web/app/components/share/text-generation/run-once/index.tsx @@ -13,6 +13,7 @@ import { DEFAULT_VALUE_MAX_LEN } from '@/config' import TextGenerationImageUploader from '@/app/components/base/image-uploader/text-generation-image-uploader' import type { VisionFile, VisionSettings } from '@/types/app' import { FileUploaderInAttachmentWrapper } from '@/app/components/base/file-uploader' +import { getProcessedFiles } from '@/app/components/base/file-uploader/utils' export type IRunOnceProps = { siteInfo: SiteInfo @@ -113,12 +114,9 @@ const RunOnce: FC = ({
) } - onVisionFilesChange(files.filter(file => file.progress !== -1).map(fileItem => ({ - type: fileItem.fileType, - transfer_method: fileItem.type, - url: fileItem.url || '', - upload_file_id: fileItem.fileId, - })))} /> + onVisionFilesChange(getProcessedFiles(files))} + /> {promptConfig.prompt_variables.length > 0 && (
)} diff --git a/web/app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx b/web/app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx index b1a28f94b7..4f9b602199 100644 --- a/web/app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx +++ b/web/app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx @@ -23,6 +23,7 @@ import { Line3 } from '@/app/components/base/icons/src/public/common' import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' import { BubbleX } from '@/app/components/base/icons/src/vender/line/others' import cn from '@/utils/classnames' +import { getProcessedFiles } from '@/app/components/base/file-uploader/utils' type Props = { payload: InputVar @@ -158,12 +159,7 @@ const FormItem: FC = ({ } {(type === InputVarType.singleFile || type === InputVarType.multiFiles) && ( onChange(files.filter(file => file.progress !== -1).map(fileItem => ({ - type: fileItem.fileType, - transfer_method: fileItem.type, - url: fileItem.url, - upload_file_id: fileItem.fileId, - })))} + onChange={files => onChange(getProcessedFiles(files))} fileConfig={{ allowed_file_types: payload.allowed_file_types, allowed_file_extensions: payload.allowed_file_extensions, diff --git a/web/app/components/workflow/panel/debug-and-preview/hooks.ts b/web/app/components/workflow/panel/debug-and-preview/hooks.ts index a693b5f20c..83ccce2ad3 100644 --- a/web/app/components/workflow/panel/debug-and-preview/hooks.ts +++ b/web/app/components/workflow/panel/debug-and-preview/hooks.ts @@ -189,7 +189,6 @@ export const useChat = ( const { files, ...restParams } = params const bodyParams = { - conversation_id: conversationId.current, files: getProcessedFiles(files || []), ...restParams, } @@ -208,7 +207,7 @@ export const useChat = ( let hasSetResponseId = false handleRun( - params, + bodyParams, { onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId, taskId }: any) => { responseItem.content = responseItem.content + message diff --git a/web/service/common.ts b/web/service/common.ts index 3fbcde2a2a..f4b7a91738 100644 --- a/web/service/common.ts +++ b/web/service/common.ts @@ -308,3 +308,7 @@ export const verifyForgotPasswordToken: Fetcher = ({ url, body }) => post(url, { body }) + +export const fetchRemoteFileInfo: Fetcher<{ file_type: string; file_length: number }, string> = (url) => { + return get<{ file_type: string; file_length: number }>(url) +}