From 71ac65960a1bbf27ea9188a76a4fe50b9d8e1fb1 Mon Sep 17 00:00:00 2001 From: billchen Date: Tue, 27 Feb 2024 16:20:00 +0800 Subject: [PATCH] feat: add message popover content --- web/src/components/new-document-link.tsx | 20 +++ web/src/interfaces/database/chat.ts | 2 +- .../components/chunk-card/index.tsx | 6 - .../testing-result/select-files.tsx | 10 +- web/src/pages/add-knowledge/index.tsx | 10 +- web/src/pages/chat/chat-container/index.less | 8 ++ web/src/pages/chat/chat-container/index.tsx | 117 ++++++++++++++---- web/src/utils/request.ts | 1 - 8 files changed, 131 insertions(+), 43 deletions(-) create mode 100644 web/src/components/new-document-link.tsx diff --git a/web/src/components/new-document-link.tsx b/web/src/components/new-document-link.tsx new file mode 100644 index 000000000..84c0c9378 --- /dev/null +++ b/web/src/components/new-document-link.tsx @@ -0,0 +1,20 @@ +import { api_host } from '@/utils/api'; +import React from 'react'; + +interface IProps extends React.PropsWithChildren { + documentId: string; +} + +const NewDocumentLink = ({ children, documentId }: IProps) => { + return ( + + {children} + + ); +}; + +export default NewDocumentLink; diff --git a/web/src/interfaces/database/chat.ts b/web/src/interfaces/database/chat.ts index eb4ec51f3..af6b12c90 100644 --- a/web/src/interfaces/database/chat.ts +++ b/web/src/interfaces/database/chat.ts @@ -71,7 +71,7 @@ export interface IReference { total: number; } -interface Docagg { +export interface Docagg { count: number; doc_id: string; doc_name: string; diff --git a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.tsx b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.tsx index 89af5283b..e509ec0cb 100644 --- a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.tsx @@ -1,6 +1,5 @@ import Image from '@/components/image'; import { IChunk } from '@/interfaces/database/knowledge'; -import { api_host } from '@/utils/api'; import { Card, Checkbox, CheckboxProps, Flex, Popover, Switch } from 'antd'; import { useState } from 'react'; import styles from './index.less'; @@ -48,11 +47,6 @@ const ChunkCard = ({ } > - )} diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx index ab5d06c9c..cb80d0175 100644 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx @@ -1,6 +1,6 @@ import { ReactComponent as NavigationPointerIcon } from '@/assets/svg/navigation-pointer.svg'; +import NewDocumentLink from '@/components/new-document-link'; import { ITestingDocument } from '@/interfaces/database/knowledge'; -import { api_host } from '@/utils/api'; import { Table, TableProps } from 'antd'; import { useDispatch, useSelector } from 'umi'; @@ -34,13 +34,9 @@ const SelectFiles = ({ handleTesting }: IProps) => { key: 'view', width: 50, render: (_, { doc_id }) => ( - + - + ), }, ]; diff --git a/web/src/pages/add-knowledge/index.tsx b/web/src/pages/add-knowledge/index.tsx index 370d1150f..ec4ba5df6 100644 --- a/web/src/pages/add-knowledge/index.tsx +++ b/web/src/pages/add-knowledge/index.tsx @@ -2,7 +2,7 @@ import { useKnowledgeBaseId } from '@/hooks/knowledgeHook'; import { useSecondPathName, useThirdPathName } from '@/hooks/routeHook'; import { Breadcrumb } from 'antd'; import { ItemType } from 'antd/es/breadcrumb/Breadcrumb'; -import { useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo } from 'react'; import { Link, Outlet, useDispatch, useLocation, useNavigate } from 'umi'; import Siderbar from './components/knowledge-sidebar'; import { @@ -25,9 +25,9 @@ const KnowledgeAdding = () => { const datasetActiveKey: KnowledgeDatasetRouteKey = useThirdPathName() as KnowledgeDatasetRouteKey; - const gotoList = () => { + const gotoList = useCallback(() => { navigate('/knowledge'); - }; + }, [navigate]); const breadcrumbItems: ItemType[] = useMemo(() => { const items: ItemType[] = [ @@ -54,7 +54,7 @@ const KnowledgeAdding = () => { } return items; - }, [activeKey, datasetActiveKey]); + }, [activeKey, datasetActiveKey, gotoList, knowledgeBaseId]); useEffect(() => { const search: string = location.search.slice(1); @@ -71,7 +71,7 @@ const KnowledgeAdding = () => { ...map, }, }); - }, [location]); + }, [location, dispatch]); return ( <> diff --git a/web/src/pages/chat/chat-container/index.less b/web/src/pages/chat/chat-container/index.less index c0ce04b55..1eba20a51 100644 --- a/web/src/pages/chat/chat-container/index.less +++ b/web/src/pages/chat/chat-container/index.less @@ -39,3 +39,11 @@ .messageItemRight { text-align: right; } + +.referencePopoverWrapper { + width: 50vw; +} + +.referenceChunkImage { + width: 10vw; +} diff --git a/web/src/pages/chat/chat-container/index.tsx b/web/src/pages/chat/chat-container/index.tsx index 31d939ff5..4f702b80d 100644 --- a/web/src/pages/chat/chat-container/index.tsx +++ b/web/src/pages/chat/chat-container/index.tsx @@ -3,18 +3,33 @@ 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, Popover } from 'antd'; +import { + Avatar, + Button, + Flex, + Input, + List, + Popover, + Space, + Typography, +} from 'antd'; import classNames from 'classnames'; import { ChangeEventHandler, useCallback, useMemo, useState } from 'react'; import reactStringReplace from 'react-string-replace'; import { useFetchConversation, useSendMessage } from '../hooks'; import { IClientConversation } from '../interface'; +import Image from '@/components/image'; +import NewDocumentLink from '@/components/new-document-link'; 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) => { @@ -28,32 +43,67 @@ const rehypeWrapReference = () => { }; }; -const MessageItem = ({ item }: { item: Message; references: IReference[] }) => { +const MessageItem = ({ + item, + reference, +}: { + item: Message; + reference: IReference; +}) => { const userInfo = useSelectUserInfo(); - const popoverContent = useMemo( - () => ( -
-

Content

-

Content

-
- ), - [], + 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 ( + + + +
{chunkItem.content_with_weight}
+ {documentId && ( + + {document?.doc_name} + + )} +
+
+ ); + }, + [reference], ); const renderReference = useCallback( (text: string) => { - return reactStringReplace(text, /#{2}\d{1,}\${2}/g, (match, i) => { + return reactStringReplace(text, reg, (match, i) => { + const chunkIndex = getChunkIndex(match); return ( - + ); }); }, - [popoverContent], + [getPopoverContent], ); + const referenceDocumentList = useMemo(() => { + return reference?.doc_aggs ?? []; + }, [reference?.doc_aggs]); + return (
{ )} - - {item.role === MessageType.Assistant ? 'Resume Assistant' : 'You'} - + {isAssistant ? 'Resume Assistant' : 'You'}
{ {item.content}
+ {isAssistant && referenceDocumentList.length > 0 && ( + ( + + [ITEM] + + {item.doc_name} + + + )} + /> + )}
@@ -131,13 +193,22 @@ const ChatContainer = () => {
- {conversation?.message?.map((message) => ( - - ))} + {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 ( + + ); + })}
{ * */ request.interceptors.response.use(async (response: any, request) => { - console.log(response, request); const data: ResponseType = await response.clone().json(); // response 拦截