From 996b5fe14ec40ac56deb4021111341f941862581 Mon Sep 17 00:00:00 2001 From: chanx <1243304602@qq.com> Date: Fri, 14 Nov 2025 19:50:01 +0800 Subject: [PATCH] Fix: Added the ability to download files in the agent message reply function. (#11281) ### What problem does this PR solve? Fix: Added the ability to download files in the agent message reply function. ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue) --- .../components/next-message-item/index.tsx | 30 +++++++++++++- web/src/hooks/use-send-message.ts | 7 +++- web/src/interfaces/database/chat.ts | 3 ++ web/src/locales/en.ts | 2 + web/src/locales/zh.ts | 2 + .../agent/chat/use-send-agent-message.ts | 8 +++- web/src/pages/agent/constant/index.tsx | 8 ++++ .../pages/agent/form/message-form/index.tsx | 41 ++++++++++++++++++- .../agent/form/message-form/use-values.ts | 3 +- web/src/services/file-manager-service.ts | 7 ++++ web/src/utils/api.ts | 2 + 11 files changed, 108 insertions(+), 5 deletions(-) diff --git a/web/src/components/next-message-item/index.tsx b/web/src/components/next-message-item/index.tsx index 5dd6cdf60..706553b67 100644 --- a/web/src/components/next-message-item/index.tsx +++ b/web/src/components/next-message-item/index.tsx @@ -18,8 +18,10 @@ import { cn } from '@/lib/utils'; import { AgentChatContext } from '@/pages/agent/context'; import { WorkFlowTimeline } from '@/pages/agent/log-sheet/workflow-timeline'; import { IMessage } from '@/pages/chat/interface'; +import { downloadFile } from '@/services/file-manager-service'; +import { downloadFileFromBlob } from '@/utils/file-util'; import { isEmpty } from 'lodash'; -import { Atom, ChevronDown, ChevronUp } from 'lucide-react'; +import { Atom, ChevronDown, ChevronUp, Download } from 'lucide-react'; import MarkdownContent from '../next-markdown-content'; import { RAGFlowAvatar } from '../ragflow-avatar'; import { useTheme } from '../theme-provider'; @@ -245,6 +247,32 @@ function MessageItem({ {isUser && ( )} + {isAssistant && item.attachment && item.attachment.doc_id && ( +
+ +
+ )} diff --git a/web/src/hooks/use-send-message.ts b/web/src/hooks/use-send-message.ts index 8d602f2e0..e956217f3 100644 --- a/web/src/hooks/use-send-message.ts +++ b/web/src/hooks/use-send-message.ts @@ -44,9 +44,14 @@ export interface IInputData { inputs: Record; tips: string; } - +export interface IAttachment { + doc_id: string; + format: string; + file_name: string; +} export interface IMessageData { content: string; + outputs: any; start_to_think?: boolean; end_to_think?: boolean; } diff --git a/web/src/interfaces/database/chat.ts b/web/src/interfaces/database/chat.ts index 62bcb4696..eb6eebe89 100644 --- a/web/src/interfaces/database/chat.ts +++ b/web/src/interfaces/database/chat.ts @@ -1,4 +1,5 @@ import { MessageType } from '@/constants/chat'; +import { IAttachment } from '@/hooks/use-send-message'; export interface PromptConfig { empty_response: string; @@ -97,6 +98,7 @@ export interface Message { data?: any; files?: File[]; chatBoxId?: string; + attachment?: IAttachment; } export interface IReferenceChunk { @@ -126,6 +128,7 @@ export interface IReferenceObject { export interface IAnswer { answer: string; + attachment?: IAttachment; reference?: IReference; conversationId?: string; prompt?: string; diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index b9f374f7c..e2035a378 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -1009,6 +1009,8 @@ Example: general/v2/`, pleaseUploadAtLeastOneFile: 'Please upload at least one file', }, flow: { + downloadFileTypeTip: 'The file type to download', + downloadFileType: 'Download file type', formatTypeError: 'Format or type error', variableNameMessage: 'Variable name can only contain letters and underscores', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index ce21c5a30..301719117 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -956,6 +956,8 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 pleaseUploadAtLeastOneFile: '请上传至少一个文件', }, flow: { + downloadFileTypeTip: '文件下载的类型', + downloadFileType: '文件类型', formatTypeError: '格式或类型错误', variableNameMessage: '名称只能包含字母和下划线', variableDescription: '变量的描述', diff --git a/web/src/pages/agent/chat/use-send-agent-message.ts b/web/src/pages/agent/chat/use-send-agent-message.ts index a0460fd71..5fc49d4ce 100644 --- a/web/src/pages/agent/chat/use-send-agent-message.ts +++ b/web/src/pages/agent/chat/use-send-agent-message.ts @@ -5,6 +5,7 @@ import { useSelectDerivedMessages, } from '@/hooks/logic-hooks'; import { + IAttachment, IEventList, IInputEvent, IMessageEndData, @@ -75,9 +76,13 @@ export function findMessageFromList(eventList: IEventList) { nextContent += ''; } + const workflowFinished = eventList.find( + (x) => x.event === MessageEventType.WorkflowFinished, + ) as IMessageEvent; return { id: eventList[0]?.message_id, content: nextContent, + attachment: workflowFinished?.data?.outputs?.attachment || {}, }; } @@ -388,12 +393,13 @@ export const useSendAgentMessage = ({ }, [sendMessageInTaskMode]); useEffect(() => { - const { content, id } = findMessageFromList(answerList); + const { content, id, attachment } = findMessageFromList(answerList); const inputAnswer = findInputFromList(answerList); const answer = content || getLatestError(answerList); if (answerList.length > 0) { addNewestOneAnswer({ answer: answer ?? '', + attachment: attachment as IAttachment, id: id, ...inputAnswer, }); diff --git a/web/src/pages/agent/constant/index.tsx b/web/src/pages/agent/constant/index.tsx index 7aad5e4a3..3a161d87d 100644 --- a/web/src/pages/agent/constant/index.tsx +++ b/web/src/pages/agent/constant/index.tsx @@ -417,6 +417,7 @@ export const initialIterationValues = { items_ref: '', outputs: {}, }; + export const initialIterationStartValues = { outputs: { item: { @@ -845,3 +846,10 @@ export enum JsonSchemaDataType { Array = 'array', Object = 'object', } + +export enum ExportFileType { + PDF = 'pdf', + HTML = 'html', + Markdown = 'md', + DOCX = 'docx', +} diff --git a/web/src/pages/agent/form/message-form/index.tsx b/web/src/pages/agent/form/message-form/index.tsx index e93735ee7..31b52659e 100644 --- a/web/src/pages/agent/form/message-form/index.tsx +++ b/web/src/pages/agent/form/message-form/index.tsx @@ -8,12 +8,14 @@ import { FormLabel, FormMessage, } from '@/components/ui/form'; +import { RAGFlowSelect } from '@/components/ui/select'; import { zodResolver } from '@hookform/resolvers/zod'; import { X } from 'lucide-react'; import { memo } from 'react'; import { useFieldArray, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { z } from 'zod'; +import { ExportFileType } from '../../constant'; import { INextOperatorForm } from '../../interface'; import { FormWrapper } from '../components/form-wrapper'; import { PromptEditor } from '../components/prompt-editor'; @@ -33,10 +35,14 @@ function MessageForm({ node }: INextOperatorForm) { }), ) .optional(), + output_format: z.string().optional(), }); const form = useForm({ - defaultValues: values, + defaultValues: { + ...values, + output_format: values.output_format, + }, resolver: zodResolver(FormSchema), }); @@ -50,6 +56,39 @@ function MessageForm({ node }: INextOperatorForm) { return (
+ + + + {t('flow.downloadFileType')} + + ( + + + { + return { + value: + ExportFileType[ + key as keyof typeof ExportFileType + ], + label: key, + }; + }, + )} + {...field} + onValueChange={field.onChange} + placeholder={t('flow.messagePlaceholder')} + > + + + )} + /> + + {t('flow.msg')} diff --git a/web/src/pages/agent/form/message-form/use-values.ts b/web/src/pages/agent/form/message-form/use-values.ts index 6a90881be..0cece91fc 100644 --- a/web/src/pages/agent/form/message-form/use-values.ts +++ b/web/src/pages/agent/form/message-form/use-values.ts @@ -1,7 +1,7 @@ import { RAGFlowNodeType } from '@/interfaces/database/flow'; import { isEmpty } from 'lodash'; import { useMemo } from 'react'; -import { initialMessageValues } from '../../constant'; +import { ExportFileType, initialMessageValues } from '../../constant'; import { convertToObjectArray } from '../../utils'; export function useValues(node?: RAGFlowNodeType) { @@ -15,6 +15,7 @@ export function useValues(node?: RAGFlowNodeType) { return { ...formData, content: convertToObjectArray(formData.content), + output_format: formData.output_format || ExportFileType.PDF, }; }, [node]); diff --git a/web/src/services/file-manager-service.ts b/web/src/services/file-manager-service.ts index 8342117c9..8c5eb6c4e 100644 --- a/web/src/services/file-manager-service.ts +++ b/web/src/services/file-manager-service.ts @@ -13,6 +13,7 @@ const { get_document_file, getFile, moveFile, + get_document_file_download, } = api; const methods = { @@ -65,4 +66,10 @@ const fileManagerService = registerServer( request, ); +export const downloadFile = (data: { docId: string; ext: string }) => { + return request.get(get_document_file_download(data.docId), { + params: { ext: data.ext }, + responseType: 'blob', + }); +}; export default fileManagerService; diff --git a/web/src/utils/api.ts b/web/src/utils/api.ts index e0afdbeb3..c4ce8205f 100644 --- a/web/src/utils/api.ts +++ b/web/src/utils/api.ts @@ -100,6 +100,8 @@ export default { document_change_parser: `${api_host}/document/change_parser`, document_thumbnails: `${api_host}/document/thumbnails`, get_document_file: `${api_host}/document/get`, + get_document_file_download: (docId: string) => + `${api_host}/document/download/${docId}`, document_upload: `${api_host}/document/upload`, web_crawl: `${api_host}/document/web_crawl`, document_infos: `${api_host}/document/infos`,