Feat: Upload files in the chat box on the agent page #3221 (#9035)

### What problem does this PR solve?

Feat: Upload files in the chat box on the agent page #3221
### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-07-24 19:17:56 +08:00
committed by GitHub
parent 2ae8f2cf00
commit 88910449e4
9 changed files with 356 additions and 20 deletions

View File

@ -3,11 +3,15 @@ import { useGetFileIcon } from '@/pages/chat/hooks';
import { useSendAgentMessage } from './use-send-agent-message';
import MessageInput from '@/components/message-input';
import { FileUploadProps } from '@/components/file-upload';
import { NextMessageInput } from '@/components/message-input/next';
import MessageItem from '@/components/next-message-item';
import PdfDrawer from '@/components/pdf-drawer';
import { useClickDrawer } from '@/components/pdf-drawer/hooks';
import { useFetchAgent } from '@/hooks/use-agent-request';
import {
useFetchAgent,
useUploadCanvasFileWithProgress,
} from '@/hooks/use-agent-request';
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
import { Message } from '@/interfaces/database/chat';
import { buildMessageUuidWithRole } from '@/utils/chat';
@ -20,15 +24,16 @@ import { buildBeginQueryWithObject } from '../utils';
const AgentChatBox = () => {
const {
sendLoading,
handleInputChange,
handlePressEnter,
value,
ref,
sendLoading,
derivedMessages,
handleInputChange,
handlePressEnter,
stopOutputMessage,
sendFormMessage,
findReferenceByMessageId,
appendUploadResponseList,
} = useSendAgentMessage();
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
@ -37,6 +42,7 @@ const AgentChatBox = () => {
const { data: userInfo } = useFetchUserInfo();
const { data: canvasInfo } = useFetchAgent();
const { id: canvasId } = useParams();
const { uploadCanvasFile, loading } = useUploadCanvasFileWithProgress();
const getInputs = useCallback((message: Message) => {
return get(message, 'data.inputs', {}) as Record<string, BeginQuery>;
@ -66,6 +72,15 @@ const AgentChatBox = () => {
[canvasId, getInputs, sendFormMessage],
);
const handleUploadFile: NonNullable<FileUploadProps['onUpload']> =
useCallback(
async (files, options) => {
const ret = await uploadCanvasFile({ files, options });
appendUploadResponseList(ret.data);
},
[appendUploadResponseList, uploadCanvasFile],
);
return (
<>
<section className="flex flex-1 flex-col px-5 h-[90vh]">
@ -104,15 +119,17 @@ const AgentChatBox = () => {
</div>
<div ref={ref} />
</div>
<MessageInput
<NextMessageInput
value={value}
sendLoading={sendLoading}
disabled={false}
sendDisabled={sendLoading}
conversationId=""
isUploading={loading}
onPressEnter={handlePressEnter}
onInputChange={handleInputChange}
stopOutputMessage={stopOutputMessage}
onUpload={handleUploadFile}
conversationId=""
/>
</section>
<PdfDrawer

View File

@ -1,4 +1,4 @@
import { Sheet, SheetContent } from '@/components/ui/sheet';
import { Sheet, SheetContent, SheetTitle } from '@/components/ui/sheet';
import { IModalProps } from '@/interfaces/common';
import { cn } from '@/lib/utils';
import { useTranslation } from 'react-i18next';
@ -12,6 +12,7 @@ export function ChatSheet({ hideModal }: IModalProps<any>) {
className={cn('top-20 p-0')}
onInteractOutside={(e) => e.preventDefault()}
>
<SheetTitle className="hidden"></SheetTitle>
<div className="pl-5 pt-2">{t('chat.chat')}</div>
<AgentChatBox></AgentChatBox>
</SheetContent>

View File

@ -137,6 +137,38 @@ export function useFindMessageReference(answerList: IEventList) {
return { findReferenceByMessageId };
}
interface UploadResponseDataType {
created_at: number;
created_by: string;
extension: string;
id: string;
mime_type: string;
name: string;
preview_url: null;
size: number;
}
export function useSetUploadResponseData() {
const [uploadResponseList, setUploadResponseList] = useState<
UploadResponseDataType[]
>([]);
const append = useCallback((data: UploadResponseDataType) => {
setUploadResponseList((prev) => [...prev, data]);
}, []);
const clear = useCallback(() => {
setUploadResponseList([]);
}, []);
return {
uploadResponseList,
setUploadResponseList,
appendUploadResponseList: append,
clearUploadResponseList: clear,
};
}
export const useSendAgentMessage = (url?: string) => {
const { id: agentId } = useParams();
const { handleInputChange, value, setValue } = useHandleMessageInputChange();
@ -155,6 +187,11 @@ export const useSendAgentMessage = (url?: string) => {
addNewestOneAnswer,
} = useSelectDerivedMessages();
const { addEventList } = useContext(AgentChatLogContext);
const {
appendUploadResponseList,
clearUploadResponseList,
uploadResponseList,
} = useSetUploadResponseData();
const sendMessage = useCallback(
async ({ message }: { message: Message; messages?: Message[] }) => {
@ -171,9 +208,13 @@ export const useSendAgentMessage = (url?: string) => {
params.query = message.content;
// params.message_id = message.id;
params.inputs = transferInputsArrayToObject(query); // begin operator inputs
params.files = uploadResponseList;
}
const res = await send(params);
clearUploadResponseList();
if (receiveMessageError(res)) {
sonnerMessage.error(res?.data?.message);
@ -184,7 +225,15 @@ export const useSendAgentMessage = (url?: string) => {
// refetch(); // pull the message list after sending the message successfully
}
},
[agentId, send, inputs, setValue, removeLatestMessage],
[
agentId,
send,
inputs,
uploadResponseList,
setValue,
removeLatestMessage,
clearUploadResponseList,
],
);
const sendFormMessage = useCallback(
@ -243,16 +292,17 @@ export const useSendAgentMessage = (url?: string) => {
}, [addEventList, answerList]);
return {
handlePressEnter,
handleInputChange,
value,
sendLoading: !done,
derivedMessages,
ref,
handlePressEnter,
handleInputChange,
removeMessageById,
stopOutputMessage,
send,
sendFormMessage,
findReferenceByMessageId,
appendUploadResponseList,
};
};

View File

@ -150,7 +150,8 @@ function AgentForm({ node }: INextOperatorForm) {
<FormContainer>
<QueryVariable
name="visual_files_var"
label="Visual files var"
label="Visual Input File"
type={VariableType.File}
></QueryVariable>
<FormField
control={form.control}