mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 19:59:50 +08:00
file uploader
This commit is contained in:
parent
1df41cef4c
commit
fd9b71c4d7
|
@ -1,5 +1,4 @@
|
|||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useRef,
|
||||
useState,
|
||||
|
@ -16,11 +15,15 @@ import { useTextAreaHeight } from './hooks'
|
|||
import Operation from './operation'
|
||||
import cn from '@/utils/classnames'
|
||||
import { FileListInChatInput } from '@/app/components/base/file-uploader'
|
||||
import { FileContextProvider } from '@/app/components/base/file-uploader/store'
|
||||
import {
|
||||
FileContextProvider,
|
||||
useStore,
|
||||
} from '@/app/components/base/file-uploader/store'
|
||||
import VoiceInput from '@/app/components/base/voice-input'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import FeatureBar from '@/app/components/base/features/new-feature-panel/feature-bar'
|
||||
import type { FileUpload } from '@/app/components/base/features/types'
|
||||
import { TransferMethod } from '@/types/app'
|
||||
|
||||
type ChatInputAreaProps = {
|
||||
showFeatureBar?: boolean
|
||||
|
@ -55,15 +58,27 @@ const ChatInputArea = ({
|
|||
const [query, setQuery] = useState('')
|
||||
const isUseInputMethod = useRef(false)
|
||||
const [showVoiceInput, setShowVoiceInput] = useState(false)
|
||||
const files = useStore(s => s.files)
|
||||
const setFiles = useStore(s => s.setFiles)
|
||||
|
||||
const handleSend = () => {
|
||||
if (onSend) {
|
||||
if (files.find(item => item.type === TransferMethod.local_file && !item.fileStorageId)) {
|
||||
notify({ type: 'info', message: t('appDebug.errorMessage.waitForImgUpload') })
|
||||
return
|
||||
}
|
||||
if (!query || !query.trim()) {
|
||||
notify({ type: 'info', message: t('appAnnotation.errorMessage.queryRequired') })
|
||||
return
|
||||
}
|
||||
onSend(query)
|
||||
onSend(query, files.filter(file => file.progress !== -1).map(fileItem => ({
|
||||
type: fileItem.fileType,
|
||||
transfer_method: fileItem.type,
|
||||
url: fileItem.url || '',
|
||||
upload_file_id: fileItem.fileStorageId || '',
|
||||
})))
|
||||
setQuery('')
|
||||
setFiles([])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,7 +118,6 @@ const ChatInputArea = ({
|
|||
)
|
||||
|
||||
return (
|
||||
<FileContextProvider onChange={() => {}}>
|
||||
<>
|
||||
<div
|
||||
className={cn(
|
||||
|
@ -159,8 +173,15 @@ const ChatInputArea = ({
|
|||
</div>
|
||||
{showFeatureBar && <FeatureBar showFileUpload={showFileUpload} disabled={featureBarDisabled} onFeatureBarClick={onFeatureBarClick} />}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const ChatInputAreaWrapper = (props: ChatInputAreaProps) => {
|
||||
return (
|
||||
<FileContextProvider>
|
||||
<ChatInputArea {...props} />
|
||||
</FileContextProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(ChatInputArea)
|
||||
export default ChatInputAreaWrapper
|
||||
|
|
1
web/app/components/base/file-uploader/constants.ts
Normal file
1
web/app/components/base/file-uploader/constants.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export const FILE_LIMIT = 15 * 1024 * 1024
|
|
@ -9,14 +9,21 @@ import { v4 as uuid4 } from 'uuid'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import type { FileEntity } from './types'
|
||||
import { useFileStore } from './store'
|
||||
import { fileUpload } from './utils'
|
||||
import {
|
||||
fileUpload,
|
||||
getFileType,
|
||||
} from './utils'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import { TransferMethod } from '@/types/app'
|
||||
import { useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
|
||||
|
||||
export const useFile = () => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
const fileStore = useFileStore()
|
||||
const params = useParams()
|
||||
const featuresStore = useFeaturesStore()
|
||||
|
||||
const handleAddOrUpdateFiles = useCallback((newFile: FileEntity) => {
|
||||
const {
|
||||
|
@ -90,6 +97,9 @@ export const useFile = () => {
|
|||
const handleLocalFileUpload = useCallback((file: File) => {
|
||||
const reader = new FileReader()
|
||||
const isImage = file.type.startsWith('image')
|
||||
const allowedFileTypes = featuresStore?.getState().features.file?.allowed_file_types
|
||||
const isCustomFileType = allowedFileTypes?.includes(SupportUploadFileTypes.custom)
|
||||
|
||||
reader.addEventListener(
|
||||
'load',
|
||||
() => {
|
||||
|
@ -99,6 +109,8 @@ export const useFile = () => {
|
|||
url: '',
|
||||
progress: 0,
|
||||
base64Url: isImage ? reader.result as string : '',
|
||||
fileType: isCustomFileType ? SupportUploadFileTypes.custom : getFileType(file),
|
||||
type: TransferMethod.local_file,
|
||||
}
|
||||
handleAddOrUpdateFiles(uploadingFile)
|
||||
fileUpload({
|
||||
|
|
|
@ -7,21 +7,20 @@ import {
|
|||
create,
|
||||
useStore as useZustandStore,
|
||||
} from 'zustand'
|
||||
import type { FileEntity } from './types'
|
||||
import type {
|
||||
FileEntity,
|
||||
} from './types'
|
||||
|
||||
type Shape = {
|
||||
files: FileEntity[]
|
||||
setFiles: (files: FileEntity[]) => void
|
||||
}
|
||||
|
||||
export const createFileStore = ({
|
||||
onChange,
|
||||
}: Pick<FileProviderProps, 'onChange'>) => {
|
||||
export const createFileStore = () => {
|
||||
return create<Shape>(set => ({
|
||||
files: [],
|
||||
setFiles: (files) => {
|
||||
set({ files })
|
||||
onChange(files)
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
@ -43,18 +42,16 @@ export const useFileStore = () => {
|
|||
|
||||
type FileProviderProps = {
|
||||
children: React.ReactNode
|
||||
onChange: (files: FileEntity[]) => void
|
||||
isPublicAPI?: boolean
|
||||
url?: string
|
||||
}
|
||||
export const FileContextProvider = ({
|
||||
children,
|
||||
onChange,
|
||||
}: FileProviderProps) => {
|
||||
const storeRef = useRef<FileStore>()
|
||||
|
||||
if (!storeRef.current)
|
||||
storeRef.current = createFileStore({ onChange })
|
||||
storeRef.current = createFileStore()
|
||||
|
||||
return (
|
||||
<FileContext.Provider value={storeRef.current}>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import type { TransferMethod } from '@/types/app'
|
||||
|
||||
export enum FileAppearanceTypeEnum {
|
||||
IMAGE = 'IMAGE',
|
||||
VIDEO = 'VIDEO',
|
||||
|
@ -22,4 +24,6 @@ export type FileEntity = {
|
|||
progress: number
|
||||
url?: string
|
||||
base64Url?: string
|
||||
type: TransferMethod
|
||||
fileType: string
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { FileAppearanceTypeEnum } from './types'
|
||||
import { upload } from '@/service/base'
|
||||
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
|
||||
|
||||
type FileUploadParams = {
|
||||
file: File
|
||||
|
@ -72,3 +73,13 @@ export const getFileExtension = (file?: File) => {
|
|||
|
||||
return ''
|
||||
}
|
||||
|
||||
export const getFileType = (file?: File) => {
|
||||
const extension = getFileExtension(file)
|
||||
for (const key in FILE_EXTS) {
|
||||
if ((FILE_EXTS[key]).includes(extension.toUpperCase()))
|
||||
return key
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user