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