balibabu commited on
Commit
badd5fe
·
1 Parent(s): 429cc62

fix: #209 after saving the knowledge base configuration, jump to the dataset page (#212)

Browse files

### What problem does this PR solve?
fix: #209 after saving the knowledge base configuration, jump to the
dataset page
feat: translate ConfigurationForm
feat: translate KnowledgeTesting
feat: translate document list page
feat: translate knowledge list page

Issue link: #209

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)

web/src/components/chunk-method-modal/index.tsx CHANGED
@@ -22,6 +22,7 @@ import omit from 'lodash/omit';
22
  import React, { useEffect, useMemo } from 'react';
23
  import { useFetchParserListOnMount } from './hooks';
24
 
 
25
  import styles from './index.less';
26
 
27
  const { CheckableTag } = Tag;
@@ -56,6 +57,7 @@ const ChunkMethodModal: React.FC<IProps> = ({
56
  documentExtension,
57
  );
58
  const [form] = Form.useForm();
 
59
 
60
  const handleOk = async () => {
61
  const values = await form.validateFields();
@@ -91,7 +93,7 @@ const ChunkMethodModal: React.FC<IProps> = ({
91
 
92
  return (
93
  <Modal
94
- title="Chunk Method"
95
  open={visible}
96
  onOk={handleOk}
97
  onCancel={hideModal}
 
22
  import React, { useEffect, useMemo } from 'react';
23
  import { useFetchParserListOnMount } from './hooks';
24
 
25
+ import { useTranslate } from '@/hooks/commonHooks';
26
  import styles from './index.less';
27
 
28
  const { CheckableTag } = Tag;
 
57
  documentExtension,
58
  );
59
  const [form] = Form.useForm();
60
+ const { t } = useTranslate('knowledgeDetails');
61
 
62
  const handleOk = async () => {
63
  const values = await form.validateFields();
 
93
 
94
  return (
95
  <Modal
96
+ title={t('chunkMethod')}
97
  open={visible}
98
  onOk={handleOk}
99
  onCancel={hideModal}
web/src/components/similarity-slider/index.tsx CHANGED
@@ -1,3 +1,4 @@
 
1
  import { Form, Slider } from 'antd';
2
 
3
  type FieldType = {
@@ -10,27 +11,23 @@ interface IProps {
10
  }
11
 
12
  const SimilaritySlider = ({ isTooltipShown = false }: IProps) => {
 
 
13
  return (
14
  <>
15
  <Form.Item<FieldType>
16
- label="Similarity threshold"
17
  name={'similarity_threshold'}
18
- tooltip={isTooltipShown && `We use hybrid similarity score to evaluate distance between two lines of text.
19
- It\'s weighted keywords similarity and vector cosine similarity.
20
- If the similarity between query and chunk is less than this threshold, the chunk will be filtered out.`
21
- }
22
  initialValue={0.2}
23
  >
24
  <Slider max={1} step={0.01} />
25
  </Form.Item>
26
  <Form.Item<FieldType>
27
- label="Vector similarity weight"
28
  name={'vector_similarity_weight'}
29
  initialValue={0.3}
30
- tooltip={isTooltipShown && `We use hybrid similarity score to evaluate distance between two lines of text.
31
- It\'s weighted keywords similarity and vector cosine similarity.
32
- The sum of both weights is 1.0.
33
- `}
34
  >
35
  <Slider max={1} step={0.01} />
36
  </Form.Item>
 
1
+ import { useTranslate } from '@/hooks/commonHooks';
2
  import { Form, Slider } from 'antd';
3
 
4
  type FieldType = {
 
11
  }
12
 
13
  const SimilaritySlider = ({ isTooltipShown = false }: IProps) => {
14
+ const { t } = useTranslate('knowledgeDetails');
15
+
16
  return (
17
  <>
18
  <Form.Item<FieldType>
19
+ label={t('similarityThreshold')}
20
  name={'similarity_threshold'}
21
+ tooltip={isTooltipShown && t('similarityThresholdTip')}
 
 
 
22
  initialValue={0.2}
23
  >
24
  <Slider max={1} step={0.01} />
25
  </Form.Item>
26
  <Form.Item<FieldType>
27
+ label={t('vectorSimilarityWeight')}
28
  name={'vector_similarity_weight'}
29
  initialValue={0.3}
30
+ tooltip={isTooltipShown && t('vectorSimilarityWeightTip')}
 
 
 
31
  >
32
  <Slider max={1} step={0.01} />
33
  </Form.Item>
web/src/hooks/commonHooks.tsx CHANGED
@@ -92,9 +92,9 @@ export const useShowDeleteConfirm = () => {
92
  title: t('common.deleteModalTitle'),
93
  icon: <ExclamationCircleFilled />,
94
  // content: 'Some descriptions',
95
- okText: 'Yes',
96
  okType: 'danger',
97
- cancelText: 'No',
98
  async onOk() {
99
  try {
100
  const ret = await onOk?.();
@@ -115,3 +115,7 @@ export const useShowDeleteConfirm = () => {
115
 
116
  return showDeleteConfirm;
117
  };
 
 
 
 
 
92
  title: t('common.deleteModalTitle'),
93
  icon: <ExclamationCircleFilled />,
94
  // content: 'Some descriptions',
95
+ okText: t('common.ok'),
96
  okType: 'danger',
97
+ cancelText: t('common.cancel'),
98
  async onOk() {
99
  try {
100
  const ret = await onOk?.();
 
115
 
116
  return showDeleteConfirm;
117
  };
118
+
119
+ export const useTranslate = (keyPrefix: string) => {
120
+ return useTranslation('translation', { keyPrefix });
121
+ };
web/src/hooks/routeHook.ts CHANGED
@@ -1,4 +1,7 @@
1
- import { KnowledgeSearchParams } from '@/constants/knowledge';
 
 
 
2
  import { useCallback } from 'react';
3
  import { useLocation, useNavigate, useSearchParams } from 'umi';
4
 
@@ -42,3 +45,12 @@ export const useNavigateWithFromState = () => {
42
  [navigate],
43
  );
44
  };
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ KnowledgeRouteKey,
3
+ KnowledgeSearchParams,
4
+ } from '@/constants/knowledge';
5
  import { useCallback } from 'react';
6
  import { useLocation, useNavigate, useSearchParams } from 'umi';
7
 
 
45
  [navigate],
46
  );
47
  };
48
+
49
+ export const useNavigateToDataset = () => {
50
+ const navigate = useNavigate();
51
+ const { knowledgeId } = useGetKnowledgeSearchParams();
52
+
53
+ return useCallback(() => {
54
+ navigate(`/knowledge/${KnowledgeRouteKey.Dataset}?id=${knowledgeId}`);
55
+ }, [knowledgeId, navigate]);
56
+ };
web/src/locales/config.ts CHANGED
@@ -5,12 +5,8 @@ import translation_en from './en.json';
5
  import translation_zh from './zh.json';
6
 
7
  const resources = {
8
- en: {
9
- translation: translation_en,
10
- },
11
- zh: {
12
- translation: translation_zh,
13
- },
14
  };
15
 
16
  i18n.use(initReactI18next).init({
 
5
  import translation_zh from './zh.json';
6
 
7
  const resources = {
8
+ en: translation_en,
9
+ zh: translation_zh,
 
 
 
 
10
  };
11
 
12
  i18n.use(initReactI18next).init({
web/src/locales/en.json CHANGED
@@ -1,50 +1,122 @@
1
  {
2
- "common": {
3
- "delete": "Delete",
4
- "deleteModalTitle": "Are you sure delete this item?"
5
- },
6
- "login": {
7
- "login": "Sign in",
8
- "signUp": "Sign up",
9
- "loginDescription": "We’re so excited to see you again!",
10
- "registerDescription": "Glad to have you on board!",
11
- "emailLabel": "Email",
12
- "emailPlaceholder": "Please input email",
13
- "passwordLabel": "Password",
14
- "passwordPlaceholder": "Please input password",
15
- "rememberMe": "Remember me",
16
- "signInTip": "Dont have an account?",
17
- "signUpTip": "Already have an account?",
18
- "nicknameLabel": "Nickname",
19
- "nicknamePlaceholder": "Please input nickname",
20
- "register": "Create an account",
21
- "continue": "Continue"
22
- },
23
- "header": {
24
- "knowledgeBase": "Knowledge Base",
25
- "chat": "Chat",
26
- "register": "Register",
27
- "signin": "Sign in",
28
- "home": "Home",
29
- "setting": "用户设置",
30
- "logout": "登出"
31
- },
32
- "knowledgeList": {
33
- "welcome": "Welcome back",
34
- "description": "Which database are we going to use today?",
35
- "createKnowledgeBase": "Create knowledge base",
36
- "name": "Name",
37
- "namePlaceholder": "Please input name!"
38
- },
39
- "footer": {
40
- "detail": "All rights reserved @ React"
41
- },
42
- "layout": {
43
- "file": "file",
44
- "knowledge": "knowledge",
45
- "chat": "chat"
46
- },
47
- "setting": {
48
- "btn": "en"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  }
50
  }
 
1
  {
2
+ "translation": {
3
+ "common": {
4
+ "delete": "Delete",
5
+ "deleteModalTitle": "Are you sure delete this item?",
6
+ "ok": "Yes",
7
+ "cancel": "No",
8
+ "total": "Total",
9
+ "rename": "Rename",
10
+ "name": "Name",
11
+ "namePlaceholder": "Please input name"
12
+ },
13
+ "login": {
14
+ "login": "Sign in",
15
+ "signUp": "Sign up",
16
+ "loginDescription": "Were so excited to see you again!",
17
+ "registerDescription": "Glad to have you on board!",
18
+ "emailLabel": "Email",
19
+ "emailPlaceholder": "Please input email",
20
+ "passwordLabel": "Password",
21
+ "passwordPlaceholder": "Please input password",
22
+ "rememberMe": "Remember me",
23
+ "signInTip": "Don’t have an account?",
24
+ "signUpTip": "Already have an account?",
25
+ "nicknameLabel": "Nickname",
26
+ "nicknamePlaceholder": "Please input nickname",
27
+ "register": "Create an account",
28
+ "continue": "Continue"
29
+ },
30
+ "header": {
31
+ "knowledgeBase": "Knowledge Base",
32
+ "chat": "Chat",
33
+ "register": "Register",
34
+ "signin": "Sign in",
35
+ "home": "Home",
36
+ "setting": "用户设置",
37
+ "logout": "登出"
38
+ },
39
+ "knowledgeList": {
40
+ "welcome": "Welcome back",
41
+ "description": "Which database are we going to use today?",
42
+ "createKnowledgeBase": "Create knowledge base",
43
+ "name": "Name",
44
+ "namePlaceholder": "Please input name!",
45
+ "doc": "Docs"
46
+ },
47
+ "knowledgeDetails": {
48
+ "dataset": "Dataset",
49
+ "testing": "Retrieval testing",
50
+ "configuration": "Configuration",
51
+ "name": "Name",
52
+ "namePlaceholder": "Please input name!",
53
+ "doc": "Docs",
54
+ "datasetDescription": "Hey, don't forget to adjust the chunk after adding the dataset! 😉",
55
+ "addFile": "Add file",
56
+ "searchFiles": "Search your files",
57
+ "localFiles": "Local files",
58
+ "emptyFiles": "Create empty file",
59
+ "chunkNumber": "Chunk Number",
60
+ "uploadDate": "Upload Date",
61
+ "chunkMethod": "Chunk Method",
62
+ "enabled": "Enabled",
63
+ "action": "Action",
64
+ "parsingStatus": "Parsing Status",
65
+ "processBeginAt": "Process Begin At",
66
+ "processDuration": "Process Duration",
67
+ "progressMsg": "Progress Msg",
68
+ "testingDescription": "Final step! After success, leave the rest to Infiniflow AI.",
69
+ "topK": "Top K",
70
+ "topKTip": "For the computaion cost, not all the retrieved chunk will be computed vector cosine similarity with query. The bigger the 'Top K' is, the higher the recall rate is, the slower the retrieval speed is.",
71
+ "similarityThreshold": "Similarity threshold",
72
+ "similarityThresholdTip": "We use hybrid similarity score to evaluate distance between two lines of text. It's weighted keywords similarity and vector cosine similarity. If the similarity between query and chunk is less than this threshold, the chunk will be filtered out.",
73
+ "vectorSimilarityWeight": "Vector similarity weight",
74
+ "vectorSimilarityWeightTip": "We use hybrid similarity score to evaluate distance between two lines of text. It's weighted keywords similarity and vector cosine similarity. The sum of both weights is 1.0.",
75
+ "testText": "Test text",
76
+ "testTextPlaceholder": "Please input your question!",
77
+ "testingLabel": "Testing",
78
+ "similarity": "Hybrid Similarity",
79
+ "termSimilarity": "Term Similarity",
80
+ "vectorSimilarity": "Vector Similarity",
81
+ "hits": "Hits",
82
+ "view": "View",
83
+ "filesSelected": "Files Selected"
84
+ },
85
+ "knowledgeConfiguration": {
86
+ "titleDescription": "Update your knowledge base details especially parsing method here.",
87
+ "name": "Knowledge base name",
88
+ "photo": "Knowledge base photo",
89
+ "description": "Description",
90
+ "language": "Language",
91
+ "languageMessage": "Please input your language!",
92
+ "languagePlaceholder": "Please input your language!",
93
+ "permissions": "Permissions",
94
+ "embeddingModel": "Embedding model",
95
+ "chunkTokenNumber": "Chunk token number",
96
+ "embeddingModelTip": "The embedding model used to embedding chunks. It's unchangable once the knowledgebase has chunks. You need to delete all the chunks if you want to change it.",
97
+ "permissionsTip": "If the permission is 'Team', all the team member can manipulate the knowledgebase.",
98
+ "chunkTokenNumberTip": "It determine the token number of a chunk approximately.",
99
+ "chunkMethodTip": "The instruction is at right.",
100
+ "upload": "Upload",
101
+ "english": "English",
102
+ "chinese": "Chinese",
103
+ "embeddingModelPlaceholder": "Please select a embedding model",
104
+ "chunkMethodPlaceholder": "Please select a chunk method",
105
+ "save": "Save",
106
+ "me": "Only me",
107
+ "team": "Team",
108
+ "cancel": "Cancel"
109
+ },
110
+ "footer": {
111
+ "detail": "All rights reserved @ React"
112
+ },
113
+ "layout": {
114
+ "file": "file",
115
+ "knowledge": "knowledge",
116
+ "chat": "chat"
117
+ },
118
+ "setting": {
119
+ "btn": "en"
120
+ }
121
  }
122
  }
web/src/locales/zh.json CHANGED
@@ -1,21 +1,23 @@
1
  {
2
- "login": { "login": "登录" },
3
- "header": {
4
- "register": "注册",
5
- "signin": "登陆",
6
- "home": "首页",
7
- "setting": "user setting",
8
- "logout": "logout"
9
- },
10
- "footer": {
11
- "detail": "版权所有 @ React"
12
- },
13
- "layout": {
14
- "file": "文件",
15
- "knowledge": "知识库",
16
- "chat": "聊天"
17
- },
18
- "setting": {
19
- "btn": "中文"
 
 
20
  }
21
  }
 
1
  {
2
+ "translation": {
3
+ "login": { "login": "登录" },
4
+ "header": {
5
+ "register": "注册",
6
+ "signin": "登陆",
7
+ "home": "首页",
8
+ "setting": "user setting",
9
+ "logout": "logout"
10
+ },
11
+ "footer": {
12
+ "detail": "版权所有 @ React"
13
+ },
14
+ "layout": {
15
+ "file": "文件",
16
+ "knowledge": "知识库",
17
+ "chat": "聊天"
18
+ },
19
+ "setting": {
20
+ "btn": "中文"
21
+ }
22
  }
23
  }
web/src/pages/add-knowledge/components/knowledge-file/index.tsx CHANGED
@@ -42,6 +42,7 @@ import ParsingStatusCell from './parsing-status-cell';
42
  import RenameModal from './rename-modal';
43
 
44
  import { useSetSelectedRecord } from '@/hooks/logicHooks';
 
45
  import styles from './index.less';
46
 
47
  const KnowledgeFile = () => {
@@ -76,6 +77,9 @@ const KnowledgeFile = () => {
76
  hideChangeParserModal,
77
  showChangeParserModal,
78
  } = useChangeDocumentParser(currentRecord.id);
 
 
 
79
 
80
  const actionItems: MenuProps['items'] = useMemo(() => {
81
  return [
@@ -87,7 +91,7 @@ const KnowledgeFile = () => {
87
  <Button type="link">
88
  <Space>
89
  <FileTextOutlined />
90
- Local files
91
  </Space>
92
  </Button>
93
  </div>
@@ -101,18 +105,18 @@ const KnowledgeFile = () => {
101
  <div>
102
  <Button type="link">
103
  <FileOutlined />
104
- Create empty file
105
  </Button>
106
  </div>
107
  ),
108
  // disabled: true,
109
  },
110
  ];
111
- }, [linkToUploadPage, showCreateModal]);
112
 
113
  const columns: ColumnsType<IKnowledgeFile> = [
114
  {
115
- title: 'Name',
116
  dataIndex: 'name',
117
  key: 'name',
118
  fixed: 'left',
@@ -133,17 +137,17 @@ const KnowledgeFile = () => {
133
  ),
134
  },
135
  {
136
- title: 'Chunk Number',
137
  dataIndex: 'chunk_num',
138
  key: 'chunk_num',
139
  },
140
  {
141
- title: 'Upload Date',
142
  dataIndex: 'create_date',
143
  key: 'create_date',
144
  },
145
  {
146
- title: 'Chunk Method',
147
  dataIndex: 'parser_id',
148
  key: 'parser_id',
149
  render: (text) => {
@@ -151,7 +155,7 @@ const KnowledgeFile = () => {
151
  },
152
  },
153
  {
154
- title: 'Enabled',
155
  key: 'status',
156
  dataIndex: 'status',
157
  render: (_, { status, id }) => (
@@ -166,7 +170,7 @@ const KnowledgeFile = () => {
166
  ),
167
  },
168
  {
169
- title: 'Parsing Status',
170
  dataIndex: 'run',
171
  key: 'run',
172
  render: (text, record) => {
@@ -174,7 +178,7 @@ const KnowledgeFile = () => {
174
  },
175
  },
176
  {
177
- title: 'Action',
178
  key: 'action',
179
  render: (_, record) => (
180
  <ParsingActionCell
@@ -194,17 +198,17 @@ const KnowledgeFile = () => {
194
 
195
  return (
196
  <div className={styles.datasetWrapper}>
197
- <h3>Dataset</h3>
198
- <p>Hey, don't forget to adjust the chunk after adding the dataset! 😉</p>
199
  <Divider></Divider>
200
  <div className={styles.filter}>
201
  <Space>
202
- <h3>Total</h3>
203
  <Tag color="purple">{total} files</Tag>
204
  </Space>
205
  <Space>
206
  <Input
207
- placeholder="Seach your files"
208
  value={searchString}
209
  style={{ width: 220 }}
210
  allowClear
@@ -214,7 +218,7 @@ const KnowledgeFile = () => {
214
 
215
  <Dropdown menu={{ items: actionItems }} trigger={['click']}>
216
  <Button type="primary" icon={<PlusOutlined />}>
217
- Add file
218
  </Button>
219
  </Dropdown>
220
  </Space>
 
42
  import RenameModal from './rename-modal';
43
 
44
  import { useSetSelectedRecord } from '@/hooks/logicHooks';
45
+ import { useTranslation } from 'react-i18next';
46
  import styles from './index.less';
47
 
48
  const KnowledgeFile = () => {
 
77
  hideChangeParserModal,
78
  showChangeParserModal,
79
  } = useChangeDocumentParser(currentRecord.id);
80
+ const { t } = useTranslation('translation', {
81
+ keyPrefix: 'knowledgeDetails',
82
+ });
83
 
84
  const actionItems: MenuProps['items'] = useMemo(() => {
85
  return [
 
91
  <Button type="link">
92
  <Space>
93
  <FileTextOutlined />
94
+ {t('localFiles')}
95
  </Space>
96
  </Button>
97
  </div>
 
105
  <div>
106
  <Button type="link">
107
  <FileOutlined />
108
+ {t('emptyFiles')}
109
  </Button>
110
  </div>
111
  ),
112
  // disabled: true,
113
  },
114
  ];
115
+ }, [linkToUploadPage, showCreateModal, t]);
116
 
117
  const columns: ColumnsType<IKnowledgeFile> = [
118
  {
119
+ title: t('name'),
120
  dataIndex: 'name',
121
  key: 'name',
122
  fixed: 'left',
 
137
  ),
138
  },
139
  {
140
+ title: t('chunkNumber'),
141
  dataIndex: 'chunk_num',
142
  key: 'chunk_num',
143
  },
144
  {
145
+ title: t('uploadDate'),
146
  dataIndex: 'create_date',
147
  key: 'create_date',
148
  },
149
  {
150
+ title: t('chunkMethod'),
151
  dataIndex: 'parser_id',
152
  key: 'parser_id',
153
  render: (text) => {
 
155
  },
156
  },
157
  {
158
+ title: t('enabled'),
159
  key: 'status',
160
  dataIndex: 'status',
161
  render: (_, { status, id }) => (
 
170
  ),
171
  },
172
  {
173
+ title: t('parsingStatus'),
174
  dataIndex: 'run',
175
  key: 'run',
176
  render: (text, record) => {
 
178
  },
179
  },
180
  {
181
+ title: t('action'),
182
  key: 'action',
183
  render: (_, record) => (
184
  <ParsingActionCell
 
198
 
199
  return (
200
  <div className={styles.datasetWrapper}>
201
+ <h3>{t('dataset')}</h3>
202
+ <p>{t('datasetDescription')}</p>
203
  <Divider></Divider>
204
  <div className={styles.filter}>
205
  <Space>
206
+ <h3>{t('total', { keyPrefix: 'common' })}</h3>
207
  <Tag color="purple">{total} files</Tag>
208
  </Space>
209
  <Space>
210
  <Input
211
+ placeholder={t('searchFiles')}
212
  value={searchString}
213
  style={{ width: 220 }}
214
  allowClear
 
218
 
219
  <Dropdown menu={{ items: actionItems }} trigger={['click']}>
220
  <Button type="primary" icon={<PlusOutlined />}>
221
+ {t('addFile')}
222
  </Button>
223
  </Dropdown>
224
  </Space>
web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { useShowDeleteConfirm } from '@/hooks/commonHooks';
2
  import { useRemoveDocument } from '@/hooks/documentHooks';
3
  import { IKnowledgeFile } from '@/interfaces/database/knowledge';
4
  import { api_host } from '@/utils/api';
@@ -29,7 +29,7 @@ const ParsingActionCell = ({
29
  }: IProps) => {
30
  const documentId = record.id;
31
  const isRunning = isParserRunning(record.run);
32
-
33
  const removeDocument = useRemoveDocument(documentId);
34
  const showDeleteConfirm = useShowDeleteConfirm();
35
 
@@ -65,7 +65,7 @@ const ParsingActionCell = ({
65
  label: (
66
  <div>
67
  <Button type="link" onClick={onShowChangeParserModal}>
68
- Chunk Method
69
  </Button>
70
  </div>
71
  ),
@@ -83,7 +83,7 @@ const ParsingActionCell = ({
83
  <ToolOutlined size={20} />
84
  </Button>
85
  </Dropdown>
86
- <Tooltip title="Rename">
87
  <Button
88
  type="text"
89
  disabled={isRunning}
 
1
+ import { useShowDeleteConfirm, useTranslate } from '@/hooks/commonHooks';
2
  import { useRemoveDocument } from '@/hooks/documentHooks';
3
  import { IKnowledgeFile } from '@/interfaces/database/knowledge';
4
  import { api_host } from '@/utils/api';
 
29
  }: IProps) => {
30
  const documentId = record.id;
31
  const isRunning = isParserRunning(record.run);
32
+ const { t } = useTranslate('knowledgeDetails');
33
  const removeDocument = useRemoveDocument(documentId);
34
  const showDeleteConfirm = useShowDeleteConfirm();
35
 
 
65
  label: (
66
  <div>
67
  <Button type="link" onClick={onShowChangeParserModal}>
68
+ {t('chunkMethod')}
69
  </Button>
70
  </div>
71
  ),
 
83
  <ToolOutlined size={20} />
84
  </Button>
85
  </Dropdown>
86
+ <Tooltip title={t('rename', { keyPrefix: 'common' })}>
87
  <Button
88
  type="text"
89
  disabled={isRunning}
web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.tsx CHANGED
@@ -1,5 +1,6 @@
1
  import { ReactComponent as RefreshIcon } from '@/assets/svg/refresh.svg';
2
  import { ReactComponent as RunIcon } from '@/assets/svg/run.svg';
 
3
  import { IKnowledgeFile } from '@/interfaces/database/knowledge';
4
  import { CloseCircleOutlined } from '@ant-design/icons';
5
  import { Badge, DescriptionsProps, Flex, Popover, Space, Tag } from 'antd';
@@ -22,6 +23,8 @@ interface IProps {
22
  }
23
 
24
  const PopoverContent = ({ record }: IProps) => {
 
 
25
  const replaceText = (text: string) => {
26
  // Remove duplicate \n
27
  const nextText = text.replace(/(\n)\1+/g, '$1');
@@ -44,17 +47,17 @@ const PopoverContent = ({ record }: IProps) => {
44
  const items: DescriptionsProps['items'] = [
45
  {
46
  key: 'process_begin_at',
47
- label: 'Process Begin At',
48
  children: record.process_begin_at,
49
  },
50
  {
51
  key: 'process_duation',
52
- label: 'Process Duration',
53
  children: record.process_duation,
54
  },
55
  {
56
  key: 'progress_msg',
57
- label: 'Progress Msg',
58
  children: replaceText(record.progress_msg.trim()),
59
  },
60
  ];
 
1
  import { ReactComponent as RefreshIcon } from '@/assets/svg/refresh.svg';
2
  import { ReactComponent as RunIcon } from '@/assets/svg/run.svg';
3
+ import { useTranslate } from '@/hooks/commonHooks';
4
  import { IKnowledgeFile } from '@/interfaces/database/knowledge';
5
  import { CloseCircleOutlined } from '@ant-design/icons';
6
  import { Badge, DescriptionsProps, Flex, Popover, Space, Tag } from 'antd';
 
23
  }
24
 
25
  const PopoverContent = ({ record }: IProps) => {
26
+ const { t } = useTranslate('knowledgeDetails');
27
+
28
  const replaceText = (text: string) => {
29
  // Remove duplicate \n
30
  const nextText = text.replace(/(\n)\1+/g, '$1');
 
47
  const items: DescriptionsProps['items'] = [
48
  {
49
  key: 'process_begin_at',
50
+ label: t('processBeginAt'),
51
  children: record.process_begin_at,
52
  },
53
  {
54
  key: 'process_duation',
55
+ label: t('processDuration'),
56
  children: record.process_duation,
57
  },
58
  {
59
  key: 'progress_msg',
60
+ label: t('progressMsg'),
61
  children: replaceText(record.progress_msg.trim()),
62
  },
63
  ];
web/src/pages/add-knowledge/components/knowledge-file/rename-modal/index.tsx CHANGED
@@ -1,4 +1,5 @@
1
  import { IModalManagerChildrenProps } from '@/components/modal-manager';
 
2
  import { Form, Input, Modal } from 'antd';
3
  import { useEffect } from 'react';
4
 
@@ -17,7 +18,7 @@ const RenameModal = ({
17
  hideModal,
18
  }: IProps) => {
19
  const [form] = Form.useForm();
20
-
21
  type FieldType = {
22
  name?: string;
23
  };
@@ -43,7 +44,7 @@ const RenameModal = ({
43
 
44
  return (
45
  <Modal
46
- title="Rename"
47
  open={visible}
48
  onOk={handleOk}
49
  onCancel={hideModal}
@@ -60,9 +61,9 @@ const RenameModal = ({
60
  form={form}
61
  >
62
  <Form.Item<FieldType>
63
- label="Name"
64
  name="name"
65
- rules={[{ required: true, message: 'Please input name!' }]}
66
  >
67
  <Input />
68
  </Form.Item>
 
1
  import { IModalManagerChildrenProps } from '@/components/modal-manager';
2
+ import { useTranslate } from '@/hooks/commonHooks';
3
  import { Form, Input, Modal } from 'antd';
4
  import { useEffect } from 'react';
5
 
 
18
  hideModal,
19
  }: IProps) => {
20
  const [form] = Form.useForm();
21
+ const { t } = useTranslate('common');
22
  type FieldType = {
23
  name?: string;
24
  };
 
44
 
45
  return (
46
  <Modal
47
+ title={t('rename')}
48
  open={visible}
49
  onOk={handleOk}
50
  onCancel={hideModal}
 
61
  form={form}
62
  >
63
  <Form.Item<FieldType>
64
+ label={t('name')}
65
  name="name"
66
+ rules={[{ required: true, message: t('namePlaceholder') }]}
67
  >
68
  <Input />
69
  </Form.Item>
web/src/pages/add-knowledge/components/knowledge-setting/configuration.tsx CHANGED
@@ -7,40 +7,27 @@ import {
7
  } from './hooks';
8
 
9
  import MaxTokenNumber from '@/components/max-token-number';
 
10
  import { FormInstance } from 'antd/lib';
11
  import styles from './index.less';
12
 
13
  const { Option } = Select;
14
 
15
  const ConfigurationForm = ({ form }: { form: FormInstance }) => {
16
- const { submitKnowledgeConfiguration, submitLoading } =
17
- useSubmitKnowledgeConfiguration();
18
  const { parserList, embeddingModelOptions, disabled } =
19
  useFetchKnowledgeConfigurationOnMount(form);
20
-
21
- const onFinishFailed = (errorInfo: any) => {
22
- console.log('Failed:', errorInfo);
23
- };
24
 
25
  return (
26
- <Form
27
- form={form}
28
- name="validateOnly"
29
- layout="vertical"
30
- autoComplete="off"
31
- onFinish={submitKnowledgeConfiguration}
32
- onFinishFailed={onFinishFailed}
33
- >
34
- <Form.Item
35
- name="name"
36
- label="Knowledge base name"
37
- rules={[{ required: true }]}
38
- >
39
  <Input />
40
  </Form.Item>
41
  <Form.Item
42
  name="avatar"
43
- label="Knowledge base photo"
44
  valuePropName="fileList"
45
  getValueFromEvent={normFile}
46
  >
@@ -52,43 +39,43 @@ const ConfigurationForm = ({ form }: { form: FormInstance }) => {
52
  >
53
  <button style={{ border: 0, background: 'none' }} type="button">
54
  <PlusOutlined />
55
- <div style={{ marginTop: 8 }}>Upload</div>
56
  </button>
57
  </Upload>
58
  </Form.Item>
59
- <Form.Item name="description" label="Description">
60
  <Input />
61
  </Form.Item>
62
  <Form.Item
63
- label="Language"
64
  name="language"
65
  initialValue={'English'}
66
- rules={[{ required: true, message: 'Please input your language!' }]}
67
  >
68
- <Select placeholder="select your language">
69
- <Option value="English">English</Option>
70
- <Option value="Chinese">Chinese</Option>
71
  </Select>
72
  </Form.Item>
73
  <Form.Item
74
  name="permission"
75
  label="Permissions"
76
- tooltip="If the permission is 'Team', all the team member can manipulate the knowledgebase."
77
  rules={[{ required: true }]}
78
  >
79
  <Radio.Group>
80
- <Radio value="me">Only me</Radio>
81
- <Radio value="team">Team</Radio>
82
  </Radio.Group>
83
  </Form.Item>
84
  <Form.Item
85
  name="embd_id"
86
  label="Embedding model"
87
  rules={[{ required: true }]}
88
- tooltip="The embedding model used to embedding chunks. It's unchangable once the knowledgebase has chunks. You need to delete all the chunks if you want to change it."
89
  >
90
  <Select
91
- placeholder="Please select a embedding model"
92
  options={embeddingModelOptions}
93
  disabled={disabled}
94
  ></Select>
@@ -96,10 +83,10 @@ const ConfigurationForm = ({ form }: { form: FormInstance }) => {
96
  <Form.Item
97
  name="parser_id"
98
  label="Chunk method"
99
- tooltip="The instruction is at right."
100
  rules={[{ required: true }]}
101
  >
102
- <Select placeholder="Please select a chunk method" disabled={disabled}>
103
  {parserList.map((x) => (
104
  <Option value={x.value} key={x.value}>
105
  {x.label}
@@ -120,16 +107,16 @@ const ConfigurationForm = ({ form }: { form: FormInstance }) => {
120
  <Form.Item>
121
  <div className={styles.buttonWrapper}>
122
  <Space>
123
- <Button htmlType="reset" size={'middle'}>
124
- Cancel
125
  </Button>
126
  <Button
127
- htmlType="submit"
128
  type="primary"
129
  size={'middle'}
130
  loading={submitLoading}
 
131
  >
132
- Save
133
  </Button>
134
  </Space>
135
  </div>
 
7
  } from './hooks';
8
 
9
  import MaxTokenNumber from '@/components/max-token-number';
10
+ import { useTranslate } from '@/hooks/commonHooks';
11
  import { FormInstance } from 'antd/lib';
12
  import styles from './index.less';
13
 
14
  const { Option } = Select;
15
 
16
  const ConfigurationForm = ({ form }: { form: FormInstance }) => {
17
+ const { submitKnowledgeConfiguration, submitLoading, navigateToDataset } =
18
+ useSubmitKnowledgeConfiguration(form);
19
  const { parserList, embeddingModelOptions, disabled } =
20
  useFetchKnowledgeConfigurationOnMount(form);
21
+ const { t } = useTranslate('knowledgeConfiguration');
 
 
 
22
 
23
  return (
24
+ <Form form={form} name="validateOnly" layout="vertical" autoComplete="off">
25
+ <Form.Item name="name" label={t('name')} rules={[{ required: true }]}>
 
 
 
 
 
 
 
 
 
 
 
26
  <Input />
27
  </Form.Item>
28
  <Form.Item
29
  name="avatar"
30
+ label={t('photo')}
31
  valuePropName="fileList"
32
  getValueFromEvent={normFile}
33
  >
 
39
  >
40
  <button style={{ border: 0, background: 'none' }} type="button">
41
  <PlusOutlined />
42
+ <div style={{ marginTop: 8 }}>{t('upload')}</div>
43
  </button>
44
  </Upload>
45
  </Form.Item>
46
+ <Form.Item name="description" label={t('description')}>
47
  <Input />
48
  </Form.Item>
49
  <Form.Item
50
+ label={t('language')}
51
  name="language"
52
  initialValue={'English'}
53
+ rules={[{ required: true, message: t('languageMessage') }]}
54
  >
55
+ <Select placeholder={t('languagePlaceholder')}>
56
+ <Option value="English">{t('english')}</Option>
57
+ <Option value="Chinese">{t('chinese')}</Option>
58
  </Select>
59
  </Form.Item>
60
  <Form.Item
61
  name="permission"
62
  label="Permissions"
63
+ tooltip={t('permissionsTip')}
64
  rules={[{ required: true }]}
65
  >
66
  <Radio.Group>
67
+ <Radio value="me">{t('me')}</Radio>
68
+ <Radio value="team">{t('team')}</Radio>
69
  </Radio.Group>
70
  </Form.Item>
71
  <Form.Item
72
  name="embd_id"
73
  label="Embedding model"
74
  rules={[{ required: true }]}
75
+ tooltip={t('embeddingModelTip')}
76
  >
77
  <Select
78
+ placeholder={t('embeddingModelPlaceholder')}
79
  options={embeddingModelOptions}
80
  disabled={disabled}
81
  ></Select>
 
83
  <Form.Item
84
  name="parser_id"
85
  label="Chunk method"
86
+ tooltip={t('chunkMethodTip')}
87
  rules={[{ required: true }]}
88
  >
89
+ <Select placeholder={t('chunkMethodPlaceholder')} disabled={disabled}>
90
  {parserList.map((x) => (
91
  <Option value={x.value} key={x.value}>
92
  {x.label}
 
107
  <Form.Item>
108
  <div className={styles.buttonWrapper}>
109
  <Space>
110
+ <Button size={'middle'} onClick={navigateToDataset}>
111
+ {t('cancel')}
112
  </Button>
113
  <Button
 
114
  type="primary"
115
  size={'middle'}
116
  loading={submitLoading}
117
+ onClick={submitKnowledgeConfiguration}
118
  >
119
+ {t('save')}
120
  </Button>
121
  </Space>
122
  </div>
web/src/pages/add-knowledge/components/knowledge-setting/hooks.ts CHANGED
@@ -5,6 +5,7 @@ import {
5
  useUpdateKnowledge,
6
  } from '@/hooks/knowledgeHook';
7
  import { useFetchLlmList, useSelectLlmOptions } from '@/hooks/llmHooks';
 
8
  import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
9
  import {
10
  useFetchTenantInfo,
@@ -20,24 +21,24 @@ import pick from 'lodash/pick';
20
  import { useCallback, useEffect } from 'react';
21
  import { LlmModelType } from '../../constant';
22
 
23
- export const useSubmitKnowledgeConfiguration = () => {
24
  const save = useUpdateKnowledge();
25
  const knowledgeBaseId = useKnowledgeBaseId();
26
  const submitLoading = useOneNamespaceEffectsLoading('kSModel', ['updateKb']);
 
27
 
28
- const submitKnowledgeConfiguration = useCallback(
29
- async (values: any) => {
30
- const avatar = await getBase64FromUploadFileList(values.avatar);
31
- save({
32
- ...values,
33
- avatar,
34
- kb_id: knowledgeBaseId,
35
- });
36
- },
37
- [save, knowledgeBaseId],
38
- );
39
 
40
- return { submitKnowledgeConfiguration, submitLoading };
41
  };
42
 
43
  export const useFetchKnowledgeConfigurationOnMount = (form: FormInstance) => {
 
5
  useUpdateKnowledge,
6
  } from '@/hooks/knowledgeHook';
7
  import { useFetchLlmList, useSelectLlmOptions } from '@/hooks/llmHooks';
8
+ import { useNavigateToDataset } from '@/hooks/routeHook';
9
  import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
10
  import {
11
  useFetchTenantInfo,
 
21
  import { useCallback, useEffect } from 'react';
22
  import { LlmModelType } from '../../constant';
23
 
24
+ export const useSubmitKnowledgeConfiguration = (form: FormInstance) => {
25
  const save = useUpdateKnowledge();
26
  const knowledgeBaseId = useKnowledgeBaseId();
27
  const submitLoading = useOneNamespaceEffectsLoading('kSModel', ['updateKb']);
28
+ const navigateToDataset = useNavigateToDataset();
29
 
30
+ const submitKnowledgeConfiguration = useCallback(async () => {
31
+ const values = await form.validateFields();
32
+ const avatar = await getBase64FromUploadFileList(values.avatar);
33
+ save({
34
+ ...values,
35
+ avatar,
36
+ kb_id: knowledgeBaseId,
37
+ });
38
+ navigateToDataset();
39
+ }, [save, knowledgeBaseId, form, navigateToDataset]);
 
40
 
41
+ return { submitKnowledgeConfiguration, submitLoading, navigateToDataset };
42
  };
43
 
44
  export const useFetchKnowledgeConfigurationOnMount = (form: FormInstance) => {
web/src/pages/add-knowledge/components/knowledge-setting/index.tsx CHANGED
@@ -6,6 +6,7 @@ import {
6
  useSelectKnowledgeDetailsLoading,
7
  } from './hooks';
8
 
 
9
  import styles from './index.less';
10
 
11
  const { Title } = Typography;
@@ -13,11 +14,14 @@ const { Title } = Typography;
13
  const Configuration = () => {
14
  const loading = useSelectKnowledgeDetailsLoading();
15
  const { form, chunkMethod } = useHandleChunkMethodChange();
 
16
 
17
  return (
18
  <div className={styles.configurationWrapper}>
19
- <Title level={5}>Configuration</Title>
20
- <p>Update your knowledge base details especially parsing method here.</p>
 
 
21
  <Divider></Divider>
22
  <Spin spinning={loading}>
23
  <Row gutter={32}>
 
6
  useSelectKnowledgeDetailsLoading,
7
  } from './hooks';
8
 
9
+ import { useTranslate } from '@/hooks/commonHooks';
10
  import styles from './index.less';
11
 
12
  const { Title } = Typography;
 
14
  const Configuration = () => {
15
  const loading = useSelectKnowledgeDetailsLoading();
16
  const { form, chunkMethod } = useHandleChunkMethodChange();
17
+ const { t } = useTranslate('knowledgeConfiguration');
18
 
19
  return (
20
  <div className={styles.configurationWrapper}>
21
+ <Title level={5}>
22
+ {t('configuration', { keyPrefix: 'knowledgeDetails' })}
23
+ </Title>
24
+ <p>{t('titleDescription')}</p>
25
  <Divider></Divider>
26
  <Spin spinning={loading}>
27
  <Row gutter={32}>
web/src/pages/add-knowledge/components/knowledge-sidebar/index.tsx CHANGED
@@ -8,8 +8,9 @@ import { getWidth } from '@/utils';
8
  import { Avatar, Menu, MenuProps, Space } from 'antd';
9
  import classNames from 'classnames';
10
  import { useCallback, useEffect, useMemo, useState } from 'react';
 
11
  import { useNavigate, useSelector } from 'umi';
12
- import { KnowledgeRouteKey, routeMap } from '../../constant';
13
  import styles from './index.less';
14
 
15
  const KnowledgeSidebar = () => {
@@ -23,6 +24,7 @@ const KnowledgeSidebar = () => {
23
 
24
  const [windowWidth, setWindowWidth] = useState(getWidth());
25
  const [collapsed, setCollapsed] = useState(false);
 
26
 
27
  const handleSelect: MenuProps['onSelect'] = (e) => {
28
  navigate(`/knowledge/${e.key}?id=${id}`);
@@ -32,7 +34,7 @@ const KnowledgeSidebar = () => {
32
 
33
  const getItem = useCallback(
34
  (
35
- label: React.ReactNode,
36
  key: React.Key,
37
  icon?: React.ReactNode,
38
  disabled?: boolean,
@@ -43,28 +45,28 @@ const KnowledgeSidebar = () => {
43
  key,
44
  icon,
45
  children,
46
- label,
47
  type,
48
  disabled,
49
  } as MenuItem;
50
  },
51
- [],
52
  );
53
 
54
  const items: MenuItem[] = useMemo(() => {
55
  return [
56
  getItem(
57
- routeMap[KnowledgeRouteKey.Dataset], // TODO: Change icon color when selected
58
  KnowledgeRouteKey.Dataset,
59
  <DatasetIcon />,
60
  ),
61
  getItem(
62
- routeMap[KnowledgeRouteKey.Testing],
63
  KnowledgeRouteKey.Testing,
64
  <TestingIcon />,
65
  ),
66
  getItem(
67
- routeMap[KnowledgeRouteKey.Configuration],
68
  KnowledgeRouteKey.Configuration,
69
  <ConfigurationIcon />,
70
  ),
 
8
  import { Avatar, Menu, MenuProps, Space } from 'antd';
9
  import classNames from 'classnames';
10
  import { useCallback, useEffect, useMemo, useState } from 'react';
11
+ import { useTranslation } from 'react-i18next';
12
  import { useNavigate, useSelector } from 'umi';
13
+ import { KnowledgeRouteKey } from '../../constant';
14
  import styles from './index.less';
15
 
16
  const KnowledgeSidebar = () => {
 
24
 
25
  const [windowWidth, setWindowWidth] = useState(getWidth());
26
  const [collapsed, setCollapsed] = useState(false);
27
+ const { t } = useTranslation();
28
 
29
  const handleSelect: MenuProps['onSelect'] = (e) => {
30
  navigate(`/knowledge/${e.key}?id=${id}`);
 
34
 
35
  const getItem = useCallback(
36
  (
37
+ label: string,
38
  key: React.Key,
39
  icon?: React.ReactNode,
40
  disabled?: boolean,
 
45
  key,
46
  icon,
47
  children,
48
+ label: t(`knowledgeDetails.${label}`),
49
  type,
50
  disabled,
51
  } as MenuItem;
52
  },
53
+ [t],
54
  );
55
 
56
  const items: MenuItem[] = useMemo(() => {
57
  return [
58
  getItem(
59
+ KnowledgeRouteKey.Dataset, // TODO: Change icon color when selected
60
  KnowledgeRouteKey.Dataset,
61
  <DatasetIcon />,
62
  ),
63
  getItem(
64
+ KnowledgeRouteKey.Testing,
65
  KnowledgeRouteKey.Testing,
66
  <TestingIcon />,
67
  ),
68
  getItem(
69
+ KnowledgeRouteKey.Configuration,
70
  KnowledgeRouteKey.Configuration,
71
  <ConfigurationIcon />,
72
  ),
web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx CHANGED
@@ -1,7 +1,8 @@
1
  import SimilaritySlider from '@/components/similarity-slider';
2
- import { Button, Card, Divider, Flex, Form, Input, Slider, Tag } from 'antd';
3
  import { FormInstance } from 'antd/lib';
4
 
 
5
  import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
6
  import styles from './index.less';
7
 
@@ -22,6 +23,7 @@ const TestingControl = ({ form, handleTesting }: IProps) => {
22
  const loading = useOneNamespaceEffectsLoading('testingModel', [
23
  'testDocumentChunk',
24
  ]);
 
25
 
26
  const buttonDisabled =
27
  !question || (typeof question === 'string' && question.trim() === '');
@@ -29,9 +31,9 @@ const TestingControl = ({ form, handleTesting }: IProps) => {
29
  return (
30
  <section className={styles.testingControlWrapper}>
31
  <div>
32
- <b>Retrieval testing</b>
33
  </div>
34
- <p>Final step! After success, leave the rest to Infiniflow AI.</p>
35
  <Divider></Divider>
36
  <section>
37
  <Form
@@ -46,22 +48,18 @@ const TestingControl = ({ form, handleTesting }: IProps) => {
46
  <Form.Item<FieldType>
47
  label="Top K"
48
  name={'top_k'}
49
- tooltip="For the computaion cost, not all the retrieved chunk will be computed vector cosine similarity with query.
50
- The bigger the 'Top K' is, the higher the recall rate is, the slower the retrieval speed is."
51
  >
52
  <Slider marks={{ 0: 0, 2048: 2048 }} max={2048} />
53
  </Form.Item>
54
- <Card size="small" title="Test text">
55
  <Form.Item<FieldType>
56
  name={'question'}
57
- rules={[
58
- { required: true, message: 'Please input your question!' },
59
- ]}
60
  >
61
  <Input.TextArea autoSize={{ minRows: 8 }}></Input.TextArea>
62
  </Form.Item>
63
- <Flex justify={'space-between'}>
64
- <Tag>10/200</Tag>
65
  <Button
66
  type="primary"
67
  size="small"
@@ -69,7 +67,7 @@ const TestingControl = ({ form, handleTesting }: IProps) => {
69
  disabled={buttonDisabled}
70
  loading={loading}
71
  >
72
- Testing
73
  </Button>
74
  </Flex>
75
  </Card>
 
1
  import SimilaritySlider from '@/components/similarity-slider';
2
+ import { Button, Card, Divider, Flex, Form, Input, Slider } from 'antd';
3
  import { FormInstance } from 'antd/lib';
4
 
5
+ import { useTranslate } from '@/hooks/commonHooks';
6
  import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
7
  import styles from './index.less';
8
 
 
23
  const loading = useOneNamespaceEffectsLoading('testingModel', [
24
  'testDocumentChunk',
25
  ]);
26
+ const { t } = useTranslate('knowledgeDetails');
27
 
28
  const buttonDisabled =
29
  !question || (typeof question === 'string' && question.trim() === '');
 
31
  return (
32
  <section className={styles.testingControlWrapper}>
33
  <div>
34
+ <b>{t('testing')}</b>
35
  </div>
36
+ <p>{t('testingDescription')}</p>
37
  <Divider></Divider>
38
  <section>
39
  <Form
 
48
  <Form.Item<FieldType>
49
  label="Top K"
50
  name={'top_k'}
51
+ tooltip={t('topKTip')}
 
52
  >
53
  <Slider marks={{ 0: 0, 2048: 2048 }} max={2048} />
54
  </Form.Item>
55
+ <Card size="small" title={t('testText')}>
56
  <Form.Item<FieldType>
57
  name={'question'}
58
+ rules={[{ required: true, message: t('testTextPlaceholder') }]}
 
 
59
  >
60
  <Input.TextArea autoSize={{ minRows: 8 }}></Input.TextArea>
61
  </Form.Item>
62
+ <Flex justify={'end'}>
 
63
  <Button
64
  type="primary"
65
  size="small"
 
67
  disabled={buttonDisabled}
68
  loading={loading}
69
  >
70
+ {t('testingLabel')}
71
  </Button>
72
  </Flex>
73
  </Card>
web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx CHANGED
@@ -1,5 +1,6 @@
1
  import { ReactComponent as SelectedFilesCollapseIcon } from '@/assets/svg/selected-files-collapse.svg';
2
  import Image from '@/components/image';
 
3
  import { ITestingChunk } from '@/interfaces/database/knowledge';
4
  import {
5
  Card,
@@ -10,11 +11,13 @@ import {
10
  Popover,
11
  Space,
12
  } from 'antd';
 
13
  import { useDispatch, useSelector } from 'umi';
14
  import { TestingModelState } from '../model';
15
- import styles from './index.less';
16
  import SelectFiles from './select-files';
17
 
 
 
18
  const similarityList: Array<{ field: keyof ITestingChunk; label: string }> = [
19
  { field: 'similarity', label: 'Hybrid Similarity' },
20
  { field: 'term_similarity', label: 'Term Similarity' },
@@ -22,6 +25,7 @@ const similarityList: Array<{ field: keyof ITestingChunk; label: string }> = [
22
  ];
23
 
24
  const ChunkTitle = ({ item }: { item: ITestingChunk }) => {
 
25
  return (
26
  <Flex gap={10}>
27
  {similarityList.map((x) => (
@@ -29,7 +33,7 @@ const ChunkTitle = ({ item }: { item: ITestingChunk }) => {
29
  <span className={styles.similarityCircle}>
30
  {((item[x.field] as number) * 100).toFixed(2)}
31
  </span>
32
- <span className={styles.similarityText}>{x.label}</span>
33
  </Space>
34
  ))}
35
  </Flex>
@@ -49,6 +53,7 @@ const TestingResult = ({ handleTesting }: IProps) => {
49
  selectedDocumentIds,
50
  }: TestingModelState = useSelector((state: any) => state.testingModel);
51
  const dispatch = useDispatch();
 
52
 
53
  const onChange: PaginationProps['onChange'] = (pageNumber, pageSize) => {
54
  console.log('Page: ', pageNumber, pageSize);
@@ -75,13 +80,15 @@ const TestingResult = ({ handleTesting }: IProps) => {
75
  align="center"
76
  className={styles.selectFilesTitle}
77
  >
78
- <span>
79
- {selectedDocumentIds?.length ?? 0}/{documents.length} Files
80
- Selected
81
- </span>
 
 
82
  <Space size={52}>
83
- <b>Hits</b>
84
- <b>View</b>
85
  </Space>
86
  </Flex>
87
  ),
 
1
  import { ReactComponent as SelectedFilesCollapseIcon } from '@/assets/svg/selected-files-collapse.svg';
2
  import Image from '@/components/image';
3
+ import { useTranslate } from '@/hooks/commonHooks';
4
  import { ITestingChunk } from '@/interfaces/database/knowledge';
5
  import {
6
  Card,
 
11
  Popover,
12
  Space,
13
  } from 'antd';
14
+ import camelCase from 'lodash/camelCase';
15
  import { useDispatch, useSelector } from 'umi';
16
  import { TestingModelState } from '../model';
 
17
  import SelectFiles from './select-files';
18
 
19
+ import styles from './index.less';
20
+
21
  const similarityList: Array<{ field: keyof ITestingChunk; label: string }> = [
22
  { field: 'similarity', label: 'Hybrid Similarity' },
23
  { field: 'term_similarity', label: 'Term Similarity' },
 
25
  ];
26
 
27
  const ChunkTitle = ({ item }: { item: ITestingChunk }) => {
28
+ const { t } = useTranslate('knowledgeDetails');
29
  return (
30
  <Flex gap={10}>
31
  {similarityList.map((x) => (
 
33
  <span className={styles.similarityCircle}>
34
  {((item[x.field] as number) * 100).toFixed(2)}
35
  </span>
36
+ <span className={styles.similarityText}>{t(camelCase(x.field))}</span>
37
  </Space>
38
  ))}
39
  </Flex>
 
53
  selectedDocumentIds,
54
  }: TestingModelState = useSelector((state: any) => state.testingModel);
55
  const dispatch = useDispatch();
56
+ const { t } = useTranslate('knowledgeDetails');
57
 
58
  const onChange: PaginationProps['onChange'] = (pageNumber, pageSize) => {
59
  console.log('Page: ', pageNumber, pageSize);
 
80
  align="center"
81
  className={styles.selectFilesTitle}
82
  >
83
+ <Space>
84
+ <span>
85
+ {selectedDocumentIds?.length ?? 0}/{documents.length}
86
+ </span>
87
+ {t('filesSelected')}
88
+ </Space>
89
  <Space size={52}>
90
+ <b>{t('hits')}</b>
91
+ <b>{t('view')}</b>
92
  </Space>
93
  </Flex>
94
  ),
web/src/pages/add-knowledge/index.tsx CHANGED
@@ -7,6 +7,7 @@ import {
7
  import { Breadcrumb } from 'antd';
8
  import { ItemType } from 'antd/es/breadcrumb/Breadcrumb';
9
  import { useEffect, useMemo } from 'react';
 
10
  import { Link, Outlet, useDispatch, useLocation } from 'umi';
11
  import Siderbar from './components/knowledge-sidebar';
12
  import {
@@ -21,6 +22,7 @@ const KnowledgeAdding = () => {
21
  const dispatch = useDispatch();
22
  const knowledgeBaseId = useKnowledgeBaseId();
23
 
 
24
  const location = useLocation();
25
  const activeKey: KnowledgeRouteKey =
26
  (useSecondPathName() as KnowledgeRouteKey) || KnowledgeRouteKey.Dataset;
@@ -33,14 +35,18 @@ const KnowledgeAdding = () => {
33
  const breadcrumbItems: ItemType[] = useMemo(() => {
34
  const items: ItemType[] = [
35
  {
36
- title: <a onClick={() => gotoList('/knowledge')}>Knowledge Base</a>,
 
 
 
 
37
  },
38
  {
39
  title: datasetActiveKey ? (
40
  <Link
41
  to={`/knowledge/${KnowledgeRouteKey.Dataset}?id=${knowledgeBaseId}`}
42
  >
43
- {routeMap[activeKey]}
44
  </Link>
45
  ) : (
46
  routeMap[activeKey]
@@ -55,7 +61,7 @@ const KnowledgeAdding = () => {
55
  }
56
 
57
  return items;
58
- }, [activeKey, datasetActiveKey, gotoList, knowledgeBaseId]);
59
 
60
  useEffect(() => {
61
  const search: string = location.search.slice(1);
 
7
  import { Breadcrumb } from 'antd';
8
  import { ItemType } from 'antd/es/breadcrumb/Breadcrumb';
9
  import { useEffect, useMemo } from 'react';
10
+ import { useTranslation } from 'react-i18next';
11
  import { Link, Outlet, useDispatch, useLocation } from 'umi';
12
  import Siderbar from './components/knowledge-sidebar';
13
  import {
 
22
  const dispatch = useDispatch();
23
  const knowledgeBaseId = useKnowledgeBaseId();
24
 
25
+ const { t } = useTranslation();
26
  const location = useLocation();
27
  const activeKey: KnowledgeRouteKey =
28
  (useSecondPathName() as KnowledgeRouteKey) || KnowledgeRouteKey.Dataset;
 
35
  const breadcrumbItems: ItemType[] = useMemo(() => {
36
  const items: ItemType[] = [
37
  {
38
+ title: (
39
+ <a onClick={() => gotoList('/knowledge')}>
40
+ {t('header.knowledgeBase')}
41
+ </a>
42
+ ),
43
  },
44
  {
45
  title: datasetActiveKey ? (
46
  <Link
47
  to={`/knowledge/${KnowledgeRouteKey.Dataset}?id=${knowledgeBaseId}`}
48
  >
49
+ {t(`knowledgeDetails.${activeKey}`)}
50
  </Link>
51
  ) : (
52
  routeMap[activeKey]
 
61
  }
62
 
63
  return items;
64
+ }, [activeKey, datasetActiveKey, gotoList, knowledgeBaseId, t]);
65
 
66
  useEffect(() => {
67
  const search: string = location.search.slice(1);
web/src/pages/knowledge/knowledge-card/index.tsx CHANGED
@@ -10,6 +10,7 @@ import {
10
  UserOutlined,
11
  } from '@ant-design/icons';
12
  import { Avatar, Card, Dropdown, MenuProps, Space } from 'antd';
 
13
  import { useDispatch, useNavigate } from 'umi';
14
 
15
  import styles from './index.less';
@@ -22,6 +23,7 @@ const KnowledgeCard = ({ item }: IProps) => {
22
  const navigate = useNavigate();
23
  const dispatch = useDispatch();
24
  const showDeleteConfirm = useShowDeleteConfirm();
 
25
 
26
  const removeKnowledge = () => {
27
  return dispatch({
@@ -41,7 +43,7 @@ const KnowledgeCard = ({ item }: IProps) => {
41
  key: '1',
42
  label: (
43
  <Space>
44
- Delete
45
  <DeleteOutlined />
46
  </Space>
47
  ),
@@ -87,7 +89,10 @@ const KnowledgeCard = ({ item }: IProps) => {
87
  <div className={styles.bottomLeft}>
88
  <FileTextOutlined className={styles.leftIcon} />
89
  <span className={styles.rightText}>
90
- <Space>{item.doc_num}Docs</Space>
 
 
 
91
  </span>
92
  </div>
93
  </div>
 
10
  UserOutlined,
11
  } from '@ant-design/icons';
12
  import { Avatar, Card, Dropdown, MenuProps, Space } from 'antd';
13
+ import { useTranslation } from 'react-i18next';
14
  import { useDispatch, useNavigate } from 'umi';
15
 
16
  import styles from './index.less';
 
23
  const navigate = useNavigate();
24
  const dispatch = useDispatch();
25
  const showDeleteConfirm = useShowDeleteConfirm();
26
+ const { t } = useTranslation();
27
 
28
  const removeKnowledge = () => {
29
  return dispatch({
 
43
  key: '1',
44
  label: (
45
  <Space>
46
+ {t('common.delete')}
47
  <DeleteOutlined />
48
  </Space>
49
  ),
 
89
  <div className={styles.bottomLeft}>
90
  <FileTextOutlined className={styles.leftIcon} />
91
  <span className={styles.rightText}>
92
+ <Space>
93
+ {item.doc_num}
94
+ {t('knowledgeList.doc')}
95
+ </Space>
96
  </span>
97
  </div>
98
  </div>