mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-14 00:25:57 +08:00
fix: upload image (#1522)
This commit is contained in:
parent
d9336d9ae4
commit
cfbfd59b8f
@ -161,7 +161,7 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
|
|||||||
{
|
{
|
||||||
appType === AppType.completion && visionConfig?.enabled && (
|
appType === AppType.completion && visionConfig?.enabled && (
|
||||||
<div className="mt-3 xl:flex justify-between">
|
<div className="mt-3 xl:flex justify-between">
|
||||||
<div className="mr-1 py-2 shrink-0 w-[120px] text-sm text-gray-900">Image Upload</div>
|
<div className="mr-1 py-2 shrink-0 w-[120px] text-sm text-gray-900">{t('common.imageUploader.imageUpload')}</div>
|
||||||
<div className='grow'>
|
<div className='grow'>
|
||||||
<TextGenerationImageUploader
|
<TextGenerationImageUploader
|
||||||
settings={visionConfig}
|
settings={visionConfig}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react'
|
import { useMemo, useRef, useState } from 'react'
|
||||||
import { useParams } from 'next/navigation'
|
import { useParams } from 'next/navigation'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { imageUpload } from './utils'
|
import { imageUpload } from './utils'
|
||||||
@ -10,38 +10,59 @@ export const useImageFiles = () => {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { notify } = useToastContext()
|
const { notify } = useToastContext()
|
||||||
const [files, setFiles] = useState<ImageFile[]>([])
|
const [files, setFiles] = useState<ImageFile[]>([])
|
||||||
|
const filesRef = useRef<ImageFile[]>([])
|
||||||
|
|
||||||
const handleUpload = (imageFile: ImageFile) => {
|
const handleUpload = (imageFile: ImageFile) => {
|
||||||
const newFiles = [...files, imageFile]
|
const files = filesRef.current
|
||||||
setFiles(newFiles)
|
const index = files.findIndex(file => file._id === imageFile._id)
|
||||||
|
|
||||||
|
if (index > -1) {
|
||||||
|
const currentFile = files[index]
|
||||||
|
const newFiles = [...files.slice(0, index), { ...currentFile, ...imageFile }, ...files.slice(index + 1)]
|
||||||
|
setFiles(newFiles)
|
||||||
|
filesRef.current = newFiles
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const newFiles = [...files, imageFile]
|
||||||
|
setFiles(newFiles)
|
||||||
|
filesRef.current = newFiles
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const handleRemove = (imageFileId: string) => {
|
const handleRemove = (imageFileId: string) => {
|
||||||
|
const files = filesRef.current
|
||||||
const index = files.findIndex(file => file._id === imageFileId)
|
const index = files.findIndex(file => file._id === imageFileId)
|
||||||
|
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
const newFiles = [...files.slice(0, index), ...files.slice(index + 1)]
|
const currentFile = files[index]
|
||||||
|
const newFiles = [...files.slice(0, index), { ...currentFile, deleted: true }, ...files.slice(index + 1)]
|
||||||
setFiles(newFiles)
|
setFiles(newFiles)
|
||||||
|
filesRef.current = newFiles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleImageLinkLoadError = (imageFileId: string) => {
|
const handleImageLinkLoadError = (imageFileId: string) => {
|
||||||
|
const files = filesRef.current
|
||||||
const index = files.findIndex(file => file._id === imageFileId)
|
const index = files.findIndex(file => file._id === imageFileId)
|
||||||
|
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
const currentFile = files[index]
|
const currentFile = files[index]
|
||||||
const newFiles = [...files.slice(0, index), { ...currentFile, progress: -1 }, ...files.slice(index + 1)]
|
const newFiles = [...files.slice(0, index), { ...currentFile, progress: -1 }, ...files.slice(index + 1)]
|
||||||
|
filesRef.current = newFiles
|
||||||
setFiles(newFiles)
|
setFiles(newFiles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleImageLinkLoadSuccess = (imageFileId: string) => {
|
const handleImageLinkLoadSuccess = (imageFileId: string) => {
|
||||||
|
const files = filesRef.current
|
||||||
const index = files.findIndex(file => file._id === imageFileId)
|
const index = files.findIndex(file => file._id === imageFileId)
|
||||||
|
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
const currentImageFile = files[index]
|
const currentImageFile = files[index]
|
||||||
const newFiles = [...files.slice(0, index), { ...currentImageFile, progress: 100 }, ...files.slice(index + 1)]
|
const newFiles = [...files.slice(0, index), { ...currentImageFile, progress: 100 }, ...files.slice(index + 1)]
|
||||||
|
filesRef.current = newFiles
|
||||||
setFiles(newFiles)
|
setFiles(newFiles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleReUpload = (imageFileId: string) => {
|
const handleReUpload = (imageFileId: string) => {
|
||||||
|
const files = filesRef.current
|
||||||
const index = files.findIndex(file => file._id === imageFileId)
|
const index = files.findIndex(file => file._id === imageFileId)
|
||||||
|
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
@ -50,15 +71,18 @@ export const useImageFiles = () => {
|
|||||||
file: currentImageFile.file!,
|
file: currentImageFile.file!,
|
||||||
onProgressCallback: (progress) => {
|
onProgressCallback: (progress) => {
|
||||||
const newFiles = [...files.slice(0, index), { ...currentImageFile, progress }, ...files.slice(index + 1)]
|
const newFiles = [...files.slice(0, index), { ...currentImageFile, progress }, ...files.slice(index + 1)]
|
||||||
|
filesRef.current = newFiles
|
||||||
setFiles(newFiles)
|
setFiles(newFiles)
|
||||||
},
|
},
|
||||||
onSuccessCallback: (res) => {
|
onSuccessCallback: (res) => {
|
||||||
const newFiles = [...files.slice(0, index), { ...currentImageFile, fileId: res.id, progress: 100 }, ...files.slice(index + 1)]
|
const newFiles = [...files.slice(0, index), { ...currentImageFile, fileId: res.id, progress: 100 }, ...files.slice(index + 1)]
|
||||||
|
filesRef.current = newFiles
|
||||||
setFiles(newFiles)
|
setFiles(newFiles)
|
||||||
},
|
},
|
||||||
onErrorCallback: () => {
|
onErrorCallback: () => {
|
||||||
notify({ type: 'error', message: t('common.imageUploader.uploadFromComputerUploadError') })
|
notify({ type: 'error', message: t('common.imageUploader.uploadFromComputerUploadError') })
|
||||||
const newFiles = [...files.slice(0, index), { ...currentImageFile, progress: -1 }, ...files.slice(index + 1)]
|
const newFiles = [...files.slice(0, index), { ...currentImageFile, progress: -1 }, ...files.slice(index + 1)]
|
||||||
|
filesRef.current = newFiles
|
||||||
setFiles(newFiles)
|
setFiles(newFiles)
|
||||||
},
|
},
|
||||||
}, !!params.token)
|
}, !!params.token)
|
||||||
@ -67,10 +91,15 @@ export const useImageFiles = () => {
|
|||||||
|
|
||||||
const handleClear = () => {
|
const handleClear = () => {
|
||||||
setFiles([])
|
setFiles([])
|
||||||
|
filesRef.current = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filteredFiles = useMemo(() => {
|
||||||
|
return files.filter(file => !file.deleted)
|
||||||
|
}, [files])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
files,
|
files: filteredFiles,
|
||||||
onUpload: handleUpload,
|
onUpload: handleUpload,
|
||||||
onRemove: handleRemove,
|
onRemove: handleRemove,
|
||||||
onImageLinkLoadError: handleImageLinkLoadError,
|
onImageLinkLoadError: handleImageLinkLoadError,
|
||||||
|
@ -88,6 +88,7 @@ const Uploader: FC<UploaderProps> = ({
|
|||||||
absolute block inset-0 opacity-0 text-[0]
|
absolute block inset-0 opacity-0 text-[0]
|
||||||
${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}
|
${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}
|
||||||
`}
|
`}
|
||||||
|
onClick={e => (e.target as HTMLInputElement).value = ''}
|
||||||
type='file'
|
type='file'
|
||||||
accept='.png, .jpg, .jpeg, .webp, .gif'
|
accept='.png, .jpg, .jpeg, .webp, .gif'
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
@ -82,7 +82,7 @@ const RunOnce: FC<IRunOnceProps> = ({
|
|||||||
{
|
{
|
||||||
visionConfig?.enabled && (
|
visionConfig?.enabled && (
|
||||||
<div className="w-full mt-4">
|
<div className="w-full mt-4">
|
||||||
<div className="text-gray-900 text-sm font-medium">Image Upload</div>
|
<div className="text-gray-900 text-sm font-medium">{t('common.imageUploader.imageUpload')}</div>
|
||||||
<div className='mt-2'>
|
<div className='mt-2'>
|
||||||
<TextGenerationImageUploader
|
<TextGenerationImageUploader
|
||||||
settings={visionConfig}
|
settings={visionConfig}
|
||||||
|
@ -438,6 +438,7 @@ const translation = {
|
|||||||
pasteImageLink: 'Paste image link',
|
pasteImageLink: 'Paste image link',
|
||||||
pasteImageLinkInputPlaceholder: 'Paste image link here',
|
pasteImageLinkInputPlaceholder: 'Paste image link here',
|
||||||
pasteImageLinkInvalid: 'Invalid image link',
|
pasteImageLinkInvalid: 'Invalid image link',
|
||||||
|
imageUpload: 'Image Upload',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,6 +438,7 @@ const translation = {
|
|||||||
pasteImageLink: '粘贴图片链接',
|
pasteImageLink: '粘贴图片链接',
|
||||||
pasteImageLinkInputPlaceholder: '将图像链接粘贴到此处',
|
pasteImageLinkInputPlaceholder: '将图像链接粘贴到此处',
|
||||||
pasteImageLinkInvalid: '图片链接无效',
|
pasteImageLinkInvalid: '图片链接无效',
|
||||||
|
imageUpload: '图片上传',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,6 +301,7 @@ export type ImageFile = {
|
|||||||
progress: number
|
progress: number
|
||||||
url: string
|
url: string
|
||||||
base64Url?: string
|
base64Url?: string
|
||||||
|
deleted?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type VisionFile = {
|
export type VisionFile = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user