From 1a156e6569ba94bd3b156b6da18fdfb40daf08c4 Mon Sep 17 00:00:00 2001 From: balibabu Date: Thu, 8 Feb 2024 18:12:31 +0800 Subject: [PATCH] feat: test document chunks (#62) --- web/src/interfaces/database/knowledge.ts | 27 +++++ .../components/knowledge-testing/index.tsx | 39 ++++++- .../components/knowledge-testing/model.ts | 72 ++++++++++++ .../testing-control/index.less | 3 + .../testing-control/index.tsx | 104 +++++++++++++----- .../testing-result/index.less | 20 ++++ .../testing-result/index.tsx | 82 ++++++++++++-- .../testing-result/select-files.tsx | 83 +++++++------- web/src/utils/api.ts | 2 +- 9 files changed, 341 insertions(+), 91 deletions(-) create mode 100644 web/src/pages/add-knowledge/components/knowledge-testing/model.ts diff --git a/web/src/interfaces/database/knowledge.ts b/web/src/interfaces/database/knowledge.ts index a98a04bec..68b88da6d 100644 --- a/web/src/interfaces/database/knowledge.ts +++ b/web/src/interfaces/database/knowledge.ts @@ -75,3 +75,30 @@ export interface IChunk { img_id: string; important_kwd: any[]; } + +export interface ITestingChunk { + chunk_id: string; + content_ltks: string; + content_with_weight: string; + doc_id: string; + docnm_kwd: string; + img_id: string; + important_kwd: any[]; + kb_id: string; + similarity: number; + term_similarity: number; + vector: number[]; + vector_similarity: number; +} + +export interface ITestingDocument { + count: number; + doc_id: string; + doc_name: string; +} + +export interface ITestingResult { + chunks: ITestingChunk[]; + doc_aggs: Record; + total: number; +} diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/index.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/index.tsx index 5c4d22d98..e3dd8625f 100644 --- a/web/src/pages/add-knowledge/components/knowledge-testing/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-testing/index.tsx @@ -1,14 +1,47 @@ -import { Flex } from 'antd'; +import { Flex, Form } from 'antd'; import TestingControl from './testing-control'; import TestingResult from './testing-result'; +import { useKnowledgeBaseId } from '@/hooks/knowledgeHook'; +import { useEffect } from 'react'; +import { useDispatch } from 'umi'; import styles from './index.less'; const KnowledgeTesting = () => { + const [form] = Form.useForm(); + + const dispatch = useDispatch(); + const knowledgeBaseId = useKnowledgeBaseId(); + + const handleTesting = async () => { + const values = await form.validateFields(); + console.info(values); + const similarity_threshold = values.similarity_threshold / 100; + const vector_similarity_weight = values.vector_similarity_weight / 100; + dispatch({ + type: 'testingModel/testDocumentChunk', + payload: { + ...values, + similarity_threshold, + vector_similarity_weight, + kb_id: knowledgeBaseId, + }, + }); + }; + + useEffect(() => { + return () => { + dispatch({ type: 'testingModel/reset' }); + }; + }, [dispatch]); + return ( - - + + ); }; diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/model.ts b/web/src/pages/add-knowledge/components/knowledge-testing/model.ts new file mode 100644 index 000000000..ac7580700 --- /dev/null +++ b/web/src/pages/add-knowledge/components/knowledge-testing/model.ts @@ -0,0 +1,72 @@ +import { BaseState } from '@/interfaces/common'; +import { + ITestingChunk, + ITestingDocument, +} from '@/interfaces/database/knowledge'; +import kbService from '@/services/kbService'; +import { DvaModel } from 'umi'; + +export interface TestingModelState extends Pick { + chunks: ITestingChunk[]; + documents: ITestingDocument[]; + total: number; + selectedDocumentIds: string[] | undefined; +} + +const initialState = { + chunks: [], + documents: [], + total: 0, + pagination: { + current: 1, + pageSize: 10, + }, + selectedDocumentIds: undefined, +}; + +const model: DvaModel = { + namespace: 'testingModel', + state: initialState, + reducers: { + setChunksAndDocuments(state, { payload }) { + return { + ...state, + ...payload, + }; + }, + setPagination(state, { payload }) { + return { ...state, pagination: { ...state.pagination, ...payload } }; + }, + setSelectedDocumentIds(state, { payload }) { + return { ...state, selectedDocumentIds: payload }; + }, + reset() { + return initialState; + }, + }, + effects: { + *testDocumentChunk({ payload = {} }, { call, put, select }) { + const { pagination, selectedDocumentIds }: TestingModelState = + yield select((state: any) => state.testingModel); + + const { data } = yield call(kbService.retrieval_test, { + ...payload, + doc_ids: selectedDocumentIds, + page: pagination.current, + size: pagination.pageSize, + }); + const { retcode, data: res } = data; + if (retcode === 0) { + yield put({ + type: 'setChunksAndDocuments', + payload: { + chunks: res.chunks, + documents: res.doc_aggs, + total: res.total, + }, + }); + } + }, + }, +}; +export default model; diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.less b/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.less index 42842a278..2e9f01a12 100644 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.less +++ b/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.less @@ -2,6 +2,9 @@ width: 350px; background-color: white; padding: 30px 20px; + overflow: auto; + height: calc(100vh - 160px); + .historyTitle { padding: 30px 0 20px; } diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx index 97ef9d5f2..376feffb7 100644 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx @@ -3,6 +3,7 @@ import { Card, Divider, Flex, + Form, Input, Slider, SliderSingleProps, @@ -11,50 +12,95 @@ import { } from 'antd'; import { DeleteOutlined, HistoryOutlined } from '@ant-design/icons'; +import { FormInstance } from 'antd/lib'; import styles from './index.less'; const list = [1, 2, 3]; const marks: SliderSingleProps['marks'] = { - 0: '0°C', - 26: '26°C', - 37: '37°C', - 100: { - style: { - color: '#f50', - }, - label: 100°C, - }, + 0: '0', + 100: '1', }; -const TestingControl = () => { +type FieldType = { + similarity_threshold?: number; + vector_similarity_weight?: number; + top_k?: number; + question: string; +}; + +const formatter = (value: number | undefined) => { + return typeof value === 'number' ? value / 100 : 0; +}; + +const tooltip = { formatter }; + +interface IProps { + form: FormInstance; + handleTesting: () => Promise; +} + +const TestingControl = ({ form, handleTesting }: IProps) => { + const question = Form.useWatch('question', { form, preserve: true }); + + const buttonDisabled = + !question || (typeof question === 'string' && question.trim() === ''); + return (

Retrieval testing

-

xxxx

+

Final step! After success, leave the rest to Infiniflow AI.

- - - - Semantic Search - - } +
- - - 10/200 - - - + + label="Similarity threshold" + name={'similarity_threshold'} + > + + + + label="Vector similarity weight" + name={'vector_similarity_weight'} + > + + + label="Top k" name={'top_k'}> + + + + + name={'question'} + rules={[ + { required: true, message: 'Please input your question!' }, + ]} + > + + + + 10/200 + + + +

diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less index 2a1d8c01f..46ef353dc 100644 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less +++ b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less @@ -2,15 +2,35 @@ flex: 1; background-color: white; padding: 30px 20px; + overflow: auto; + height: calc(100vh - 160px); + display: flex; + flex-direction: column; + justify-content: space-between; .selectFilesCollapse { :global(.ant-collapse-header) { padding-left: 22px; } margin-bottom: 32px; + overflow-y: auto; } .selectFilesTitle { padding-right: 10px; } + + .similarityCircle { + width: 24px; + height: 24px; + border-radius: 50%; + background-color: rgba(244, 235, 255, 1); + font-size: 10px; + font-weight: normal; + } + + .similarityText { + font-size: 12px; + font-weight: 500; + } } diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx index 14a04ac96..dbe7b22aa 100644 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx @@ -1,12 +1,55 @@ import { ReactComponent as SelectedFilesCollapseIcon } from '@/assets/svg/selected-files-collapse.svg'; -import { Card, Collapse, Flex, Space } from 'antd'; +import { ITestingChunk } from '@/interfaces/database/knowledge'; +import { Card, Collapse, Flex, Pagination, PaginationProps, Space } from 'antd'; +import { useDispatch, useSelector } from 'umi'; +import { TestingModelState } from '../model'; +import styles from './index.less'; import SelectFiles from './select-files'; -import styles from './index.less'; +const similarityList: Array<{ field: keyof ITestingChunk; label: string }> = [ + { field: 'similarity', label: 'Hybrid Similarity' }, + { field: 'term_similarity', label: 'Term Similarity' }, + { field: 'vector_similarity', label: 'Vector Similarity' }, +]; -const list = [1, 2, 3, 4]; +const ChunkTitle = ({ item }: { item: ITestingChunk }) => { + return ( + + {similarityList.map((x) => ( + + + {((item[x.field] as number) * 100).toFixed(2)}% + + Hybrid Similarity + + ))} + + ); +}; + +interface IProps { + handleTesting: () => Promise; +} + +const TestingResult = ({ handleTesting }: IProps) => { + const { + documents, + chunks, + total, + pagination, + selectedDocumentIds, + }: TestingModelState = useSelector((state: any) => state.testingModel); + const dispatch = useDispatch(); + + const onChange: PaginationProps['onChange'] = (pageNumber, pageSize) => { + console.log('Page: ', pageNumber, pageSize); + dispatch({ + type: 'testingModel/setPagination', + payload: { current: pageNumber, pageSize }, + }); + handleTesting(); + }; -const TestingResult = () => { return (

{ align="center" className={styles.selectFilesTitle} > - 4/25 Files Selected + + {selectedDocumentIds?.length ?? 0}/{documents.length} Files + Selected + Hits View @@ -32,21 +78,33 @@ const TestingResult = () => { ), children: (
- +
), }, ]} /> - - {list.map((x) => ( - More}> -

Card content

-

Card content

-

Card content

+ + {chunks.map((x) => ( + }> +
{x.content_with_weight}
))}
+
); }; 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 0aee3dc13..ab5d06c9c 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,80 +1,71 @@ import { ReactComponent as NavigationPointerIcon } from '@/assets/svg/navigation-pointer.svg'; +import { ITestingDocument } from '@/interfaces/database/knowledge'; +import { api_host } from '@/utils/api'; import { Table, TableProps } from 'antd'; +import { useDispatch, useSelector } from 'umi'; -interface DataType { - key: string; - name: string; - hits: number; - address: string; - tags: string[]; +interface IProps { + handleTesting: () => Promise; } -const SelectFiles = () => { - const columns: TableProps['columns'] = [ +const SelectFiles = ({ handleTesting }: IProps) => { + const documents: ITestingDocument[] = useSelector( + (state: any) => state.testingModel.documents, + ); + + const dispatch = useDispatch(); + + const columns: TableProps['columns'] = [ { title: 'Name', - dataIndex: 'name', - key: 'name', + dataIndex: 'doc_name', + key: 'doc_name', render: (text) =>

{text}

, }, { title: 'Hits', - dataIndex: 'hits', - key: 'hits', + dataIndex: 'count', + key: 'count', width: 80, }, { title: 'View', key: 'view', width: 50, - render: () => , + render: (_, { doc_id }) => ( + + + + ), }, ]; const rowSelection = { - onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => { - console.log( - `selectedRowKeys: ${selectedRowKeys}`, - 'selectedRows: ', - selectedRows, - ); + onChange: (selectedRowKeys: React.Key[]) => { + dispatch({ + type: 'testingModel/setSelectedDocumentIds', + payload: selectedRowKeys, + }); + handleTesting(); }, - getCheckboxProps: (record: DataType) => ({ - disabled: record.name === 'Disabled User', // Column configuration not to be checked - name: record.name, + getCheckboxProps: (record: ITestingDocument) => ({ + disabled: record.doc_name === 'Disabled User', // Column configuration not to be checked + name: record.doc_name, }), }; - const data: DataType[] = [ - { - key: '1', - name: 'John Brown', - hits: 32, - address: 'New York No. 1 Lake Park', - tags: ['nice', 'developer'], - }, - { - key: '2', - name: 'Jim Green', - hits: 42, - address: 'London No. 1 Lake Park', - tags: ['loser'], - }, - { - key: '3', - name: 'Joe Black', - hits: 32, - address: 'Sydney No. 1 Lake Park', - tags: ['cool', 'teacher'], - }, - ]; return ( ); }; diff --git a/web/src/utils/api.ts b/web/src/utils/api.ts index d7634efa0..d0afb1847 100644 --- a/web/src/utils/api.ts +++ b/web/src/utils/api.ts @@ -1,4 +1,4 @@ -let api_host = `http://223.111.148.200:9380/v1`; +let api_host = `http://123.60.95.134:9380/v1`; export { api_host };