balibabu commited on
Commit
1a156e6
·
1 Parent(s): 5e0a689

feat: test document chunks (#62)

Browse files
web/src/interfaces/database/knowledge.ts CHANGED
@@ -75,3 +75,30 @@ export interface IChunk {
75
  img_id: string;
76
  important_kwd: any[];
77
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  img_id: string;
76
  important_kwd: any[];
77
  }
78
+
79
+ export interface ITestingChunk {
80
+ chunk_id: string;
81
+ content_ltks: string;
82
+ content_with_weight: string;
83
+ doc_id: string;
84
+ docnm_kwd: string;
85
+ img_id: string;
86
+ important_kwd: any[];
87
+ kb_id: string;
88
+ similarity: number;
89
+ term_similarity: number;
90
+ vector: number[];
91
+ vector_similarity: number;
92
+ }
93
+
94
+ export interface ITestingDocument {
95
+ count: number;
96
+ doc_id: string;
97
+ doc_name: string;
98
+ }
99
+
100
+ export interface ITestingResult {
101
+ chunks: ITestingChunk[];
102
+ doc_aggs: Record<string, number>;
103
+ total: number;
104
+ }
web/src/pages/add-knowledge/components/knowledge-testing/index.tsx CHANGED
@@ -1,14 +1,47 @@
1
- import { Flex } from 'antd';
2
  import TestingControl from './testing-control';
3
  import TestingResult from './testing-result';
4
 
 
 
 
5
  import styles from './index.less';
6
 
7
  const KnowledgeTesting = () => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  return (
9
  <Flex className={styles.testingWrapper} gap={16}>
10
- <TestingControl></TestingControl>
11
- <TestingResult></TestingResult>
 
 
 
12
  </Flex>
13
  );
14
  };
 
1
+ import { Flex, Form } from 'antd';
2
  import TestingControl from './testing-control';
3
  import TestingResult from './testing-result';
4
 
5
+ import { useKnowledgeBaseId } from '@/hooks/knowledgeHook';
6
+ import { useEffect } from 'react';
7
+ import { useDispatch } from 'umi';
8
  import styles from './index.less';
9
 
10
  const KnowledgeTesting = () => {
11
+ const [form] = Form.useForm();
12
+
13
+ const dispatch = useDispatch();
14
+ const knowledgeBaseId = useKnowledgeBaseId();
15
+
16
+ const handleTesting = async () => {
17
+ const values = await form.validateFields();
18
+ console.info(values);
19
+ const similarity_threshold = values.similarity_threshold / 100;
20
+ const vector_similarity_weight = values.vector_similarity_weight / 100;
21
+ dispatch({
22
+ type: 'testingModel/testDocumentChunk',
23
+ payload: {
24
+ ...values,
25
+ similarity_threshold,
26
+ vector_similarity_weight,
27
+ kb_id: knowledgeBaseId,
28
+ },
29
+ });
30
+ };
31
+
32
+ useEffect(() => {
33
+ return () => {
34
+ dispatch({ type: 'testingModel/reset' });
35
+ };
36
+ }, [dispatch]);
37
+
38
  return (
39
  <Flex className={styles.testingWrapper} gap={16}>
40
+ <TestingControl
41
+ form={form}
42
+ handleTesting={handleTesting}
43
+ ></TestingControl>
44
+ <TestingResult handleTesting={handleTesting}></TestingResult>
45
  </Flex>
46
  );
47
  };
web/src/pages/add-knowledge/components/knowledge-testing/model.ts ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { BaseState } from '@/interfaces/common';
2
+ import {
3
+ ITestingChunk,
4
+ ITestingDocument,
5
+ } from '@/interfaces/database/knowledge';
6
+ import kbService from '@/services/kbService';
7
+ import { DvaModel } from 'umi';
8
+
9
+ export interface TestingModelState extends Pick<BaseState, 'pagination'> {
10
+ chunks: ITestingChunk[];
11
+ documents: ITestingDocument[];
12
+ total: number;
13
+ selectedDocumentIds: string[] | undefined;
14
+ }
15
+
16
+ const initialState = {
17
+ chunks: [],
18
+ documents: [],
19
+ total: 0,
20
+ pagination: {
21
+ current: 1,
22
+ pageSize: 10,
23
+ },
24
+ selectedDocumentIds: undefined,
25
+ };
26
+
27
+ const model: DvaModel<TestingModelState> = {
28
+ namespace: 'testingModel',
29
+ state: initialState,
30
+ reducers: {
31
+ setChunksAndDocuments(state, { payload }) {
32
+ return {
33
+ ...state,
34
+ ...payload,
35
+ };
36
+ },
37
+ setPagination(state, { payload }) {
38
+ return { ...state, pagination: { ...state.pagination, ...payload } };
39
+ },
40
+ setSelectedDocumentIds(state, { payload }) {
41
+ return { ...state, selectedDocumentIds: payload };
42
+ },
43
+ reset() {
44
+ return initialState;
45
+ },
46
+ },
47
+ effects: {
48
+ *testDocumentChunk({ payload = {} }, { call, put, select }) {
49
+ const { pagination, selectedDocumentIds }: TestingModelState =
50
+ yield select((state: any) => state.testingModel);
51
+
52
+ const { data } = yield call(kbService.retrieval_test, {
53
+ ...payload,
54
+ doc_ids: selectedDocumentIds,
55
+ page: pagination.current,
56
+ size: pagination.pageSize,
57
+ });
58
+ const { retcode, data: res } = data;
59
+ if (retcode === 0) {
60
+ yield put({
61
+ type: 'setChunksAndDocuments',
62
+ payload: {
63
+ chunks: res.chunks,
64
+ documents: res.doc_aggs,
65
+ total: res.total,
66
+ },
67
+ });
68
+ }
69
+ },
70
+ },
71
+ };
72
+ export default model;
web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.less CHANGED
@@ -2,6 +2,9 @@
2
  width: 350px;
3
  background-color: white;
4
  padding: 30px 20px;
 
 
 
5
  .historyTitle {
6
  padding: 30px 0 20px;
7
  }
 
2
  width: 350px;
3
  background-color: white;
4
  padding: 30px 20px;
5
+ overflow: auto;
6
+ height: calc(100vh - 160px);
7
+
8
  .historyTitle {
9
  padding: 30px 0 20px;
10
  }
web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx CHANGED
@@ -3,6 +3,7 @@ import {
3
  Card,
4
  Divider,
5
  Flex,
 
6
  Input,
7
  Slider,
8
  SliderSingleProps,
@@ -11,50 +12,95 @@ import {
11
  } from 'antd';
12
 
13
  import { DeleteOutlined, HistoryOutlined } from '@ant-design/icons';
 
14
  import styles from './index.less';
15
 
16
  const list = [1, 2, 3];
17
 
18
  const marks: SliderSingleProps['marks'] = {
19
- 0: '0°C',
20
- 26: '26°C',
21
- 37: '37°C',
22
- 100: {
23
- style: {
24
- color: '#f50',
25
- },
26
- label: <strong>100°C</strong>,
27
- },
28
  };
29
 
30
- const TestingControl = () => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  return (
32
  <section className={styles.testingControlWrapper}>
33
  <p>
34
  <b>Retrieval testing</b>
35
  </p>
36
- <p>xxxx</p>
37
  <Divider></Divider>
38
  <section>
39
- <Slider range marks={marks} defaultValue={[26, 37]} />
40
- <Slider range marks={marks} defaultValue={[26, 37]} />
41
- <Card
42
- size="small"
43
- title="Test text"
44
- extra={
45
- <Button type="primary" ghost>
46
- Semantic Search
47
- </Button>
48
- }
49
  >
50
- <Input.TextArea autoSize={{ minRows: 8 }}></Input.TextArea>
51
- <Flex justify={'space-between'}>
52
- <Tag>10/200</Tag>
53
- <Button type="primary" size="small">
54
- Testing
55
- </Button>
56
- </Flex>
57
- </Card>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  </section>
59
  <section>
60
  <p className={styles.historyTitle}>
 
3
  Card,
4
  Divider,
5
  Flex,
6
+ Form,
7
  Input,
8
  Slider,
9
  SliderSingleProps,
 
12
  } from 'antd';
13
 
14
  import { DeleteOutlined, HistoryOutlined } from '@ant-design/icons';
15
+ import { FormInstance } from 'antd/lib';
16
  import styles from './index.less';
17
 
18
  const list = [1, 2, 3];
19
 
20
  const marks: SliderSingleProps['marks'] = {
21
+ 0: '0',
22
+ 100: '1',
 
 
 
 
 
 
 
23
  };
24
 
25
+ type FieldType = {
26
+ similarity_threshold?: number;
27
+ vector_similarity_weight?: number;
28
+ top_k?: number;
29
+ question: string;
30
+ };
31
+
32
+ const formatter = (value: number | undefined) => {
33
+ return typeof value === 'number' ? value / 100 : 0;
34
+ };
35
+
36
+ const tooltip = { formatter };
37
+
38
+ interface IProps {
39
+ form: FormInstance;
40
+ handleTesting: () => Promise<any>;
41
+ }
42
+
43
+ const TestingControl = ({ form, handleTesting }: IProps) => {
44
+ const question = Form.useWatch('question', { form, preserve: true });
45
+
46
+ const buttonDisabled =
47
+ !question || (typeof question === 'string' && question.trim() === '');
48
+
49
  return (
50
  <section className={styles.testingControlWrapper}>
51
  <p>
52
  <b>Retrieval testing</b>
53
  </p>
54
+ <p>Final step! After success, leave the rest to Infiniflow AI.</p>
55
  <Divider></Divider>
56
  <section>
57
+ <Form
58
+ name="testing"
59
+ layout="vertical"
60
+ form={form}
61
+ initialValues={{
62
+ similarity_threshold: 20,
63
+ vector_similarity_weight: 30,
64
+ top_k: 1024,
65
+ }}
 
66
  >
67
+ <Form.Item<FieldType>
68
+ label="Similarity threshold"
69
+ name={'similarity_threshold'}
70
+ >
71
+ <Slider marks={marks} defaultValue={0} tooltip={tooltip} />
72
+ </Form.Item>
73
+ <Form.Item<FieldType>
74
+ label="Vector similarity weight"
75
+ name={'vector_similarity_weight'}
76
+ >
77
+ <Slider marks={marks} defaultValue={0} tooltip={tooltip} />
78
+ </Form.Item>
79
+ <Form.Item<FieldType> label="Top k" name={'top_k'}>
80
+ <Slider marks={{ 0: 0, 2048: 2048 }} defaultValue={0} max={2048} />
81
+ </Form.Item>
82
+ <Card size="small" title="Test text">
83
+ <Form.Item<FieldType>
84
+ name={'question'}
85
+ rules={[
86
+ { required: true, message: 'Please input your question!' },
87
+ ]}
88
+ >
89
+ <Input.TextArea autoSize={{ minRows: 8 }}></Input.TextArea>
90
+ </Form.Item>
91
+ <Flex justify={'space-between'}>
92
+ <Tag>10/200</Tag>
93
+ <Button
94
+ type="primary"
95
+ size="small"
96
+ onClick={handleTesting}
97
+ disabled={buttonDisabled}
98
+ >
99
+ Testing
100
+ </Button>
101
+ </Flex>
102
+ </Card>
103
+ </Form>
104
  </section>
105
  <section>
106
  <p className={styles.historyTitle}>
web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less CHANGED
@@ -2,15 +2,35 @@
2
  flex: 1;
3
  background-color: white;
4
  padding: 30px 20px;
 
 
 
 
 
5
 
6
  .selectFilesCollapse {
7
  :global(.ant-collapse-header) {
8
  padding-left: 22px;
9
  }
10
  margin-bottom: 32px;
 
11
  }
12
 
13
  .selectFilesTitle {
14
  padding-right: 10px;
15
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  }
 
2
  flex: 1;
3
  background-color: white;
4
  padding: 30px 20px;
5
+ overflow: auto;
6
+ height: calc(100vh - 160px);
7
+ display: flex;
8
+ flex-direction: column;
9
+ justify-content: space-between;
10
 
11
  .selectFilesCollapse {
12
  :global(.ant-collapse-header) {
13
  padding-left: 22px;
14
  }
15
  margin-bottom: 32px;
16
+ overflow-y: auto;
17
  }
18
 
19
  .selectFilesTitle {
20
  padding-right: 10px;
21
  }
22
+
23
+ .similarityCircle {
24
+ width: 24px;
25
+ height: 24px;
26
+ border-radius: 50%;
27
+ background-color: rgba(244, 235, 255, 1);
28
+ font-size: 10px;
29
+ font-weight: normal;
30
+ }
31
+
32
+ .similarityText {
33
+ font-size: 12px;
34
+ font-weight: 500;
35
+ }
36
  }
web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx CHANGED
@@ -1,12 +1,55 @@
1
  import { ReactComponent as SelectedFilesCollapseIcon } from '@/assets/svg/selected-files-collapse.svg';
2
- import { Card, Collapse, Flex, Space } from 'antd';
 
 
 
 
3
  import SelectFiles from './select-files';
4
 
5
- import styles from './index.less';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
- const list = [1, 2, 3, 4];
 
 
 
 
 
 
 
8
 
9
- const TestingResult = () => {
10
  return (
11
  <section className={styles.testingResultWrapper}>
12
  <Collapse
@@ -23,7 +66,10 @@ const TestingResult = () => {
23
  align="center"
24
  className={styles.selectFilesTitle}
25
  >
26
- <span>4/25 Files Selected</span>
 
 
 
27
  <Space size={52}>
28
  <b>Hits</b>
29
  <b>View</b>
@@ -32,21 +78,33 @@ const TestingResult = () => {
32
  ),
33
  children: (
34
  <div>
35
- <SelectFiles></SelectFiles>
36
  </div>
37
  ),
38
  },
39
  ]}
40
  />
41
- <Flex gap={'large'} vertical>
42
- {list.map((x) => (
43
- <Card key={x} title="Default size card" extra={<a href="#">More</a>}>
44
- <p>Card content</p>
45
- <p>Card content</p>
46
- <p>Card content</p>
 
 
 
47
  </Card>
48
  ))}
49
  </Flex>
 
 
 
 
 
 
 
 
 
50
  </section>
51
  );
52
  };
 
1
  import { ReactComponent as SelectedFilesCollapseIcon } from '@/assets/svg/selected-files-collapse.svg';
2
+ import { ITestingChunk } from '@/interfaces/database/knowledge';
3
+ import { Card, Collapse, Flex, Pagination, PaginationProps, Space } from 'antd';
4
+ import { useDispatch, useSelector } from 'umi';
5
+ import { TestingModelState } from '../model';
6
+ import styles from './index.less';
7
  import SelectFiles from './select-files';
8
 
9
+ const similarityList: Array<{ field: keyof ITestingChunk; label: string }> = [
10
+ { field: 'similarity', label: 'Hybrid Similarity' },
11
+ { field: 'term_similarity', label: 'Term Similarity' },
12
+ { field: 'vector_similarity', label: 'Vector Similarity' },
13
+ ];
14
+
15
+ const ChunkTitle = ({ item }: { item: ITestingChunk }) => {
16
+ return (
17
+ <Flex gap={10}>
18
+ {similarityList.map((x) => (
19
+ <Space key={x.field}>
20
+ <span className={styles.similarityCircle}>
21
+ {((item[x.field] as number) * 100).toFixed(2)}%
22
+ </span>
23
+ <span className={styles.similarityText}>Hybrid Similarity</span>
24
+ </Space>
25
+ ))}
26
+ </Flex>
27
+ );
28
+ };
29
+
30
+ interface IProps {
31
+ handleTesting: () => Promise<any>;
32
+ }
33
+
34
+ const TestingResult = ({ handleTesting }: IProps) => {
35
+ const {
36
+ documents,
37
+ chunks,
38
+ total,
39
+ pagination,
40
+ selectedDocumentIds,
41
+ }: TestingModelState = useSelector((state: any) => state.testingModel);
42
+ const dispatch = useDispatch();
43
 
44
+ const onChange: PaginationProps['onChange'] = (pageNumber, pageSize) => {
45
+ console.log('Page: ', pageNumber, pageSize);
46
+ dispatch({
47
+ type: 'testingModel/setPagination',
48
+ payload: { current: pageNumber, pageSize },
49
+ });
50
+ handleTesting();
51
+ };
52
 
 
53
  return (
54
  <section className={styles.testingResultWrapper}>
55
  <Collapse
 
66
  align="center"
67
  className={styles.selectFilesTitle}
68
  >
69
+ <span>
70
+ {selectedDocumentIds?.length ?? 0}/{documents.length} Files
71
+ Selected
72
+ </span>
73
  <Space size={52}>
74
  <b>Hits</b>
75
  <b>View</b>
 
78
  ),
79
  children: (
80
  <div>
81
+ <SelectFiles handleTesting={handleTesting}></SelectFiles>
82
  </div>
83
  ),
84
  },
85
  ]}
86
  />
87
+ <Flex
88
+ gap={'large'}
89
+ vertical
90
+ flex={1}
91
+ className={styles.selectFilesCollapse}
92
+ >
93
+ {chunks.map((x) => (
94
+ <Card key={x.chunk_id} title={<ChunkTitle item={x}></ChunkTitle>}>
95
+ <div>{x.content_with_weight}</div>
96
  </Card>
97
  ))}
98
  </Flex>
99
+ <Pagination
100
+ size={'small'}
101
+ showQuickJumper
102
+ current={pagination.current}
103
+ pageSize={pagination.pageSize}
104
+ total={total}
105
+ showSizeChanger
106
+ onChange={onChange}
107
+ />
108
  </section>
109
  );
110
  };
web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx CHANGED
@@ -1,80 +1,71 @@
1
  import { ReactComponent as NavigationPointerIcon } from '@/assets/svg/navigation-pointer.svg';
 
 
2
  import { Table, TableProps } from 'antd';
 
3
 
4
- interface DataType {
5
- key: string;
6
- name: string;
7
- hits: number;
8
- address: string;
9
- tags: string[];
10
  }
11
 
12
- const SelectFiles = () => {
13
- const columns: TableProps<DataType>['columns'] = [
 
 
 
 
 
 
14
  {
15
  title: 'Name',
16
- dataIndex: 'name',
17
- key: 'name',
18
  render: (text) => <p>{text}</p>,
19
  },
20
 
21
  {
22
  title: 'Hits',
23
- dataIndex: 'hits',
24
- key: 'hits',
25
  width: 80,
26
  },
27
  {
28
  title: 'View',
29
  key: 'view',
30
  width: 50,
31
- render: () => <NavigationPointerIcon />,
 
 
 
 
 
 
 
 
32
  },
33
  ];
34
 
35
  const rowSelection = {
36
- onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => {
37
- console.log(
38
- `selectedRowKeys: ${selectedRowKeys}`,
39
- 'selectedRows: ',
40
- selectedRows,
41
- );
42
  },
43
- getCheckboxProps: (record: DataType) => ({
44
- disabled: record.name === 'Disabled User', // Column configuration not to be checked
45
- name: record.name,
46
  }),
47
  };
48
 
49
- const data: DataType[] = [
50
- {
51
- key: '1',
52
- name: 'John Brown',
53
- hits: 32,
54
- address: 'New York No. 1 Lake Park',
55
- tags: ['nice', 'developer'],
56
- },
57
- {
58
- key: '2',
59
- name: 'Jim Green',
60
- hits: 42,
61
- address: 'London No. 1 Lake Park',
62
- tags: ['loser'],
63
- },
64
- {
65
- key: '3',
66
- name: 'Joe Black',
67
- hits: 32,
68
- address: 'Sydney No. 1 Lake Park',
69
- tags: ['cool', 'teacher'],
70
- },
71
- ];
72
  return (
73
  <Table
74
  columns={columns}
75
- dataSource={data}
76
  showHeader={false}
77
  rowSelection={rowSelection}
 
78
  />
79
  );
80
  };
 
1
  import { ReactComponent as NavigationPointerIcon } from '@/assets/svg/navigation-pointer.svg';
2
+ import { ITestingDocument } from '@/interfaces/database/knowledge';
3
+ import { api_host } from '@/utils/api';
4
  import { Table, TableProps } from 'antd';
5
+ import { useDispatch, useSelector } from 'umi';
6
 
7
+ interface IProps {
8
+ handleTesting: () => Promise<any>;
 
 
 
 
9
  }
10
 
11
+ const SelectFiles = ({ handleTesting }: IProps) => {
12
+ const documents: ITestingDocument[] = useSelector(
13
+ (state: any) => state.testingModel.documents,
14
+ );
15
+
16
+ const dispatch = useDispatch();
17
+
18
+ const columns: TableProps<ITestingDocument>['columns'] = [
19
  {
20
  title: 'Name',
21
+ dataIndex: 'doc_name',
22
+ key: 'doc_name',
23
  render: (text) => <p>{text}</p>,
24
  },
25
 
26
  {
27
  title: 'Hits',
28
+ dataIndex: 'count',
29
+ key: 'count',
30
  width: 80,
31
  },
32
  {
33
  title: 'View',
34
  key: 'view',
35
  width: 50,
36
+ render: (_, { doc_id }) => (
37
+ <a
38
+ href={`${api_host}/document/get/${doc_id}`}
39
+ target="_blank"
40
+ rel="noreferrer"
41
+ >
42
+ <NavigationPointerIcon />
43
+ </a>
44
+ ),
45
  },
46
  ];
47
 
48
  const rowSelection = {
49
+ onChange: (selectedRowKeys: React.Key[]) => {
50
+ dispatch({
51
+ type: 'testingModel/setSelectedDocumentIds',
52
+ payload: selectedRowKeys,
53
+ });
54
+ handleTesting();
55
  },
56
+ getCheckboxProps: (record: ITestingDocument) => ({
57
+ disabled: record.doc_name === 'Disabled User', // Column configuration not to be checked
58
+ name: record.doc_name,
59
  }),
60
  };
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  return (
63
  <Table
64
  columns={columns}
65
+ dataSource={documents}
66
  showHeader={false}
67
  rowSelection={rowSelection}
68
+ rowKey={'doc_id'}
69
  />
70
  );
71
  };
web/src/utils/api.ts CHANGED
@@ -1,4 +1,4 @@
1
- let api_host = `http://223.111.148.200:9380/v1`;
2
 
3
  export { api_host };
4
 
 
1
+ let api_host = `http://123.60.95.134:9380/v1`;
2
 
3
  export { api_host };
4