- import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg';
- import { MessageType } from '@/constants/chat';
- import { useSetModalState } from '@/hooks/common-hooks';
- import { IReference } from '@/interfaces/database/chat';
- import { IChunk } from '@/interfaces/database/knowledge';
- import classNames from 'classnames';
- import { memo, useCallback, useEffect, useMemo, useState } from 'react';
-
- import {
- useFetchDocumentInfosByIds,
- useFetchDocumentThumbnailsByIds,
- } from '@/hooks/document-hooks';
- import { IRegenerateMessage, IRemoveMessageById } from '@/hooks/logic-hooks';
- import { IMessage } from '@/pages/chat/interface';
- import MarkdownContent from '@/pages/chat/markdown-content';
- import { getExtension, isImage } from '@/utils/document-util';
- import { Avatar, Button, Flex, List, Space, Typography } from 'antd';
- import FileIcon from '../file-icon';
- import IndentedTreeModal from '../indented-tree/modal';
- import NewDocumentLink from '../new-document-link';
- import { AssistantGroupButton, UserGroupButton } from './group-button';
- import styles from './index.less';
-
- const { Text } = Typography;
-
- interface IProps extends Partial<IRemoveMessageById>, IRegenerateMessage {
- item: IMessage;
- reference: IReference;
- loading?: boolean;
- sendLoading?: boolean;
- nickname?: string;
- avatar?: string;
- clickDocumentButton?: (documentId: string, chunk: IChunk) => void;
- index: number;
- showLikeButton?: boolean;
- }
-
- const MessageItem = ({
- item,
- reference,
- loading = false,
- avatar = '',
- sendLoading = false,
- clickDocumentButton,
- index,
- removeMessageById,
- regenerateMessage,
- showLikeButton = true,
- }: IProps) => {
- const isAssistant = item.role === MessageType.Assistant;
- const isUser = item.role === MessageType.User;
- const { data: documentList, setDocumentIds } = useFetchDocumentInfosByIds();
- const { data: documentThumbnails, setDocumentIds: setIds } =
- useFetchDocumentThumbnailsByIds();
- const { visible, hideModal, showModal } = useSetModalState();
- const [clickedDocumentId, setClickedDocumentId] = useState('');
-
- const referenceDocumentList = useMemo(() => {
- return reference?.doc_aggs ?? [];
- }, [reference?.doc_aggs]);
-
- const handleUserDocumentClick = useCallback(
- (id: string) => () => {
- setClickedDocumentId(id);
- showModal();
- },
- [showModal],
- );
-
- const handleRegenerateMessage = useCallback(() => {
- regenerateMessage?.(item);
- }, [regenerateMessage, item]);
-
- useEffect(() => {
- const ids = item?.doc_ids ?? [];
- if (ids.length) {
- setDocumentIds(ids);
- const documentIds = ids.filter((x) => !(x in documentThumbnails));
- if (documentIds.length) {
- setIds(documentIds);
- }
- }
- }, [item.doc_ids, setDocumentIds, setIds, documentThumbnails]);
-
- return (
- <div
- className={classNames(styles.messageItem, {
- [styles.messageItemLeft]: item.role === MessageType.Assistant,
- [styles.messageItemRight]: item.role === MessageType.User,
- })}
- >
- <section
- className={classNames(styles.messageItemSection, {
- [styles.messageItemSectionLeft]: item.role === MessageType.Assistant,
- [styles.messageItemSectionRight]: item.role === MessageType.User,
- })}
- >
- <div
- className={classNames(styles.messageItemContent, {
- [styles.messageItemContentReverse]: item.role === MessageType.User,
- })}
- >
- {item.role === MessageType.User ? (
- <Avatar
- size={40}
- src={
- avatar ??
- 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'
- }
- />
- ) : (
- <AssistantIcon></AssistantIcon>
- )}
- <Flex vertical gap={8} flex={1}>
- <Space>
- {isAssistant ? (
- index !== 0 && (
- <AssistantGroupButton
- messageId={item.id}
- content={item.content}
- prompt={item.prompt}
- showLikeButton={showLikeButton}
- audioBinary={item.audio_binary}
- ></AssistantGroupButton>
- )
- ) : (
- <UserGroupButton
- content={item.content}
- messageId={item.id}
- removeMessageById={removeMessageById}
- regenerateMessage={
- regenerateMessage && handleRegenerateMessage
- }
- sendLoading={sendLoading}
- ></UserGroupButton>
- )}
-
- {/* <b>{isAssistant ? '' : nickname}</b> */}
- </Space>
- <div
- className={
- isAssistant ? styles.messageText : styles.messageUserText
- }
- >
- <MarkdownContent
- loading={loading}
- content={item.content}
- reference={reference}
- clickDocumentButton={clickDocumentButton}
- ></MarkdownContent>
- </div>
- {isAssistant && referenceDocumentList.length > 0 && (
- <List
- bordered
- dataSource={referenceDocumentList}
- renderItem={(item) => {
- return (
- <List.Item>
- <Flex gap={'small'} align="center">
- <FileIcon
- id={item.doc_id}
- name={item.doc_name}
- ></FileIcon>
-
- <NewDocumentLink
- documentId={item.doc_id}
- documentName={item.doc_name}
- prefix="document"
- >
- {item.doc_name}
- </NewDocumentLink>
- </Flex>
- </List.Item>
- );
- }}
- />
- )}
- {isUser && documentList.length > 0 && (
- <List
- bordered
- dataSource={documentList}
- renderItem={(item) => {
- // TODO:
- const fileThumbnail =
- documentThumbnails[item.id] || documentThumbnails[item.id];
- const fileExtension = getExtension(item.name);
- return (
- <List.Item>
- <Flex gap={'small'} align="center">
- <FileIcon id={item.id} name={item.name}></FileIcon>
-
- {isImage(fileExtension) ? (
- <NewDocumentLink
- documentId={item.id}
- documentName={item.name}
- prefix="document"
- >
- {item.name}
- </NewDocumentLink>
- ) : (
- <Button
- type={'text'}
- onClick={handleUserDocumentClick(item.id)}
- >
- <Text
- style={{ maxWidth: '40vw' }}
- ellipsis={{ tooltip: item.name }}
- >
- {item.name}
- </Text>
- </Button>
- )}
- </Flex>
- </List.Item>
- );
- }}
- />
- )}
- </Flex>
- </div>
- </section>
- {visible && (
- <IndentedTreeModal
- visible={visible}
- hideModal={hideModal}
- documentId={clickedDocumentId}
- ></IndentedTreeModal>
- )}
- </div>
- );
- };
-
- export default memo(MessageItem);
|