feat: Add RetrievalDocuments to SearchPage #2247 (#2327)

### What problem does this PR solve?
feat: Add RetrievalDocuments to SearchPage #2247
feat: Click on the link in the reference to display the pdf drawer #2247

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2024-09-09 19:20:16 +08:00
committed by GitHub
parent 7241c73c7a
commit 42eeb38247
14 changed files with 390 additions and 143 deletions

View File

@@ -1,9 +1,7 @@
import MessageItem from '@/components/message-item';
import DocumentPreviewer from '@/components/pdf-previewer';
import { MessageType } from '@/constants/chat';
import { Drawer, Flex, Spin } from 'antd';
import { Flex, Spin } from 'antd';
import {
useClickDrawer,
useCreateConversationBeforeUploadDocument,
useGetFileIcon,
useGetSendButtonDisabled,
@@ -13,6 +11,8 @@ import {
import { buildMessageItemReference } from '../utils';
import MessageInput from '@/components/message-input';
import PdfDrawer from '@/components/pdf-drawer';
import { useClickDrawer } from '@/components/pdf-drawer/hooks';
import {
useFetchNextConversation,
useGetChatSearchParams,
@@ -96,18 +96,12 @@ const ChatContainer = () => {
}
></MessageInput>
</Flex>
<Drawer
title="Document Previewer"
onClose={hideModal}
open={visible}
width={'50vw'}
>
<DocumentPreviewer
documentId={documentId}
chunk={selectedChunk}
visible={visible}
></DocumentPreviewer>
</Drawer>
<PdfDrawer
visible={visible}
hideModal={hideModal}
documentId={documentId}
chunk={selectedChunk}
></PdfDrawer>
</>
);
};

View File

@@ -23,7 +23,6 @@ import {
useSendMessageWithSse,
} from '@/hooks/logic-hooks';
import { IConversation, IDialog, Message } from '@/interfaces/database/chat';
import { IChunk } from '@/interfaces/database/knowledge';
import { getFileExtension } from '@/utils';
import { useMutationState } from '@tanstack/react-query';
import { get } from 'lodash';
@@ -545,30 +544,6 @@ export const useRenameConversation = () => {
};
};
export const useClickDrawer = () => {
const { visible, showModal, hideModal } = useSetModalState();
const [selectedChunk, setSelectedChunk] = useState<IChunk>({} as IChunk);
const [documentId, setDocumentId] = useState<string>('');
const clickDocumentButton = useCallback(
(documentId: string, chunk: IChunk) => {
showModal();
setSelectedChunk(chunk);
setDocumentId(documentId);
},
[showModal],
);
return {
clickDocumentButton,
visible,
showModal,
hideModal,
selectedChunk,
documentId,
};
};
export const useGetSendButtonDisabled = () => {
const { dialogId, conversationId } = useGetChatSearchParams();

View File

@@ -1,13 +1,14 @@
import MessageItem from '@/components/message-item';
import DocumentPreviewer from '@/components/pdf-previewer';
import { MessageType } from '@/constants/chat';
import { useTranslate } from '@/hooks/common-hooks';
import { useClickDrawer, useGetFileIcon } from '@/pages/chat/hooks';
import { useGetFileIcon } from '@/pages/chat/hooks';
import { buildMessageItemReference } from '@/pages/chat/utils';
import { Button, Drawer, Flex, Input, Spin } from 'antd';
import { Button, Flex, Input, Spin } from 'antd';
import { useSendNextMessage } from './hooks';
import PdfDrawer from '@/components/pdf-drawer';
import { useClickDrawer } from '@/components/pdf-drawer/hooks';
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
import styles from './index.less';
@@ -79,19 +80,12 @@ const FlowChatBox = () => {
onChange={handleInputChange}
/>
</Flex>
<Drawer
title="Document Previewer"
onClose={hideModal}
open={visible}
width={'50vw'}
mask={false}
>
<DocumentPreviewer
documentId={documentId}
chunk={selectedChunk}
visible={visible}
></DocumentPreviewer>
</Drawer>
<PdfDrawer
visible={visible}
hideModal={hideModal}
documentId={documentId}
chunk={selectedChunk}
></PdfDrawer>
</>
);
};

View File

@@ -46,10 +46,27 @@ export const useSendQuestion = (kbIds: string[]) => {
const handleClickRelatedQuestion = useCallback(
(question: string) => () => {
if (sendingLoading) return;
setSearchStr(question);
sendQuestion(question);
},
[sendQuestion],
[sendQuestion, sendingLoading],
);
const handleTestChunk = useCallback(
(documentIds: string[]) => {
const q = trim(searchStr);
if (sendingLoading || isEmpty(q)) return;
testChunk({
kb_id: kbIds,
highlight: true,
question: q,
doc_ids: Array.isArray(documentIds) ? documentIds : [],
});
},
[sendingLoading, searchStr, kbIds, testChunk],
);
useEffect(() => {
@@ -71,6 +88,7 @@ export const useSendQuestion = (kbIds: string[]) => {
sendQuestion,
handleSearchStrChange,
handleClickRelatedQuestion,
handleTestChunk,
loading,
sendingLoading,
answer: currentAnswer,

View File

@@ -51,6 +51,9 @@
.firstRenderContent {
height: 100%;
background-image: url(https://www.bing.com/th?id=OHR.IguazuRainbow_ZH-CN6524347982_1920x1080.webp&qlt=50);
background-position: center;
background-size: cover;
}
.content {
@@ -79,10 +82,13 @@
.input() {
:global(.ant-input-affix-wrapper) {
padding: 4px 8px;
padding: 4px 12px;
border-start-start-radius: 30px !important;
border-end-start-radius: 30px !important;
}
:global(.ant-input-group-addon) {
background-color: transparent;
}
input {
height: 40px;
}
@@ -101,3 +107,35 @@
width: 100%;
.input();
}
.appIcon {
display: inline-block;
vertical-align: middle;
width: 60px;
}
.appName {
vertical-align: middle;
font-family: Inter;
font-size: 40px;
font-style: normal;
font-weight: 600;
line-height: 20px;
background: linear-gradient(to right, #095fab 10%, #25abe8 50%, #57d75b 60%);
background-size: auto auto;
background-clip: border-box;
background-size: 200% auto;
color: #fff;
background-clip: text;
text-fill-color: transparent;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: textclip 1.5s linear infinite;
}
@keyframes textclip {
to {
background-position: 200% center;
}
}

View File

@@ -19,18 +19,26 @@ import MarkdownContent from '../chat/markdown-content';
import { useSendQuestion } from './hooks';
import SearchSidebar from './sidebar';
import PdfDrawer from '@/components/pdf-drawer';
import { useClickDrawer } from '@/components/pdf-drawer/hooks';
import RetrievalDocuments from '@/components/retrieval-documents';
import { useFetchAppConf } from '@/hooks/logic-hooks';
import { useTranslation } from 'react-i18next';
import styles from './index.less';
const { Content } = Layout;
const { Search } = Input;
const SearchPage = () => {
const { t } = useTranslation();
const [checkedList, setCheckedList] = useState<string[]>([]);
const list = useSelectTestingResult();
const appConf = useFetchAppConf();
const {
sendQuestion,
handleClickRelatedQuestion,
handleSearchStrChange,
handleTestChunk,
answer,
sendingLoading,
relatedQuestions,
@@ -40,12 +48,14 @@ const SearchPage = () => {
loading,
isFirstRender,
} = useSendQuestion(checkedList);
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
useClickDrawer();
const InputSearch = (
<Search
value={searchStr}
onChange={handleSearchStrChange}
placeholder="input search text"
placeholder={t('header.search')}
allowClear
enterButton
onSearch={sendQuestion}
@@ -57,88 +67,107 @@ const SearchPage = () => {
);
return (
<Layout className={styles.searchPage}>
<SearchSidebar
checkedList={checkedList}
setCheckedList={setCheckedList}
></SearchSidebar>
<Layout>
<Content>
{isFirstRender ? (
<Flex
justify="center"
align="center"
className={styles.firstRenderContent}
>
{InputSearch}
</Flex>
) : (
<Flex className={styles.content}>
<section className={styles.main}>
{InputSearch}
{answer.answer && (
<div className={styles.answerWrapper}>
<MarkdownContent
loading={sendingLoading}
content={answer.answer}
reference={answer.reference ?? ({} as IReference)}
clickDocumentButton={() => {}}
></MarkdownContent>
</div>
)}
<Divider></Divider>
{list.chunks.length > 0 && (
<List
dataSource={list.chunks}
loading={loading}
renderItem={(item) => (
<List.Item>
<Card className={styles.card}>
<Space>
<ImageWithPopover
id={item.img_id}
></ImageWithPopover>
<HightLightMarkdown>
{item.highlight}
</HightLightMarkdown>
</Space>
</Card>
</List.Item>
)}
/>
)}
{relatedQuestions?.length > 0 && (
<Card>
<Flex wrap="wrap" gap={'10px 0'}>
{relatedQuestions?.map((x, idx) => (
<Tag
key={idx}
className={styles.tag}
onClick={handleClickRelatedQuestion(x)}
>
{x}
</Tag>
))}
</Flex>
</Card>
)}
</section>
<section className={styles.graph}>
{mindMapLoading ? (
<Skeleton active />
) : (
<IndentedTree
data={mindMap}
show
style={{ width: '100%', height: '100%' }}
></IndentedTree>
)}
</section>
</Flex>
)}
</Content>
<>
<Layout className={styles.searchPage}>
<SearchSidebar
checkedList={checkedList}
setCheckedList={setCheckedList}
></SearchSidebar>
<Layout>
<Content>
{isFirstRender ? (
<Flex
justify="center"
align="center"
className={styles.firstRenderContent}
>
<Flex vertical align="center" gap={'large'}>
<Space size={30}>
<img src="/logo.svg" alt="" className={styles.appIcon} />
<span className={styles.appName}>{appConf.appName}</span>
</Space>
{InputSearch}
</Flex>
</Flex>
) : (
<Flex className={styles.content}>
<section className={styles.main}>
{InputSearch}
{answer.answer && (
<div className={styles.answerWrapper}>
<MarkdownContent
loading={sendingLoading}
content={answer.answer}
reference={answer.reference ?? ({} as IReference)}
clickDocumentButton={clickDocumentButton}
></MarkdownContent>
</div>
)}
<Divider></Divider>
<RetrievalDocuments
selectedDocumentIdsLength={0}
onTesting={handleTestChunk}
></RetrievalDocuments>
<Divider></Divider>
{list.chunks.length > 0 && (
<List
dataSource={list.chunks}
loading={loading}
renderItem={(item) => (
<List.Item>
<Card className={styles.card}>
<Space>
<ImageWithPopover
id={item.img_id}
></ImageWithPopover>
<HightLightMarkdown>
{item.highlight}
</HightLightMarkdown>
</Space>
</Card>
</List.Item>
)}
/>
)}
{relatedQuestions?.length > 0 && (
<Card>
<Flex wrap="wrap" gap={'10px 0'}>
{relatedQuestions?.map((x, idx) => (
<Tag
key={idx}
className={styles.tag}
onClick={handleClickRelatedQuestion(x)}
>
{x}
</Tag>
))}
</Flex>
</Card>
)}
</section>
<section className={styles.graph}>
{mindMapLoading ? (
<Skeleton active />
) : (
<IndentedTree
data={mindMap}
show
style={{ width: '100%', height: '100%' }}
></IndentedTree>
)}
</section>
</Flex>
)}
</Content>
</Layout>
</Layout>
</Layout>
<PdfDrawer
visible={visible}
hideModal={hideModal}
documentId={documentId}
chunk={selectedChunk}
></PdfDrawer>
</>
);
};