- import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg';
 - import { MessageType } from '@/constants/chat';
 - import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
 - import { useSelectUserInfo } from '@/hooks/userSettingHook';
 - import { IReference, Message } from '@/interfaces/database/chat';
 - import { Avatar, Button, Flex, Input, List, Popover, Space } from 'antd';
 - import classNames from 'classnames';
 - import { ChangeEventHandler, useCallback, useMemo, useState } from 'react';
 - import reactStringReplace from 'react-string-replace';
 - import {
 -   useFetchConversationOnMount,
 -   useGetFileIcon,
 -   useSendMessage,
 - } from '../hooks';
 - 
 - import Image from '@/components/image';
 - import NewDocumentLink from '@/components/new-document-link';
 - import { useSelectFileThumbnails } from '@/hooks/knowledgeHook';
 - import { InfoCircleOutlined } from '@ant-design/icons';
 - import Markdown from 'react-markdown';
 - import { visitParents } from 'unist-util-visit-parents';
 - import styles from './index.less';
 - 
 - const reg = /(#{2}\d+\${2})/g;
 - 
 - const getChunkIndex = (match: string) => Number(match.slice(2, 3));
 - 
 - const rehypeWrapReference = () => {
 -   return function wrapTextTransform(tree: any) {
 -     visitParents(tree, 'text', (node, ancestors) => {
 -       if (ancestors.at(-1).tagName !== 'custom-typography') {
 -         node.type = 'element';
 -         node.tagName = 'custom-typography';
 -         node.properties = {};
 -         node.children = [{ type: 'text', value: node.value }];
 -       }
 -     });
 -   };
 - };
 - 
 - const MessageItem = ({
 -   item,
 -   reference,
 - }: {
 -   item: Message;
 -   reference: IReference;
 - }) => {
 -   const userInfo = useSelectUserInfo();
 -   const fileThumbnails = useSelectFileThumbnails();
 - 
 -   const isAssistant = item.role === MessageType.Assistant;
 - 
 -   const getPopoverContent = useCallback(
 -     (chunkIndex: number) => {
 -       const chunks = reference?.chunks ?? [];
 -       const chunkItem = chunks[chunkIndex];
 -       const document = reference?.doc_aggs.find(
 -         (x) => x?.doc_id === chunkItem?.doc_id,
 -       );
 -       const documentId = document?.doc_id;
 -       return (
 -         <Flex
 -           key={chunkItem?.chunk_id}
 -           gap={10}
 -           className={styles.referencePopoverWrapper}
 -         >
 -           <Popover
 -             placement="topRight"
 -             content={
 -               <Image
 -                 id={chunkItem?.img_id}
 -                 className={styles.referenceImagePreview}
 -               ></Image>
 -             }
 -           >
 -             <Image
 -               id={chunkItem?.img_id}
 -               className={styles.referenceChunkImage}
 -             ></Image>
 -           </Popover>
 -           <Space direction={'vertical'}>
 -             <div>{chunkItem?.content_with_weight}</div>
 -             {documentId && (
 -               <Flex gap={'middle'}>
 -                 <img src={fileThumbnails[documentId]} alt="" />
 -                 <NewDocumentLink documentId={documentId}>
 -                   {document?.doc_name}
 -                 </NewDocumentLink>
 -               </Flex>
 -             )}
 -           </Space>
 -         </Flex>
 -       );
 -     },
 -     [reference, fileThumbnails],
 -   );
 - 
 -   const renderReference = useCallback(
 -     (text: string) => {
 -       return reactStringReplace(text, reg, (match, i) => {
 -         const chunkIndex = getChunkIndex(match);
 -         return (
 -           <Popover content={getPopoverContent(chunkIndex)}>
 -             <InfoCircleOutlined key={i} className={styles.referenceIcon} />
 -           </Popover>
 -         );
 -       });
 -     },
 -     [getPopoverContent],
 -   );
 - 
 -   const referenceDocumentList = useMemo(() => {
 -     return reference?.doc_aggs ?? [];
 -   }, [reference?.doc_aggs]);
 - 
 -   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 ? (
 -             userInfo.avatar ?? (
 -               <Avatar
 -                 size={40}
 -                 src={
 -                   userInfo.avatar ??
 -                   'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'
 -                 }
 -               />
 -             )
 -           ) : (
 -             <AssistantIcon></AssistantIcon>
 -           )}
 -           <Flex vertical gap={8} flex={1}>
 -             <b>{isAssistant ? '' : userInfo.nickname}</b>
 -             <div className={styles.messageText}>
 -               <Markdown
 -                 rehypePlugins={[rehypeWrapReference]}
 -                 components={
 -                   {
 -                     'custom-typography': ({ children }: { children: string }) =>
 -                       renderReference(children),
 -                   } as any
 -                 }
 -               >
 -                 {item.content}
 -               </Markdown>
 -             </div>
 -             {isAssistant && referenceDocumentList.length > 0 && (
 -               <List
 -                 bordered
 -                 dataSource={referenceDocumentList}
 -                 renderItem={(item) => (
 -                   <List.Item>
 -                     {/* <SvgIcon name={getFileIcon(item.doc_name)}></SvgIcon> */}
 -                     <Flex gap={'middle'}>
 -                       <img src={fileThumbnails[item.doc_id]}></img>
 -                       <NewDocumentLink documentId={item.doc_id}>
 -                         {item.doc_name}
 -                       </NewDocumentLink>
 -                     </Flex>
 -                   </List.Item>
 -                 )}
 -               />
 -             )}
 -           </Flex>
 -         </div>
 -       </section>
 -     </div>
 -   );
 - };
 - 
 - const ChatContainer = () => {
 -   const [value, setValue] = useState('');
 -   const {
 -     ref,
 -     currentConversation: conversation,
 -     addNewestConversation,
 -   } = useFetchConversationOnMount();
 -   const { sendMessage } = useSendMessage();
 - 
 -   const loading = useOneNamespaceEffectsLoading('chatModel', [
 -     'completeConversation',
 -   ]);
 -   useGetFileIcon();
 - 
 -   const handlePressEnter = () => {
 -     if (!loading) {
 -       setValue('');
 -       addNewestConversation(value);
 -       sendMessage(value);
 -     }
 -   };
 - 
 -   const handleInputChange: ChangeEventHandler<HTMLInputElement> = (e) => {
 -     setValue(e.target.value);
 -   };
 - 
 -   return (
 -     <Flex flex={1} className={styles.chatContainer} vertical>
 -       <Flex flex={1} vertical className={styles.messageContainer}>
 -         <div>
 -           {conversation?.message?.map((message) => {
 -             const assistantMessages = conversation?.message
 -               ?.filter((x) => x.role === MessageType.Assistant)
 -               .slice(1);
 -             const referenceIndex = assistantMessages.findIndex(
 -               (x) => x.id === message.id,
 -             );
 -             const reference = conversation.reference[referenceIndex];
 -             return (
 -               <MessageItem
 -                 key={message.id}
 -                 item={message}
 -                 reference={reference}
 -               ></MessageItem>
 -             );
 -           })}
 -         </div>
 -         <div ref={ref} />
 -       </Flex>
 -       <Input
 -         size="large"
 -         placeholder="Message Resume Assistant..."
 -         value={value}
 -         suffix={
 -           <Button type="primary" onClick={handlePressEnter} loading={loading}>
 -             Send
 -           </Button>
 -         }
 -         onPressEnter={handlePressEnter}
 -         onChange={handleInputChange}
 -       />
 -     </Flex>
 -   );
 - };
 - 
 - export default ChatContainer;
 
 
  |