balibabu commited on
Commit
c5da52f
·
1 Parent(s): fb019e4

Feat: Add TagFeatureItem #4368 (#4432)

Browse files

### What problem does this PR solve?

Feat: Add TagFeatureItem #4368

### Type of change


- [x] New Feature (non-breaking change which adds functionality)

web/src/components/edit-tag/index.tsx CHANGED
@@ -7,11 +7,11 @@ import React, { useEffect, useRef, useState } from 'react';
7
  import styles from './index.less';
8
 
9
  interface EditTagsProps {
10
- tags?: string[];
11
- setTags?: (tags: string[]) => void;
12
  }
13
 
14
- const EditTag = ({ tags, setTags }: EditTagsProps) => {
15
  const { token } = theme.useToken();
16
  const [inputVisible, setInputVisible] = useState(false);
17
  const [inputValue, setInputValue] = useState('');
@@ -24,8 +24,8 @@ const EditTag = ({ tags, setTags }: EditTagsProps) => {
24
  }, [inputVisible]);
25
 
26
  const handleClose = (removedTag: string) => {
27
- const newTags = tags?.filter((tag) => tag !== removedTag);
28
- setTags?.(newTags ?? []);
29
  };
30
 
31
  const showInput = () => {
@@ -37,12 +37,12 @@ const EditTag = ({ tags, setTags }: EditTagsProps) => {
37
  };
38
 
39
  const handleInputConfirm = () => {
40
- if (inputValue && tags) {
41
  const newTags = inputValue
42
  .split(';')
43
  .map((tag) => tag.trim())
44
- .filter((tag) => tag && !tags.includes(tag));
45
- setTags?.([...tags, ...newTags]);
46
  }
47
  setInputVisible(false);
48
  setInputValue('');
@@ -64,7 +64,7 @@ const EditTag = ({ tags, setTags }: EditTagsProps) => {
64
  );
65
  };
66
 
67
- const tagChild = tags?.map(forMap);
68
 
69
  const tagPlusStyle: React.CSSProperties = {
70
  background: token.colorBgContainer,
 
7
  import styles from './index.less';
8
 
9
  interface EditTagsProps {
10
+ value?: string[];
11
+ onChange?: (tags: string[]) => void;
12
  }
13
 
14
+ const EditTag = ({ value = [], onChange }: EditTagsProps) => {
15
  const { token } = theme.useToken();
16
  const [inputVisible, setInputVisible] = useState(false);
17
  const [inputValue, setInputValue] = useState('');
 
24
  }, [inputVisible]);
25
 
26
  const handleClose = (removedTag: string) => {
27
+ const newTags = value?.filter((tag) => tag !== removedTag);
28
+ onChange?.(newTags ?? []);
29
  };
30
 
31
  const showInput = () => {
 
37
  };
38
 
39
  const handleInputConfirm = () => {
40
+ if (inputValue && value) {
41
  const newTags = inputValue
42
  .split(';')
43
  .map((tag) => tag.trim())
44
+ .filter((tag) => tag && !value.includes(tag));
45
+ onChange?.([...value, ...newTags]);
46
  }
47
  setInputVisible(false);
48
  setInputValue('');
 
64
  );
65
  };
66
 
67
+ const tagChild = value?.map(forMap);
68
 
69
  const tagPlusStyle: React.CSSProperties = {
70
  background: token.colorBgContainer,
web/src/components/entity-types-item.tsx CHANGED
@@ -18,8 +18,6 @@ const EntityTypesItem = () => {
18
  label={t('entityTypes')}
19
  rules={[{ required: true }]}
20
  initialValue={initialEntityTypes}
21
- valuePropName="tags"
22
- trigger="setTags"
23
  >
24
  <EditTag></EditTag>
25
  </Form.Item>
 
18
  label={t('entityTypes')}
19
  rules={[{ required: true }]}
20
  initialValue={initialEntityTypes}
 
 
21
  >
22
  <EditTag></EditTag>
23
  </Form.Item>
web/src/hooks/chunk-hooks.ts CHANGED
@@ -194,6 +194,7 @@ export const useFetchChunk = (chunkId?: string): ResponseType<any> => {
194
  queryKey: ['fetchChunk'],
195
  enabled: !!chunkId,
196
  initialData: {},
 
197
  queryFn: async () => {
198
  const data = await kbService.get_chunk({
199
  chunk_id: chunkId,
 
194
  queryKey: ['fetchChunk'],
195
  enabled: !!chunkId,
196
  initialData: {},
197
+ gcTime: 0,
198
  queryFn: async () => {
199
  const data = await kbService.get_chunk({
200
  chunk_id: chunkId,
web/src/hooks/knowledge-hooks.ts CHANGED
@@ -20,6 +20,7 @@ import {
20
  } from '@tanstack/react-query';
21
  import { useDebounce } from 'ahooks';
22
  import { message } from 'antd';
 
23
  import { useSearchParams } from 'umi';
24
  import { useHandleSearchChange } from './logic-hooks';
25
  import { useSetPaginationParams } from './route-hook';
@@ -34,9 +35,9 @@ export const useKnowledgeBaseId = (): string => {
34
  export const useFetchKnowledgeBaseConfiguration = () => {
35
  const knowledgeBaseId = useKnowledgeBaseId();
36
 
37
- const { data, isFetching: loading } = useQuery({
38
  queryKey: ['fetchKnowledgeDetail'],
39
- initialData: {},
40
  gcTime: 0,
41
  queryFn: async () => {
42
  const { data } = await kbService.get_kb_detail({
@@ -341,4 +342,24 @@ export const useTagIsRenaming = () => {
341
  return useIsMutating({ mutationKey: ['renameTag'] }) > 0;
342
  };
343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
  //#endregion
 
20
  } from '@tanstack/react-query';
21
  import { useDebounce } from 'ahooks';
22
  import { message } from 'antd';
23
+ import { useState } from 'react';
24
  import { useSearchParams } from 'umi';
25
  import { useHandleSearchChange } from './logic-hooks';
26
  import { useSetPaginationParams } from './route-hook';
 
35
  export const useFetchKnowledgeBaseConfiguration = () => {
36
  const knowledgeBaseId = useKnowledgeBaseId();
37
 
38
+ const { data, isFetching: loading } = useQuery<IKnowledge>({
39
  queryKey: ['fetchKnowledgeDetail'],
40
+ initialData: {} as IKnowledge,
41
  gcTime: 0,
42
  queryFn: async () => {
43
  const { data } = await kbService.get_kb_detail({
 
342
  return useIsMutating({ mutationKey: ['renameTag'] }) > 0;
343
  };
344
 
345
+ export const useFetchTagListByKnowledgeIds = () => {
346
+ const [knowledgeIds, setKnowledgeIds] = useState<string[]>([]);
347
+
348
+ const { data, isFetching: loading } = useQuery<Array<[string, number]>>({
349
+ queryKey: ['fetchTagListByKnowledgeIds'],
350
+ enabled: knowledgeIds.length > 0,
351
+ initialData: [],
352
+ gcTime: 0, // https://tanstack.com/query/latest/docs/framework/react/guides/caching?from=reactQueryV3
353
+ queryFn: async () => {
354
+ const { data } = await kbService.listTagByKnowledgeIds({
355
+ kb_ids: knowledgeIds.join(','),
356
+ });
357
+ const list = data?.data || [];
358
+ return list;
359
+ },
360
+ });
361
+
362
+ return { list: data, loading, setKnowledgeIds };
363
+ };
364
+
365
  //#endregion
web/src/hooks/logic-hooks.ts CHANGED
@@ -405,30 +405,6 @@ export interface IRemoveMessageById {
405
  removeMessageById(messageId: string): void;
406
  }
407
 
408
- export const useRemoveMessageById = (
409
- setCurrentConversation: (
410
- callback: (state: IClientConversation) => IClientConversation,
411
- ) => void,
412
- ) => {
413
- const removeMessageById = useCallback(
414
- (messageId: string) => {
415
- setCurrentConversation((pre) => {
416
- const nextMessages =
417
- pre.message?.filter(
418
- (x) => getMessagePureId(x.id) !== getMessagePureId(messageId),
419
- ) ?? [];
420
- return {
421
- ...pre,
422
- message: nextMessages,
423
- };
424
- });
425
- },
426
- [setCurrentConversation],
427
- );
428
-
429
- return { removeMessageById };
430
- };
431
-
432
  export const useRemoveMessagesAfterCurrentMessage = (
433
  setCurrentConversation: (
434
  callback: (state: IClientConversation) => IClientConversation,
 
405
  removeMessageById(messageId: string): void;
406
  }
407
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
408
  export const useRemoveMessagesAfterCurrentMessage = (
409
  setCurrentConversation: (
410
  callback: (state: IClientConversation) => IClientConversation,
web/src/interfaces/database/knowledge.ts CHANGED
@@ -11,7 +11,7 @@ export interface IKnowledge {
11
  doc_num: number;
12
  id: string;
13
  name: string;
14
- parser_config: Parserconfig;
15
  parser_id: string;
16
  permission: string;
17
  similarity_threshold: number;
@@ -25,9 +25,22 @@ export interface IKnowledge {
25
  nickname?: string;
26
  }
27
 
28
- export interface Parserconfig {
29
- from_page: number;
30
- to_page: number;
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  }
32
 
33
  export interface IKnowledgeFileParserConfig {
@@ -83,8 +96,11 @@ export interface IChunk {
83
  doc_id: string;
84
  doc_name: string;
85
  img_id: string;
86
- important_kwd: any[];
 
 
87
  positions: number[][];
 
88
  }
89
 
90
  export interface ITestingChunk {
 
11
  doc_num: number;
12
  id: string;
13
  name: string;
14
+ parser_config: ParserConfig;
15
  parser_id: string;
16
  permission: string;
17
  similarity_threshold: number;
 
25
  nickname?: string;
26
  }
27
 
28
+ export interface Raptor {
29
+ use_raptor: boolean;
30
+ }
31
+
32
+ export interface ParserConfig {
33
+ from_page?: number;
34
+ to_page?: number;
35
+ auto_keywords?: number;
36
+ auto_questions?: number;
37
+ chunk_token_num?: number;
38
+ delimiter?: string;
39
+ html4excel?: boolean;
40
+ layout_recognize?: boolean;
41
+ raptor?: Raptor;
42
+ tag_kb_ids?: string[];
43
+ topn_tags?: number;
44
  }
45
 
46
  export interface IKnowledgeFileParserConfig {
 
96
  doc_id: string;
97
  doc_name: string;
98
  img_id: string;
99
+ important_kwd?: string[];
100
+ question_kwd?: string[]; // keywords
101
+ tag_kwd?: string[];
102
  positions: number[][];
103
+ tag_feas?: Record<string, number>;
104
  }
105
 
106
  export interface ITestingChunk {
web/src/locales/en.ts CHANGED
@@ -338,6 +338,8 @@ This procedure will improve precision of retrieval by adding more information to
338
  </ul>
339
  `,
340
  topnTags: 'Top-N Tags',
 
 
341
  },
342
  chunk: {
343
  chunk: 'Chunk',
 
338
  </ul>
339
  `,
340
  topnTags: 'Top-N Tags',
341
+ tags: 'Tags',
342
+ addTag: 'Add tag',
343
  },
344
  chunk: {
345
  chunk: 'Chunk',
web/src/locales/zh-traditional.ts CHANGED
@@ -322,6 +322,8 @@ export default {
322
  <li>關鍵字由 LLM 生成,既昂貴又耗時。
323
  </ul>
324
  `,
 
 
325
  },
326
  chunk: {
327
  chunk: '解析塊',
 
322
  <li>關鍵字由 LLM 生成,既昂貴又耗時。
323
  </ul>
324
  `,
325
+ tags: '標籤',
326
+ addTag: '增加標籤',
327
  },
328
  chunk: {
329
  chunk: '解析塊',
web/src/locales/zh.ts CHANGED
@@ -339,6 +339,8 @@ export default {
339
  <li>关键字由 LLM 生成,这既昂贵又耗时。 </li>
340
  </ul>
341
  `,
 
 
342
  },
343
  chunk: {
344
  chunk: '解析块',
 
339
  <li>关键字由 LLM 生成,这既昂贵又耗时。 </li>
340
  </ul>
341
  `,
342
+ tags: '标签',
343
+ addTag: '增加标签',
344
  },
345
  chunk: {
346
  chunk: '解析块',
web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-creating-modal/index.tsx CHANGED
@@ -1,15 +1,23 @@
1
  import EditTag from '@/components/edit-tag';
2
  import { useFetchChunk } from '@/hooks/chunk-hooks';
3
  import { IModalProps } from '@/interfaces/common';
4
- import { DeleteOutlined, QuestionCircleOutlined } from '@ant-design/icons';
5
- import { Divider, Form, Input, Modal, Space, Switch, Tooltip } from 'antd';
6
- import React, { useEffect, useState } from 'react';
 
7
  import { useTranslation } from 'react-i18next';
8
  import { useDeleteChunkByIds } from '../../hooks';
 
 
 
 
 
 
 
 
 
 
9
 
10
- type FieldType = {
11
- content?: string;
12
- };
13
  interface kFProps {
14
  doc_id: string;
15
  chunkId: string | undefined;
@@ -26,62 +34,48 @@ const ChunkCreatingModal: React.FC<IModalProps<any> & kFProps> = ({
26
  }) => {
27
  const [form] = Form.useForm();
28
  const [checked, setChecked] = useState(false);
29
- const [keywords, setKeywords] = useState<string[]>([]);
30
- const [question, setQuestion] = useState<string[]>([]);
31
- const [tagKeyWords, setTagKeyWords] = useState<string[]>([]);
32
  const { removeChunk } = useDeleteChunkByIds();
33
  const { data } = useFetchChunk(chunkId);
34
  const { t } = useTranslation();
35
 
36
  const isTagParser = parserId === 'tag';
37
 
38
- useEffect(() => {
39
- if (data?.code === 0) {
40
- const {
41
- content_with_weight,
42
- important_kwd = [],
43
- available_int,
44
- question_kwd = [],
45
- tag_kwd = [],
46
- } = data.data;
47
- form.setFieldsValue({ content: content_with_weight });
48
- setKeywords(important_kwd);
49
- setQuestion(question_kwd);
50
- setTagKeyWords(tag_kwd);
51
- setChecked(available_int !== 0);
52
- }
53
-
54
- if (!chunkId) {
55
- setKeywords([]);
56
- setQuestion([]);
57
- setTagKeyWords([]);
58
- form.setFieldsValue({ content: undefined });
59
- }
60
- }, [data, form, chunkId]);
61
-
62
- const handleOk = async () => {
63
  try {
64
  const values = await form.validateFields();
 
 
65
  onOk?.({
66
- content: values.content,
67
- keywords, // keywords
68
- question_kwd: question,
69
- tag_kwd: tagKeyWords,
70
  available_int: checked ? 1 : 0, // available_int
71
  });
72
  } catch (errorInfo) {
73
  console.log('Failed:', errorInfo);
74
  }
75
- };
76
 
77
- const handleRemove = () => {
78
  if (chunkId) {
79
  return removeChunk([chunkId], doc_id);
80
  }
81
- };
82
- const handleCheck = () => {
 
83
  setChecked(!checked);
84
- };
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
  return (
87
  <Modal
@@ -95,31 +89,34 @@ const ChunkCreatingModal: React.FC<IModalProps<any> & kFProps> = ({
95
  <Form form={form} autoComplete="off" layout={'vertical'}>
96
  <Form.Item<FieldType>
97
  label={t('chunk.chunk')}
98
- name="content"
99
  rules={[{ required: true, message: t('chunk.chunkMessage') }]}
100
  >
101
  <Input.TextArea autoSize={{ minRows: 4, maxRows: 10 }} />
102
  </Form.Item>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  </Form>
104
- <section>
105
- <p className="mb-2">{t('chunk.keyword')} </p>
106
- <EditTag tags={keywords} setTags={setKeywords} />
107
- </section>
108
- <section className="mt-4">
109
- <div className="flex items-center gap-2 mb-2">
110
- <span>{t('chunk.question')}</span>
111
- <Tooltip title={t('chunk.questionTip')}>
112
- <QuestionCircleOutlined className="text-xs" />
113
- </Tooltip>
114
- </div>
115
- <EditTag tags={question} setTags={setQuestion} />
116
- </section>
117
- {isTagParser && (
118
- <section className="mt-4">
119
- <p className="mb-2">{t('knowledgeConfiguration.tagName')} </p>
120
- <EditTag tags={tagKeyWords} setTags={setTagKeyWords} />
121
- </section>
122
- )}
123
  {chunkId && (
124
  <section>
125
  <Divider></Divider>
 
1
  import EditTag from '@/components/edit-tag';
2
  import { useFetchChunk } from '@/hooks/chunk-hooks';
3
  import { IModalProps } from '@/interfaces/common';
4
+ import { IChunk } from '@/interfaces/database/knowledge';
5
+ import { DeleteOutlined } from '@ant-design/icons';
6
+ import { Divider, Form, Input, Modal, Space, Switch } from 'antd';
7
+ import React, { useCallback, useEffect, useState } from 'react';
8
  import { useTranslation } from 'react-i18next';
9
  import { useDeleteChunkByIds } from '../../hooks';
10
+ import {
11
+ transformTagFeaturesArrayToObject,
12
+ transformTagFeaturesObjectToArray,
13
+ } from '../../utils';
14
+ import { TagFeatureItem } from './tag-feature-item';
15
+
16
+ type FieldType = Pick<
17
+ IChunk,
18
+ 'content_with_weight' | 'tag_kwd' | 'question_kwd' | 'important_kwd'
19
+ >;
20
 
 
 
 
21
  interface kFProps {
22
  doc_id: string;
23
  chunkId: string | undefined;
 
34
  }) => {
35
  const [form] = Form.useForm();
36
  const [checked, setChecked] = useState(false);
 
 
 
37
  const { removeChunk } = useDeleteChunkByIds();
38
  const { data } = useFetchChunk(chunkId);
39
  const { t } = useTranslation();
40
 
41
  const isTagParser = parserId === 'tag';
42
 
43
+ const handleOk = useCallback(async () => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  try {
45
  const values = await form.validateFields();
46
+ console.log('🚀 ~ handleOk ~ values:', values);
47
+
48
  onOk?.({
49
+ ...values,
50
+ tag_feas: transformTagFeaturesArrayToObject(values.tag_feas),
 
 
51
  available_int: checked ? 1 : 0, // available_int
52
  });
53
  } catch (errorInfo) {
54
  console.log('Failed:', errorInfo);
55
  }
56
+ }, [checked, form, onOk]);
57
 
58
+ const handleRemove = useCallback(() => {
59
  if (chunkId) {
60
  return removeChunk([chunkId], doc_id);
61
  }
62
+ }, [chunkId, doc_id, removeChunk]);
63
+
64
+ const handleCheck = useCallback(() => {
65
  setChecked(!checked);
66
+ }, [checked]);
67
+
68
+ useEffect(() => {
69
+ if (data?.code === 0) {
70
+ const { available_int, tag_feas } = data.data;
71
+ form.setFieldsValue({
72
+ ...(data.data || {}),
73
+ tag_feas: transformTagFeaturesObjectToArray(tag_feas),
74
+ });
75
+
76
+ setChecked(available_int !== 0);
77
+ }
78
+ }, [data, form, chunkId]);
79
 
80
  return (
81
  <Modal
 
89
  <Form form={form} autoComplete="off" layout={'vertical'}>
90
  <Form.Item<FieldType>
91
  label={t('chunk.chunk')}
92
+ name="content_with_weight"
93
  rules={[{ required: true, message: t('chunk.chunkMessage') }]}
94
  >
95
  <Input.TextArea autoSize={{ minRows: 4, maxRows: 10 }} />
96
  </Form.Item>
97
+
98
+ <Form.Item<FieldType> label={t('chunk.keyword')} name="important_kwd">
99
+ <EditTag></EditTag>
100
+ </Form.Item>
101
+ <Form.Item<FieldType>
102
+ label={t('chunk.question')}
103
+ name="question_kwd"
104
+ tooltip={t('chunk.questionTip')}
105
+ >
106
+ <EditTag></EditTag>
107
+ </Form.Item>
108
+ {isTagParser && (
109
+ <Form.Item<FieldType>
110
+ label={t('knowledgeConfiguration.tagName')}
111
+ name="tag_kwd"
112
+ >
113
+ <EditTag></EditTag>
114
+ </Form.Item>
115
+ )}
116
+
117
+ {!isTagParser && <TagFeatureItem></TagFeatureItem>}
118
  </Form>
119
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  {chunkId && (
121
  <section>
122
  <Divider></Divider>
web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-creating-modal/tag-feature-item.tsx ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ useFetchKnowledgeBaseConfiguration,
3
+ useFetchTagListByKnowledgeIds,
4
+ } from '@/hooks/knowledge-hooks';
5
+ import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
6
+ import { Button, Form, InputNumber, Select } from 'antd';
7
+ import { useCallback, useEffect, useMemo } from 'react';
8
+ import { useTranslation } from 'react-i18next';
9
+ import { FormListItem } from '../../utils';
10
+
11
+ const FieldKey = 'tag_feas';
12
+
13
+ export const TagFeatureItem = () => {
14
+ const form = Form.useFormInstance();
15
+ const { t } = useTranslation();
16
+ const { data: knowledgeConfiguration } = useFetchKnowledgeBaseConfiguration();
17
+
18
+ const { setKnowledgeIds, list } = useFetchTagListByKnowledgeIds();
19
+
20
+ const tagKnowledgeIds = useMemo(() => {
21
+ return knowledgeConfiguration?.parser_config?.tag_kb_ids ?? [];
22
+ }, [knowledgeConfiguration?.parser_config?.tag_kb_ids]);
23
+
24
+ const options = useMemo(() => {
25
+ return list.map((x) => ({
26
+ value: x[0],
27
+ label: x[0],
28
+ }));
29
+ }, [list]);
30
+
31
+ const filterOptions = useCallback(
32
+ (index: number) => {
33
+ const tags: FormListItem[] = form.getFieldValue(FieldKey) ?? [];
34
+
35
+ // Exclude it's own current data
36
+ const list = tags
37
+ .filter((x, idx) => x && index !== idx)
38
+ .map((x) => x.tag);
39
+
40
+ // Exclude the selected data from other options from one's own options.
41
+ return options.filter((x) => !list.some((y) => x.value === y));
42
+ },
43
+ [form, options],
44
+ );
45
+
46
+ useEffect(() => {
47
+ setKnowledgeIds(tagKnowledgeIds);
48
+ }, [setKnowledgeIds, tagKnowledgeIds]);
49
+
50
+ return (
51
+ <Form.Item label={t('knowledgeConfiguration.tags')}>
52
+ <Form.List name={FieldKey} initialValue={[]}>
53
+ {(fields, { add, remove }) => (
54
+ <>
55
+ {fields.map(({ key, name, ...restField }) => (
56
+ <div key={key} className="flex gap-3 items-center">
57
+ <div className="flex flex-1 gap-8">
58
+ <Form.Item
59
+ {...restField}
60
+ name={[name, 'tag']}
61
+ rules={[
62
+ { required: true, message: t('common.pleaseSelect') },
63
+ ]}
64
+ className="w-2/3"
65
+ >
66
+ <Select
67
+ showSearch
68
+ placeholder={t('knowledgeConfiguration.tagName')}
69
+ options={filterOptions(name)}
70
+ />
71
+ </Form.Item>
72
+ <Form.Item
73
+ {...restField}
74
+ name={[name, 'frequency']}
75
+ rules={[
76
+ { required: true, message: t('common.pleaseInput') },
77
+ ]}
78
+ >
79
+ <InputNumber
80
+ placeholder={t('knowledgeConfiguration.frequency')}
81
+ max={10}
82
+ min={0}
83
+ />
84
+ </Form.Item>
85
+ </div>
86
+ <MinusCircleOutlined
87
+ onClick={() => remove(name)}
88
+ className="mb-6"
89
+ />
90
+ </div>
91
+ ))}
92
+ <Form.Item>
93
+ <Button
94
+ type="dashed"
95
+ onClick={() => add()}
96
+ block
97
+ icon={<PlusOutlined />}
98
+ >
99
+ {t('knowledgeConfiguration.addTag')}
100
+ </Button>
101
+ </Form.Item>
102
+ </>
103
+ )}
104
+ </Form.List>
105
+ </Form.Item>
106
+ );
107
+ };
web/src/pages/add-knowledge/components/knowledge-chunk/hooks.ts CHANGED
@@ -95,27 +95,11 @@ export const useUpdateChunk = () => {
95
  const { documentId } = useGetKnowledgeSearchParams();
96
 
97
  const onChunkUpdatingOk = useCallback(
98
- async ({
99
- content,
100
- keywords,
101
- available_int,
102
- question_kwd,
103
- tag_kwd,
104
- }: {
105
- content: string;
106
- keywords: string;
107
- available_int: number;
108
- question_kwd: string;
109
- tag_kwd: string;
110
- }) => {
111
  const code = await createChunk({
112
- content_with_weight: content,
113
  doc_id: documentId,
114
  chunk_id: chunkId,
115
- important_kwd: keywords, // keywords
116
- available_int,
117
- question_kwd,
118
- tag_kwd,
119
  });
120
 
121
  if (code === 0) {
 
95
  const { documentId } = useGetKnowledgeSearchParams();
96
 
97
  const onChunkUpdatingOk = useCallback(
98
+ async (params: IChunk) => {
 
 
 
 
 
 
 
 
 
 
 
 
99
  const code = await createChunk({
100
+ ...params,
101
  doc_id: documentId,
102
  chunk_id: chunkId,
 
 
 
 
103
  });
104
 
105
  if (code === 0) {
web/src/pages/add-knowledge/components/knowledge-chunk/utils.ts ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export type FormListItem = {
2
+ frequency: number;
3
+ tag: string;
4
+ };
5
+
6
+ export function transformTagFeaturesArrayToObject(
7
+ list: Array<FormListItem> = [],
8
+ ) {
9
+ return list.reduce<Record<string, number>>((pre, cur) => {
10
+ pre[cur.tag] = cur.frequency;
11
+
12
+ return pre;
13
+ }, {});
14
+ }
15
+
16
+ export function transformTagFeaturesObjectToArray(
17
+ object: Record<string, number> = {},
18
+ ) {
19
+ return Object.keys(object).reduce<Array<FormListItem>>((pre, key) => {
20
+ pre.push({ frequency: object[key], tag: key });
21
+
22
+ return pre;
23
+ }, []);
24
+ }
web/src/services/knowledge-service.ts CHANGED
@@ -30,6 +30,7 @@ const {
30
  knowledge_graph,
31
  document_infos,
32
  upload_and_parse,
 
33
  } = api;
34
 
35
  const methods = {
@@ -140,6 +141,10 @@ const methods = {
140
  url: upload_and_parse,
141
  method: 'post',
142
  },
 
 
 
 
143
  };
144
 
145
  const kbService = registerServer<keyof typeof methods>(methods, request);
 
30
  knowledge_graph,
31
  document_infos,
32
  upload_and_parse,
33
+ listTagByKnowledgeIds,
34
  } = api;
35
 
36
  const methods = {
 
141
  url: upload_and_parse,
142
  method: 'post',
143
  },
144
+ listTagByKnowledgeIds: {
145
+ url: listTagByKnowledgeIds,
146
+ method: 'get',
147
+ },
148
  };
149
 
150
  const kbService = registerServer<keyof typeof methods>(methods, request);
web/src/utils/api.ts CHANGED
@@ -39,6 +39,7 @@ export default {
39
 
40
  // tags
41
  listTag: (knowledgeId: string) => `${api_host}/kb/${knowledgeId}/tags`,
 
42
  removeTag: (knowledgeId: string) => `${api_host}/kb/${knowledgeId}/rm_tags`,
43
  renameTag: (knowledgeId: string) =>
44
  `${api_host}/kb/${knowledgeId}/rename_tag`,
 
39
 
40
  // tags
41
  listTag: (knowledgeId: string) => `${api_host}/kb/${knowledgeId}/tags`,
42
+ listTagByKnowledgeIds: `${api_host}/kb/tags`,
43
  removeTag: (knowledgeId: string) => `${api_host}/kb/${knowledgeId}/rm_tags`,
44
  renameTag: (knowledgeId: string) =>
45
  `${api_host}/kb/${knowledgeId}/rename_tag`,