mirror of
https://github.com/langgenius/webapp-conversation.git
synced 2025-12-08 17:32:27 +08:00
Allow file upload in chat.
This commit is contained in:
@ -15,6 +15,9 @@ import Toast from '@/app/components/base/toast'
|
|||||||
import ChatImageUploader from '@/app/components/base/image-uploader/chat-image-uploader'
|
import ChatImageUploader from '@/app/components/base/image-uploader/chat-image-uploader'
|
||||||
import ImageList from '@/app/components/base/image-uploader/image-list'
|
import ImageList from '@/app/components/base/image-uploader/image-list'
|
||||||
import { useImageFiles } from '@/app/components/base/image-uploader/hooks'
|
import { useImageFiles } from '@/app/components/base/image-uploader/hooks'
|
||||||
|
import FileUploaderInAttachmentWrapper from '@/app/components/base/file-uploader-in-attachment'
|
||||||
|
import type { FileEntity, FileUpload } from '@/app/components/base/file-uploader-in-attachment/types'
|
||||||
|
import { getProcessedFiles } from '@/app/components/base/file-uploader-in-attachment/utils'
|
||||||
|
|
||||||
export type IChatProps = {
|
export type IChatProps = {
|
||||||
chatList: ChatItem[]
|
chatList: ChatItem[]
|
||||||
@ -33,6 +36,7 @@ export type IChatProps = {
|
|||||||
isResponding?: boolean
|
isResponding?: boolean
|
||||||
controlClearQuery?: number
|
controlClearQuery?: number
|
||||||
visionConfig?: VisionSettings
|
visionConfig?: VisionSettings
|
||||||
|
fileConfig?: FileUpload
|
||||||
}
|
}
|
||||||
|
|
||||||
const Chat: FC<IChatProps> = ({
|
const Chat: FC<IChatProps> = ({
|
||||||
@ -46,6 +50,7 @@ const Chat: FC<IChatProps> = ({
|
|||||||
isResponding,
|
isResponding,
|
||||||
controlClearQuery,
|
controlClearQuery,
|
||||||
visionConfig,
|
visionConfig,
|
||||||
|
fileConfig,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { notify } = Toast
|
const { notify } = Toast
|
||||||
@ -89,15 +94,20 @@ const Chat: FC<IChatProps> = ({
|
|||||||
onClear,
|
onClear,
|
||||||
} = useImageFiles()
|
} = useImageFiles()
|
||||||
|
|
||||||
|
const [attachmentFiles, setAttachmentFiles] = React.useState<FileEntity[]>([])
|
||||||
|
|
||||||
const handleSend = () => {
|
const handleSend = () => {
|
||||||
if (!valid() || (checkCanSend && !checkCanSend()))
|
if (!valid() || (checkCanSend && !checkCanSend()))
|
||||||
return
|
return
|
||||||
onSend(queryRef.current, files.filter(file => file.progress !== -1).map(fileItem => ({
|
const imageFiles: VisionFile[] = files.filter(file => file.progress !== -1).map(fileItem => ({
|
||||||
type: 'image',
|
type: 'image',
|
||||||
transfer_method: fileItem.type,
|
transfer_method: fileItem.type,
|
||||||
url: fileItem.url,
|
url: fileItem.url,
|
||||||
upload_file_id: fileItem.fileId,
|
upload_file_id: fileItem.fileId,
|
||||||
})))
|
}))
|
||||||
|
const docAndOtherFiles: VisionFile[] = getProcessedFiles(attachmentFiles)
|
||||||
|
const combinedFiles: VisionFile[] = [...imageFiles, ...docAndOtherFiles]
|
||||||
|
onSend(queryRef.current, combinedFiles)
|
||||||
if (!files.find(item => item.type === TransferMethod.local_file && !item.fileId)) {
|
if (!files.find(item => item.type === TransferMethod.local_file && !item.fileId)) {
|
||||||
if (files.length)
|
if (files.length)
|
||||||
onClear()
|
onClear()
|
||||||
@ -106,6 +116,8 @@ const Chat: FC<IChatProps> = ({
|
|||||||
queryRef.current = ''
|
queryRef.current = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!attachmentFiles.find(item => item.transferMethod === TransferMethod.local_file && !item.uploadedId))
|
||||||
|
setAttachmentFiles([])
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleKeyUp = (e: any) => {
|
const handleKeyUp = (e: any) => {
|
||||||
@ -187,6 +199,17 @@ const Chat: FC<IChatProps> = ({
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
fileConfig?.enabled && (
|
||||||
|
<div className={`${visionConfig?.enabled ? 'pl-[52px]' : ''} mb-1`}>
|
||||||
|
<FileUploaderInAttachmentWrapper
|
||||||
|
fileConfig={fileConfig}
|
||||||
|
value={attachmentFiles}
|
||||||
|
onChange={setAttachmentFiles}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
<Textarea
|
<Textarea
|
||||||
className={`
|
className={`
|
||||||
block w-full px-2 pr-[118px] py-[7px] leading-5 max-h-none text-sm text-gray-700 outline-none appearance-none resize-none
|
block w-full px-2 pr-[118px] py-[7px] leading-5 max-h-none text-sm text-gray-700 outline-none appearance-none resize-none
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import ConfigSence from '@/app/components/config-scence'
|
|||||||
import Header from '@/app/components/header'
|
import Header from '@/app/components/header'
|
||||||
import { fetchAppParams, fetchChatList, fetchConversations, generationConversationName, sendChatMessage, updateFeedback } from '@/service'
|
import { fetchAppParams, fetchChatList, fetchConversations, generationConversationName, sendChatMessage, updateFeedback } from '@/service'
|
||||||
import type { ChatItem, ConversationItem, Feedbacktype, PromptConfig, VisionFile, VisionSettings } from '@/types/app'
|
import type { ChatItem, ConversationItem, Feedbacktype, PromptConfig, VisionFile, VisionSettings } from '@/types/app'
|
||||||
|
import type { FileUpload } from '@/app/components/base/file-uploader-in-attachment/types'
|
||||||
import { Resolution, TransferMethod, WorkflowRunningStatus } from '@/types/app'
|
import { Resolution, TransferMethod, WorkflowRunningStatus } from '@/types/app'
|
||||||
import Chat from '@/app/components/chat'
|
import Chat from '@/app/components/chat'
|
||||||
import { setLocaleOnClient } from '@/i18n/client'
|
import { setLocaleOnClient } from '@/i18n/client'
|
||||||
@ -48,6 +49,7 @@ const Main: FC<IMainProps> = () => {
|
|||||||
detail: Resolution.low,
|
detail: Resolution.low,
|
||||||
transfer_methods: [TransferMethod.local_file],
|
transfer_methods: [TransferMethod.local_file],
|
||||||
})
|
})
|
||||||
|
const [fileConfig, setFileConfig] = useState<FileUpload | undefined>()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (APP_INFO?.title)
|
if (APP_INFO?.title)
|
||||||
@ -260,10 +262,20 @@ const Main: FC<IMainProps> = () => {
|
|||||||
prompt_template: promptTemplate,
|
prompt_template: promptTemplate,
|
||||||
prompt_variables,
|
prompt_variables,
|
||||||
} as PromptConfig)
|
} as PromptConfig)
|
||||||
|
const outerFileUploadEnabled = !!file_upload?.enabled
|
||||||
setVisionConfig({
|
setVisionConfig({
|
||||||
...file_upload?.image,
|
...file_upload?.image,
|
||||||
|
enabled: !!(outerFileUploadEnabled && file_upload?.image?.enabled),
|
||||||
image_file_size_limit: system_parameters?.system_parameters || 0,
|
image_file_size_limit: system_parameters?.system_parameters || 0,
|
||||||
})
|
})
|
||||||
|
setFileConfig({
|
||||||
|
enabled: outerFileUploadEnabled,
|
||||||
|
allowed_file_types: file_upload?.allowed_file_types,
|
||||||
|
allowed_file_extensions: file_upload?.allowed_file_extensions,
|
||||||
|
allowed_file_upload_methods: file_upload?.allowed_file_upload_methods,
|
||||||
|
number_limits: file_upload?.number_limits,
|
||||||
|
fileUploadConfig: file_upload?.fileUploadConfig,
|
||||||
|
})
|
||||||
setConversationList(conversations as ConversationItem[])
|
setConversationList(conversations as ConversationItem[])
|
||||||
|
|
||||||
if (isNotNewConversation)
|
if (isNotNewConversation)
|
||||||
@ -373,7 +385,7 @@ const Main: FC<IMainProps> = () => {
|
|||||||
conversation_id: isNewConversation ? null : currConversationId,
|
conversation_id: isNewConversation ? null : currConversationId,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visionConfig?.enabled && files && files?.length > 0) {
|
if (files && files?.length > 0) {
|
||||||
data.files = files.map((item) => {
|
data.files = files.map((item) => {
|
||||||
if (item.transfer_method === TransferMethod.local_file) {
|
if (item.transfer_method === TransferMethod.local_file) {
|
||||||
return {
|
return {
|
||||||
@ -391,7 +403,7 @@ const Main: FC<IMainProps> = () => {
|
|||||||
id: questionId,
|
id: questionId,
|
||||||
content: message,
|
content: message,
|
||||||
isAnswer: false,
|
isAnswer: false,
|
||||||
message_files: files,
|
message_files: (files || []).filter((f: any) => f.type === 'image'),
|
||||||
}
|
}
|
||||||
|
|
||||||
const placeholderAnswerId = `answer-placeholder-${Date.now()}`
|
const placeholderAnswerId = `answer-placeholder-${Date.now()}`
|
||||||
@ -700,6 +712,7 @@ const Main: FC<IMainProps> = () => {
|
|||||||
isResponding={isResponding}
|
isResponding={isResponding}
|
||||||
checkCanSend={checkCanSend}
|
checkCanSend={checkCanSend}
|
||||||
visionConfig={visionConfig}
|
visionConfig={visionConfig}
|
||||||
|
fileConfig={fileConfig}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>)
|
</div>)
|
||||||
|
|||||||
Reference in New Issue
Block a user