mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-07-31 12:32:00 +08:00
### 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:
parent
7241c73c7a
commit
42eeb38247
27
web/src/components/pdf-drawer/hooks.ts
Normal file
27
web/src/components/pdf-drawer/hooks.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { useSetModalState } from '@/hooks/common-hooks';
|
||||||
|
import { IChunk } from '@/interfaces/database/knowledge';
|
||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
};
|
33
web/src/components/pdf-drawer/index.tsx
Normal file
33
web/src/components/pdf-drawer/index.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { IModalProps } from '@/interfaces/common';
|
||||||
|
import { IChunk } from '@/interfaces/database/knowledge';
|
||||||
|
import { Drawer } from 'antd';
|
||||||
|
import DocumentPreviewer from '../pdf-previewer';
|
||||||
|
|
||||||
|
interface IProps extends IModalProps<any> {
|
||||||
|
documentId: string;
|
||||||
|
chunk: IChunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PdfDrawer = ({
|
||||||
|
visible = false,
|
||||||
|
hideModal,
|
||||||
|
documentId,
|
||||||
|
chunk,
|
||||||
|
}: IProps) => {
|
||||||
|
return (
|
||||||
|
<Drawer
|
||||||
|
title="Document Previewer"
|
||||||
|
onClose={hideModal}
|
||||||
|
open={visible}
|
||||||
|
width={'50vw'}
|
||||||
|
>
|
||||||
|
<DocumentPreviewer
|
||||||
|
documentId={documentId}
|
||||||
|
chunk={chunk}
|
||||||
|
visible={visible}
|
||||||
|
></DocumentPreviewer>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PdfDrawer;
|
11
web/src/components/retrieval-documents/index.less
Normal file
11
web/src/components/retrieval-documents/index.less
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.selectFilesCollapse {
|
||||||
|
:global(.ant-collapse-header) {
|
||||||
|
padding-left: 22px;
|
||||||
|
}
|
||||||
|
margin-bottom: 32px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectFilesTitle {
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
55
web/src/components/retrieval-documents/index.tsx
Normal file
55
web/src/components/retrieval-documents/index.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { ReactComponent as SelectedFilesCollapseIcon } from '@/assets/svg/selected-files-collapse.svg';
|
||||||
|
import { Collapse, Flex, Space } from 'antd';
|
||||||
|
import SelectFiles from './select-files';
|
||||||
|
|
||||||
|
import { useSelectTestingResult } from '@/hooks/knowledge-hooks';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import styles from './index.less';
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
selectedDocumentIdsLength?: number;
|
||||||
|
onTesting(documentIds: string[]): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RetrievalDocuments = ({ onTesting }: IProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { documents } = useSelectTestingResult();
|
||||||
|
const [selectedDocumentIds, setSelectedDocumentIds] = useState<string[]>([]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Collapse
|
||||||
|
expandIcon={() => <SelectedFilesCollapseIcon></SelectedFilesCollapseIcon>}
|
||||||
|
className={styles.selectFilesCollapse}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
label: (
|
||||||
|
<Flex
|
||||||
|
justify={'space-between'}
|
||||||
|
align="center"
|
||||||
|
className={styles.selectFilesTitle}
|
||||||
|
>
|
||||||
|
<Space>
|
||||||
|
<span>
|
||||||
|
{selectedDocumentIds.length ?? 0}/{documents.length}
|
||||||
|
</span>
|
||||||
|
{t('knowledgeDetails.filesSelected')}
|
||||||
|
</Space>
|
||||||
|
</Flex>
|
||||||
|
),
|
||||||
|
children: (
|
||||||
|
<div>
|
||||||
|
<SelectFiles
|
||||||
|
setSelectedDocumentIds={setSelectedDocumentIds}
|
||||||
|
handleTesting={onTesting}
|
||||||
|
></SelectFiles>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RetrievalDocuments;
|
73
web/src/components/retrieval-documents/select-files.tsx
Normal file
73
web/src/components/retrieval-documents/select-files.tsx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import NewDocumentLink from '@/components/new-document-link';
|
||||||
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
|
import { useSelectTestingResult } from '@/hooks/knowledge-hooks';
|
||||||
|
import { ITestingDocument } from '@/interfaces/database/knowledge';
|
||||||
|
import { EyeOutlined } from '@ant-design/icons';
|
||||||
|
import { Button, Table, TableProps, Tooltip } from 'antd';
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
handleTesting: (ids: string[]) => void;
|
||||||
|
setSelectedDocumentIds: (ids: string[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SelectFiles = ({ setSelectedDocumentIds, handleTesting }: IProps) => {
|
||||||
|
const { documents } = useSelectTestingResult();
|
||||||
|
const { t } = useTranslate('fileManager');
|
||||||
|
|
||||||
|
const columns: TableProps<ITestingDocument>['columns'] = [
|
||||||
|
{
|
||||||
|
title: 'Name',
|
||||||
|
dataIndex: 'doc_name',
|
||||||
|
key: 'doc_name',
|
||||||
|
render: (text) => <p>{text}</p>,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: 'Hits',
|
||||||
|
dataIndex: 'count',
|
||||||
|
key: 'count',
|
||||||
|
width: 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'View',
|
||||||
|
key: 'view',
|
||||||
|
width: 50,
|
||||||
|
render: (_, { doc_id, doc_name }) => (
|
||||||
|
<NewDocumentLink
|
||||||
|
documentName={doc_name}
|
||||||
|
documentId={doc_id}
|
||||||
|
prefix="document"
|
||||||
|
>
|
||||||
|
<Tooltip title={t('preview')}>
|
||||||
|
<Button type="text">
|
||||||
|
<EyeOutlined size={20} />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</NewDocumentLink>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const rowSelection = {
|
||||||
|
onChange: (selectedRowKeys: React.Key[]) => {
|
||||||
|
handleTesting(selectedRowKeys as string[]);
|
||||||
|
setSelectedDocumentIds(selectedRowKeys as string[]);
|
||||||
|
},
|
||||||
|
getCheckboxProps: (record: ITestingDocument) => ({
|
||||||
|
disabled: record.doc_name === 'Disabled User', // Column configuration not to be checked
|
||||||
|
name: record.doc_name,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
dataSource={documents}
|
||||||
|
showHeader={false}
|
||||||
|
rowSelection={rowSelection}
|
||||||
|
rowKey={'doc_id'}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SelectFiles;
|
@ -646,7 +646,7 @@ The above is the content you need to summarize.`,
|
|||||||
operation: 'operation',
|
operation: 'operation',
|
||||||
run: 'Run',
|
run: 'Run',
|
||||||
save: 'Save',
|
save: 'Save',
|
||||||
title: 'Title:',
|
title: 'ID:',
|
||||||
beginDescription: 'This is where the flow begins.',
|
beginDescription: 'This is where the flow begins.',
|
||||||
answerDescription: `A component that serves as the interface between human and bot, receiving user inputs and displaying the agent's responses.`,
|
answerDescription: `A component that serves as the interface between human and bot, receiving user inputs and displaying the agent's responses.`,
|
||||||
retrievalDescription: `A component that retrieves information from a specified knowledge base and returns 'Empty response' if no information is found. Ensure the correct knowledge base is selected.`,
|
retrievalDescription: `A component that retrieves information from a specified knowledge base and returns 'Empty response' if no information is found. Ensure the correct knowledge base is selected.`,
|
||||||
|
@ -602,7 +602,7 @@ export default {
|
|||||||
operation: '操作',
|
operation: '操作',
|
||||||
run: '運行',
|
run: '運行',
|
||||||
save: '儲存',
|
save: '儲存',
|
||||||
title: '標題:',
|
title: 'ID:',
|
||||||
|
|
||||||
beginDescription: '這是流程開始的地方',
|
beginDescription: '這是流程開始的地方',
|
||||||
answerDescription: `該組件用作機器人與人類之間的介面。它接收使用者的輸入並顯示機器人的計算結果。`,
|
answerDescription: `該組件用作機器人與人類之間的介面。它接收使用者的輸入並顯示機器人的計算結果。`,
|
||||||
|
@ -621,7 +621,7 @@ export default {
|
|||||||
operation: '操作',
|
operation: '操作',
|
||||||
run: '运行',
|
run: '运行',
|
||||||
save: '保存',
|
save: '保存',
|
||||||
title: '标题:',
|
title: 'ID:',
|
||||||
beginDescription: '这是流程开始的地方',
|
beginDescription: '这是流程开始的地方',
|
||||||
answerDescription: `该组件用作机器人与人类之间的接口。它接收用户的输入并显示机器人的计算结果。`,
|
answerDescription: `该组件用作机器人与人类之间的接口。它接收用户的输入并显示机器人的计算结果。`,
|
||||||
retrievalDescription: `此组件用于从知识库中检索相关信息。选择知识库。如果没有检索到任何内容,将返回“空响应”。`,
|
retrievalDescription: `此组件用于从知识库中检索相关信息。选择知识库。如果没有检索到任何内容,将返回“空响应”。`,
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import MessageItem from '@/components/message-item';
|
import MessageItem from '@/components/message-item';
|
||||||
import DocumentPreviewer from '@/components/pdf-previewer';
|
|
||||||
import { MessageType } from '@/constants/chat';
|
import { MessageType } from '@/constants/chat';
|
||||||
import { Drawer, Flex, Spin } from 'antd';
|
import { Flex, Spin } from 'antd';
|
||||||
import {
|
import {
|
||||||
useClickDrawer,
|
|
||||||
useCreateConversationBeforeUploadDocument,
|
useCreateConversationBeforeUploadDocument,
|
||||||
useGetFileIcon,
|
useGetFileIcon,
|
||||||
useGetSendButtonDisabled,
|
useGetSendButtonDisabled,
|
||||||
@ -13,6 +11,8 @@ import {
|
|||||||
import { buildMessageItemReference } from '../utils';
|
import { buildMessageItemReference } from '../utils';
|
||||||
|
|
||||||
import MessageInput from '@/components/message-input';
|
import MessageInput from '@/components/message-input';
|
||||||
|
import PdfDrawer from '@/components/pdf-drawer';
|
||||||
|
import { useClickDrawer } from '@/components/pdf-drawer/hooks';
|
||||||
import {
|
import {
|
||||||
useFetchNextConversation,
|
useFetchNextConversation,
|
||||||
useGetChatSearchParams,
|
useGetChatSearchParams,
|
||||||
@ -96,18 +96,12 @@ const ChatContainer = () => {
|
|||||||
}
|
}
|
||||||
></MessageInput>
|
></MessageInput>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Drawer
|
<PdfDrawer
|
||||||
title="Document Previewer"
|
visible={visible}
|
||||||
onClose={hideModal}
|
hideModal={hideModal}
|
||||||
open={visible}
|
documentId={documentId}
|
||||||
width={'50vw'}
|
chunk={selectedChunk}
|
||||||
>
|
></PdfDrawer>
|
||||||
<DocumentPreviewer
|
|
||||||
documentId={documentId}
|
|
||||||
chunk={selectedChunk}
|
|
||||||
visible={visible}
|
|
||||||
></DocumentPreviewer>
|
|
||||||
</Drawer>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -23,7 +23,6 @@ import {
|
|||||||
useSendMessageWithSse,
|
useSendMessageWithSse,
|
||||||
} from '@/hooks/logic-hooks';
|
} from '@/hooks/logic-hooks';
|
||||||
import { IConversation, IDialog, Message } from '@/interfaces/database/chat';
|
import { IConversation, IDialog, Message } from '@/interfaces/database/chat';
|
||||||
import { IChunk } from '@/interfaces/database/knowledge';
|
|
||||||
import { getFileExtension } from '@/utils';
|
import { getFileExtension } from '@/utils';
|
||||||
import { useMutationState } from '@tanstack/react-query';
|
import { useMutationState } from '@tanstack/react-query';
|
||||||
import { get } from 'lodash';
|
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 = () => {
|
export const useGetSendButtonDisabled = () => {
|
||||||
const { dialogId, conversationId } = useGetChatSearchParams();
|
const { dialogId, conversationId } = useGetChatSearchParams();
|
||||||
|
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import MessageItem from '@/components/message-item';
|
import MessageItem from '@/components/message-item';
|
||||||
import DocumentPreviewer from '@/components/pdf-previewer';
|
|
||||||
import { MessageType } from '@/constants/chat';
|
import { MessageType } from '@/constants/chat';
|
||||||
import { useTranslate } from '@/hooks/common-hooks';
|
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 { 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 { useSendNextMessage } from './hooks';
|
||||||
|
|
||||||
|
import PdfDrawer from '@/components/pdf-drawer';
|
||||||
|
import { useClickDrawer } from '@/components/pdf-drawer/hooks';
|
||||||
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
@ -79,19 +80,12 @@ const FlowChatBox = () => {
|
|||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Drawer
|
<PdfDrawer
|
||||||
title="Document Previewer"
|
visible={visible}
|
||||||
onClose={hideModal}
|
hideModal={hideModal}
|
||||||
open={visible}
|
documentId={documentId}
|
||||||
width={'50vw'}
|
chunk={selectedChunk}
|
||||||
mask={false}
|
></PdfDrawer>
|
||||||
>
|
|
||||||
<DocumentPreviewer
|
|
||||||
documentId={documentId}
|
|
||||||
chunk={selectedChunk}
|
|
||||||
visible={visible}
|
|
||||||
></DocumentPreviewer>
|
|
||||||
</Drawer>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -46,10 +46,27 @@ export const useSendQuestion = (kbIds: string[]) => {
|
|||||||
|
|
||||||
const handleClickRelatedQuestion = useCallback(
|
const handleClickRelatedQuestion = useCallback(
|
||||||
(question: string) => () => {
|
(question: string) => () => {
|
||||||
|
if (sendingLoading) return;
|
||||||
|
|
||||||
setSearchStr(question);
|
setSearchStr(question);
|
||||||
sendQuestion(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(() => {
|
useEffect(() => {
|
||||||
@ -71,6 +88,7 @@ export const useSendQuestion = (kbIds: string[]) => {
|
|||||||
sendQuestion,
|
sendQuestion,
|
||||||
handleSearchStrChange,
|
handleSearchStrChange,
|
||||||
handleClickRelatedQuestion,
|
handleClickRelatedQuestion,
|
||||||
|
handleTestChunk,
|
||||||
loading,
|
loading,
|
||||||
sendingLoading,
|
sendingLoading,
|
||||||
answer: currentAnswer,
|
answer: currentAnswer,
|
||||||
|
@ -51,6 +51,9 @@
|
|||||||
|
|
||||||
.firstRenderContent {
|
.firstRenderContent {
|
||||||
height: 100%;
|
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 {
|
.content {
|
||||||
@ -79,10 +82,13 @@
|
|||||||
|
|
||||||
.input() {
|
.input() {
|
||||||
:global(.ant-input-affix-wrapper) {
|
:global(.ant-input-affix-wrapper) {
|
||||||
padding: 4px 8px;
|
padding: 4px 12px;
|
||||||
border-start-start-radius: 30px !important;
|
border-start-start-radius: 30px !important;
|
||||||
border-end-start-radius: 30px !important;
|
border-end-start-radius: 30px !important;
|
||||||
}
|
}
|
||||||
|
:global(.ant-input-group-addon) {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
input {
|
input {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
@ -101,3 +107,35 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
.input();
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,18 +19,26 @@ import MarkdownContent from '../chat/markdown-content';
|
|||||||
import { useSendQuestion } from './hooks';
|
import { useSendQuestion } from './hooks';
|
||||||
import SearchSidebar from './sidebar';
|
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';
|
import styles from './index.less';
|
||||||
|
|
||||||
const { Content } = Layout;
|
const { Content } = Layout;
|
||||||
const { Search } = Input;
|
const { Search } = Input;
|
||||||
|
|
||||||
const SearchPage = () => {
|
const SearchPage = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const [checkedList, setCheckedList] = useState<string[]>([]);
|
const [checkedList, setCheckedList] = useState<string[]>([]);
|
||||||
const list = useSelectTestingResult();
|
const list = useSelectTestingResult();
|
||||||
|
const appConf = useFetchAppConf();
|
||||||
const {
|
const {
|
||||||
sendQuestion,
|
sendQuestion,
|
||||||
handleClickRelatedQuestion,
|
handleClickRelatedQuestion,
|
||||||
handleSearchStrChange,
|
handleSearchStrChange,
|
||||||
|
handleTestChunk,
|
||||||
answer,
|
answer,
|
||||||
sendingLoading,
|
sendingLoading,
|
||||||
relatedQuestions,
|
relatedQuestions,
|
||||||
@ -40,12 +48,14 @@ const SearchPage = () => {
|
|||||||
loading,
|
loading,
|
||||||
isFirstRender,
|
isFirstRender,
|
||||||
} = useSendQuestion(checkedList);
|
} = useSendQuestion(checkedList);
|
||||||
|
const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } =
|
||||||
|
useClickDrawer();
|
||||||
|
|
||||||
const InputSearch = (
|
const InputSearch = (
|
||||||
<Search
|
<Search
|
||||||
value={searchStr}
|
value={searchStr}
|
||||||
onChange={handleSearchStrChange}
|
onChange={handleSearchStrChange}
|
||||||
placeholder="input search text"
|
placeholder={t('header.search')}
|
||||||
allowClear
|
allowClear
|
||||||
enterButton
|
enterButton
|
||||||
onSearch={sendQuestion}
|
onSearch={sendQuestion}
|
||||||
@ -57,88 +67,107 @@ const SearchPage = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout className={styles.searchPage}>
|
<>
|
||||||
<SearchSidebar
|
<Layout className={styles.searchPage}>
|
||||||
checkedList={checkedList}
|
<SearchSidebar
|
||||||
setCheckedList={setCheckedList}
|
checkedList={checkedList}
|
||||||
></SearchSidebar>
|
setCheckedList={setCheckedList}
|
||||||
<Layout>
|
></SearchSidebar>
|
||||||
<Content>
|
<Layout>
|
||||||
{isFirstRender ? (
|
<Content>
|
||||||
<Flex
|
{isFirstRender ? (
|
||||||
justify="center"
|
<Flex
|
||||||
align="center"
|
justify="center"
|
||||||
className={styles.firstRenderContent}
|
align="center"
|
||||||
>
|
className={styles.firstRenderContent}
|
||||||
{InputSearch}
|
>
|
||||||
</Flex>
|
<Flex vertical align="center" gap={'large'}>
|
||||||
) : (
|
<Space size={30}>
|
||||||
<Flex className={styles.content}>
|
<img src="/logo.svg" alt="" className={styles.appIcon} />
|
||||||
<section className={styles.main}>
|
<span className={styles.appName}>{appConf.appName}</span>
|
||||||
{InputSearch}
|
</Space>
|
||||||
{answer.answer && (
|
{InputSearch}
|
||||||
<div className={styles.answerWrapper}>
|
</Flex>
|
||||||
<MarkdownContent
|
</Flex>
|
||||||
loading={sendingLoading}
|
) : (
|
||||||
content={answer.answer}
|
<Flex className={styles.content}>
|
||||||
reference={answer.reference ?? ({} as IReference)}
|
<section className={styles.main}>
|
||||||
clickDocumentButton={() => {}}
|
{InputSearch}
|
||||||
></MarkdownContent>
|
{answer.answer && (
|
||||||
</div>
|
<div className={styles.answerWrapper}>
|
||||||
)}
|
<MarkdownContent
|
||||||
<Divider></Divider>
|
loading={sendingLoading}
|
||||||
{list.chunks.length > 0 && (
|
content={answer.answer}
|
||||||
<List
|
reference={answer.reference ?? ({} as IReference)}
|
||||||
dataSource={list.chunks}
|
clickDocumentButton={clickDocumentButton}
|
||||||
loading={loading}
|
></MarkdownContent>
|
||||||
renderItem={(item) => (
|
</div>
|
||||||
<List.Item>
|
)}
|
||||||
<Card className={styles.card}>
|
<Divider></Divider>
|
||||||
<Space>
|
<RetrievalDocuments
|
||||||
<ImageWithPopover
|
selectedDocumentIdsLength={0}
|
||||||
id={item.img_id}
|
onTesting={handleTestChunk}
|
||||||
></ImageWithPopover>
|
></RetrievalDocuments>
|
||||||
<HightLightMarkdown>
|
<Divider></Divider>
|
||||||
{item.highlight}
|
{list.chunks.length > 0 && (
|
||||||
</HightLightMarkdown>
|
<List
|
||||||
</Space>
|
dataSource={list.chunks}
|
||||||
</Card>
|
loading={loading}
|
||||||
</List.Item>
|
renderItem={(item) => (
|
||||||
)}
|
<List.Item>
|
||||||
/>
|
<Card className={styles.card}>
|
||||||
)}
|
<Space>
|
||||||
{relatedQuestions?.length > 0 && (
|
<ImageWithPopover
|
||||||
<Card>
|
id={item.img_id}
|
||||||
<Flex wrap="wrap" gap={'10px 0'}>
|
></ImageWithPopover>
|
||||||
{relatedQuestions?.map((x, idx) => (
|
<HightLightMarkdown>
|
||||||
<Tag
|
{item.highlight}
|
||||||
key={idx}
|
</HightLightMarkdown>
|
||||||
className={styles.tag}
|
</Space>
|
||||||
onClick={handleClickRelatedQuestion(x)}
|
</Card>
|
||||||
>
|
</List.Item>
|
||||||
{x}
|
)}
|
||||||
</Tag>
|
/>
|
||||||
))}
|
)}
|
||||||
</Flex>
|
{relatedQuestions?.length > 0 && (
|
||||||
</Card>
|
<Card>
|
||||||
)}
|
<Flex wrap="wrap" gap={'10px 0'}>
|
||||||
</section>
|
{relatedQuestions?.map((x, idx) => (
|
||||||
<section className={styles.graph}>
|
<Tag
|
||||||
{mindMapLoading ? (
|
key={idx}
|
||||||
<Skeleton active />
|
className={styles.tag}
|
||||||
) : (
|
onClick={handleClickRelatedQuestion(x)}
|
||||||
<IndentedTree
|
>
|
||||||
data={mindMap}
|
{x}
|
||||||
show
|
</Tag>
|
||||||
style={{ width: '100%', height: '100%' }}
|
))}
|
||||||
></IndentedTree>
|
</Flex>
|
||||||
)}
|
</Card>
|
||||||
</section>
|
)}
|
||||||
</Flex>
|
</section>
|
||||||
)}
|
<section className={styles.graph}>
|
||||||
</Content>
|
{mindMapLoading ? (
|
||||||
|
<Skeleton active />
|
||||||
|
) : (
|
||||||
|
<IndentedTree
|
||||||
|
data={mindMap}
|
||||||
|
show
|
||||||
|
style={{ width: '100%', height: '100%' }}
|
||||||
|
></IndentedTree>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Content>
|
||||||
|
</Layout>
|
||||||
</Layout>
|
</Layout>
|
||||||
</Layout>
|
<PdfDrawer
|
||||||
|
visible={visible}
|
||||||
|
hideModal={hideModal}
|
||||||
|
documentId={documentId}
|
||||||
|
chunk={selectedChunk}
|
||||||
|
></PdfDrawer>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user