mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-18 07:25:54 +08:00
file in chat question
This commit is contained in:
parent
396a240e68
commit
2b0c39ed3f
@ -71,12 +71,7 @@ const ChatInputArea = ({
|
||||
notify({ type: 'info', message: t('appAnnotation.errorMessage.queryRequired') })
|
||||
return
|
||||
}
|
||||
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 || '',
|
||||
})))
|
||||
onSend(query, files)
|
||||
setQuery('')
|
||||
setFiles([])
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import type {
|
||||
ChatItem,
|
||||
Inputs,
|
||||
PromptVariable,
|
||||
VisionFile,
|
||||
} from '../types'
|
||||
import { TransferMethod } from '@/types/app'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
@ -23,6 +22,8 @@ import type { Annotation } from '@/models/log'
|
||||
import { WorkflowRunningStatus } from '@/app/components/workflow/types'
|
||||
import useTimestamp from '@/hooks/use-timestamp'
|
||||
import { AudioPlayerManager } from '@/app/components/base/audio-btn/audio.player.manager'
|
||||
import type { FileEntity } from '@/app/components/base/file-uploader/types'
|
||||
import { getProcessedFiles } from '@/app/components/base/file-uploader/utils'
|
||||
|
||||
type GetAbortController = (abortController: AbortController) => void
|
||||
type SendCallback = {
|
||||
@ -196,7 +197,11 @@ export const useChat = (
|
||||
|
||||
const handleSend = useCallback(async (
|
||||
url: string,
|
||||
data: any,
|
||||
data: {
|
||||
query: string
|
||||
files?: FileEntity[]
|
||||
[key: string]: any
|
||||
},
|
||||
{
|
||||
onGetConversationMessages,
|
||||
onGetSuggestedQuestions,
|
||||
@ -244,13 +249,16 @@ export const useChat = (
|
||||
handleResponding(true)
|
||||
hasStopResponded.current = false
|
||||
|
||||
const { query, files, ...restData } = data
|
||||
const bodyParams = {
|
||||
response_mode: 'streaming',
|
||||
conversation_id: conversationId.current,
|
||||
...data,
|
||||
files: getProcessedFiles(files || []),
|
||||
query,
|
||||
...restData,
|
||||
}
|
||||
if (bodyParams?.files?.length) {
|
||||
bodyParams.files = bodyParams.files.map((item: VisionFile) => {
|
||||
bodyParams.files = bodyParams.files.map((item) => {
|
||||
if (item.transfer_method === TransferMethod.local_file) {
|
||||
return {
|
||||
...item,
|
||||
|
@ -10,7 +10,7 @@ import type { Theme } from '../embedded-chatbot/theme/theme-context'
|
||||
import { CssTransform } from '../embedded-chatbot/theme/utils'
|
||||
import { User } from '@/app/components/base/icons/src/public/avatar'
|
||||
import { Markdown } from '@/app/components/base/markdown'
|
||||
import ImageGallery from '@/app/components/base/image-gallery'
|
||||
import { FileList } from '@/app/components/base/file-uploader'
|
||||
|
||||
type QuestionProps = {
|
||||
item: ChatItem
|
||||
@ -27,7 +27,6 @@ const Question: FC<QuestionProps> = ({
|
||||
message_files,
|
||||
} = item
|
||||
|
||||
const imgSrcs = message_files?.length ? message_files.map(item => item.url) : []
|
||||
return (
|
||||
<div className='flex justify-end mb-2 last:mb-0 pl-10'>
|
||||
<div className='group relative mr-4'>
|
||||
@ -36,8 +35,12 @@ const Question: FC<QuestionProps> = ({
|
||||
style={theme?.chatBubbleColorStyle ? CssTransform(theme.chatBubbleColorStyle) : {}}
|
||||
>
|
||||
{
|
||||
!!imgSrcs.length && (
|
||||
<ImageGallery srcs={imgSrcs} />
|
||||
!!message_files?.length && (
|
||||
<FileList
|
||||
files={message_files}
|
||||
showDeleteAction={false}
|
||||
showDownloadAction={false}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<Markdown content={content} />
|
||||
|
@ -1,6 +1,7 @@
|
||||
import type { TypeWithI18N } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import type { Annotation, MessageRating } from '@/models/log'
|
||||
import type { VisionFile } from '@/types/app'
|
||||
import type { FileEntity } from '@/app/components/base/file-uploader/types'
|
||||
|
||||
export type MessageMore = {
|
||||
time: string
|
||||
@ -90,7 +91,7 @@ export type IChatItem = {
|
||||
suggestedQuestions?: string[]
|
||||
log?: { role: string; text: string; files?: VisionFile[] }[]
|
||||
agent_thoughts?: ThoughtItem[]
|
||||
message_files?: VisionFile[]
|
||||
message_files?: FileEntity[]
|
||||
workflow_run_id?: string
|
||||
// for agent log
|
||||
conversationId?: string
|
||||
|
@ -1,11 +1,11 @@
|
||||
import type {
|
||||
ModelConfig,
|
||||
VisionFile,
|
||||
VisionSettings,
|
||||
} from '@/types/app'
|
||||
import type { IChatItem } from '@/app/components/base/chat/chat/type'
|
||||
import type { NodeTracing } from '@/types/workflow'
|
||||
import type { WorkflowRunningStatus } from '@/app/components/workflow/types'
|
||||
import type { FileEntity } from '@/app/components/base/file-uploader/types'
|
||||
|
||||
export type { VisionFile } from '@/types/app'
|
||||
export { TransferMethod } from '@/types/app'
|
||||
@ -63,7 +63,7 @@ export type ChatItem = IChatItem & {
|
||||
conversationId?: string
|
||||
}
|
||||
|
||||
export type OnSend = (message: string, files?: VisionFile[]) => void
|
||||
export type OnSend = (message: string, files?: FileEntity[]) => void
|
||||
|
||||
export type Callback = {
|
||||
onSuccess: () => void
|
||||
|
@ -1,22 +1,25 @@
|
||||
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'
|
||||
|
||||
type FileListProps = {
|
||||
fileConfig: FileUpload
|
||||
files: FileEntity[]
|
||||
onRemove?: (fileId: string) => void
|
||||
onReUpload?: (fileId: string) => void
|
||||
showDeleteAction?: boolean
|
||||
showDownloadAction?: boolean
|
||||
}
|
||||
const FileList = ({
|
||||
fileConfig,
|
||||
export const FileList = ({
|
||||
files,
|
||||
onReUpload,
|
||||
onRemove,
|
||||
showDeleteAction = true,
|
||||
showDownloadAction = false,
|
||||
}: FileListProps) => {
|
||||
const files = useStore(s => s.files)
|
||||
const {
|
||||
handleRemoveFile,
|
||||
handleReUploadFile,
|
||||
} = useFile(fileConfig)
|
||||
|
||||
return (
|
||||
<div className='flex flex-wrap gap-2'>
|
||||
{
|
||||
@ -28,9 +31,9 @@ const FileList = ({
|
||||
fileId={file.fileId}
|
||||
imageUrl={file.base64Url}
|
||||
progress={file.progress}
|
||||
showDeleteAction
|
||||
onRemove={handleRemoveFile}
|
||||
onReUpload={handleReUploadFile}
|
||||
showDeleteAction={showDeleteAction}
|
||||
onRemove={onRemove}
|
||||
onReUpload={onReUpload}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -41,10 +44,10 @@ const FileList = ({
|
||||
fileId={file.fileId}
|
||||
file={file.file}
|
||||
progress={file.progress}
|
||||
showDeleteAction
|
||||
showDownloadAction={false}
|
||||
onRemove={handleRemoveFile}
|
||||
onReUpload={handleReUploadFile}
|
||||
showDeleteAction={showDeleteAction}
|
||||
showDownloadAction={showDownloadAction}
|
||||
onRemove={onRemove}
|
||||
onReUpload={onReUpload}
|
||||
/>
|
||||
)
|
||||
})
|
||||
@ -53,4 +56,23 @@ const FileList = ({
|
||||
)
|
||||
}
|
||||
|
||||
export default FileList
|
||||
type FileListInChatInputProps = {
|
||||
fileConfig: FileUpload
|
||||
}
|
||||
export const FileListInChatInput = ({
|
||||
fileConfig,
|
||||
}: FileListInChatInputProps) => {
|
||||
const files = useStore(s => s.files)
|
||||
const {
|
||||
handleRemoveFile,
|
||||
handleReUploadFile,
|
||||
} = useFile(fileConfig)
|
||||
|
||||
return (
|
||||
<FileList
|
||||
files={files}
|
||||
onReUpload={handleReUploadFile}
|
||||
onRemove={handleRemoveFile}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -2,5 +2,6 @@ export { default as FileUploaderInAttachmentWrapper } from './file-uploader-in-a
|
||||
export { default as FileItemInAttachment } from './file-uploader-in-attachment/file-item'
|
||||
export { default as FileUploaderInChatInput } from './file-uploader-in-chat-input'
|
||||
export { default as FileTypeIcon } from './file-type-icon'
|
||||
export { default as FileListInChatInput } from './file-uploader-in-chat-input/file-list'
|
||||
export { default as FileItemInChatInput } from './file-uploader-in-chat-input/file-list'
|
||||
export { FileListInChatInput } from './file-uploader-in-chat-input/file-list'
|
||||
export { FileList } from './file-uploader-in-chat-input/file-list'
|
||||
export { default as FileItem } from './file-uploader-in-chat-input/file-item'
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { FileAppearanceTypeEnum } from './types'
|
||||
import type { FileEntity } from './types'
|
||||
import { upload } from '@/service/base'
|
||||
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
|
||||
|
||||
@ -83,3 +84,12 @@ export const getFileType = (file?: File) => {
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
export const getProcessedFiles = (files: FileEntity[]) => {
|
||||
return files.filter(file => file.progress !== -1).map(fileItem => ({
|
||||
type: fileItem.fileType,
|
||||
transfer_method: fileItem.type,
|
||||
url: fileItem.url || '',
|
||||
upload_file_id: fileItem.fileStorageId || '',
|
||||
}))
|
||||
}
|
||||
|
@ -407,9 +407,9 @@ const WorkflowWrap = memo(() => {
|
||||
const initialFeatures: FeaturesData = {
|
||||
file: {
|
||||
image: {
|
||||
enabled: !!features.file_upload?.image.enabled,
|
||||
number_limits: features.file_upload?.image.number_limits || 3,
|
||||
transfer_methods: features.file_upload?.image.transfer_methods || ['local_file', 'remote_url'],
|
||||
enabled: !!features.file_upload?.image?.enabled,
|
||||
number_limits: features.file_upload?.image?.number_limits || 3,
|
||||
transfer_methods: features.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'],
|
||||
},
|
||||
enabled: !!(features.file_upload?.enabled || features.file_upload?.image?.enabled),
|
||||
allowed_file_types: features.file_upload?.allowed_file_types || [SupportUploadFileTypes.image],
|
||||
|
@ -15,8 +15,9 @@ import type {
|
||||
} from '@/app/components/base/chat/types'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import { TransferMethod } from '@/types/app'
|
||||
import type { VisionFile } from '@/types/app'
|
||||
import { replaceStringWithValues } from '@/app/components/app/configuration/prompt-value-panel/utils'
|
||||
import { getProcessedFiles } from '@/app/components/base/file-uploader/utils'
|
||||
import type { FileEntity } from '@/app/components/base/file-uploader/types'
|
||||
|
||||
type GetAbortController = (abortController: AbortController) => void
|
||||
type SendCallback = {
|
||||
@ -143,7 +144,11 @@ export const useChat = (
|
||||
}, [handleUpdateChatList])
|
||||
|
||||
const handleSend = useCallback((
|
||||
params: any,
|
||||
params: {
|
||||
query: string
|
||||
files?: FileEntity[]
|
||||
[key: string]: any
|
||||
},
|
||||
{
|
||||
onGetSuggestedQuestions,
|
||||
}: SendCallback,
|
||||
@ -182,12 +187,14 @@ export const useChat = (
|
||||
|
||||
handleResponding(true)
|
||||
|
||||
const { files, ...restParams } = params
|
||||
const bodyParams = {
|
||||
conversation_id: conversationId.current,
|
||||
...params,
|
||||
files: getProcessedFiles(files || []),
|
||||
...restParams,
|
||||
}
|
||||
if (bodyParams?.files?.length) {
|
||||
bodyParams.files = bodyParams.files.map((item: VisionFile) => {
|
||||
bodyParams.files = bodyParams.files.map((item) => {
|
||||
if (item.transfer_method === TransferMethod.local_file) {
|
||||
return {
|
||||
...item,
|
||||
|
Loading…
x
Reference in New Issue
Block a user