import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg'; import { MessageType } from '@/constants/chat'; import { IMessage, IReference, IReferenceChunk, UploadResponseDataType, } from '@/interfaces/database/chat'; import classNames from 'classnames'; import { memo, useCallback, useMemo } from 'react'; import { IRegenerateMessage, IRemoveMessageById } from '@/hooks/logic-hooks'; import { cn } from '@/lib/utils'; import MarkdownContent from '../markdown-content'; import { ReferenceDocumentList } from '../next-message-item/reference-document-list'; import { UploadedMessageFiles } from '../next-message-item/uploaded-message-files'; import { PDFDownloadButton, extractPDFDownloadInfo, removePDFDownloadInfo, } from '../pdf-download-button'; import { RAGFlowAvatar } from '../ragflow-avatar'; import { useTheme } from '../theme-provider'; import { AssistantGroupButton, UserGroupButton } from './group-button'; import styles from './index.less'; interface IProps extends Partial, IRegenerateMessage { item: IMessage; reference: IReference; loading?: boolean; sendLoading?: boolean; visibleAvatar?: boolean; nickname?: string; avatar?: string; avatarDialog?: string | null; clickDocumentButton?: (documentId: string, chunk: IReferenceChunk) => void; index: number; showLikeButton?: boolean; showLoudspeaker?: boolean; } const MessageItem = ({ item, reference, loading = false, avatar, avatarDialog, sendLoading = false, clickDocumentButton, index, removeMessageById, regenerateMessage, showLikeButton = true, showLoudspeaker = true, visibleAvatar = true, }: IProps) => { const { theme } = useTheme(); const isAssistant = item.role === MessageType.Assistant; const isUser = item.role === MessageType.User; const uploadedFiles = useMemo(() => { return item?.files ?? []; }, [item?.files]); const referenceDocumentList = useMemo(() => { return reference?.doc_aggs ?? []; }, [reference?.doc_aggs]); // Extract PDF download info from message content const pdfDownloadInfo = useMemo( () => extractPDFDownloadInfo(item.content), [item.content], ); // If we have PDF download info, extract the remaining text const messageContent = useMemo(() => { if (!pdfDownloadInfo) return item.content; // Remove the JSON part from the content to avoid showing it return removePDFDownloadInfo(item.content, pdfDownloadInfo); }, [item.content, pdfDownloadInfo]); const handleRegenerateMessage = useCallback(() => { regenerateMessage?.(item); }, [regenerateMessage, item]); return (
{visibleAvatar && (item.role === MessageType.User ? ( ) : avatarDialog ? ( ) : ( ))}
{isAssistant ? ( index !== 0 && ( ) ) : ( )} {/* Show PDF download button if download info is present */} {pdfDownloadInfo && ( )} {/* Show message content if there's any text besides the download */} {messageContent && (
)} {isAssistant && referenceDocumentList.length > 0 && ( )} {isUser && Array.isArray(uploadedFiles) && uploadedFiles.length > 0 && ( )}
); }; export default memo(MessageItem);