diff --git a/web/src/components/page-rank-form-field.tsx b/web/src/components/page-rank-form-field.tsx
new file mode 100644
index 000000000..4ce23d6fc
--- /dev/null
+++ b/web/src/components/page-rank-form-field.tsx
@@ -0,0 +1,19 @@
+import { useTranslate } from '@/hooks/common-hooks';
+import { SliderInputFormField } from './slider-input-form-field';
+
+export function PageRankFormField() {
+ const { t } = useTranslate('knowledgeConfiguration');
+
+ return (
+
+ );
+}
+
+export default PageRankFormField;
diff --git a/web/src/components/parse-configuration/graph-rag-form-fields.tsx b/web/src/components/parse-configuration/graph-rag-form-fields.tsx
index c92ca5697..30f8f390b 100644
--- a/web/src/components/parse-configuration/graph-rag-form-fields.tsx
+++ b/web/src/components/parse-configuration/graph-rag-form-fields.tsx
@@ -1,12 +1,11 @@
import { DocumentParserType } from '@/constants/knowledge';
import { useTranslate } from '@/hooks/common-hooks';
import { cn } from '@/lib/utils';
-import { Switch as AntSwitch, Form, Select } from 'antd';
import { upperFirst } from 'lodash';
import { useCallback, useMemo } from 'react';
-import { useFormContext } from 'react-hook-form';
-import { DatasetConfigurationContainer } from '../dataset-configuration-container';
-import EntityTypesItem from '../entity-types-item';
+import { useFormContext, useWatch } from 'react-hook-form';
+import { EntityTypesFormField } from '../entity-types-form-field';
+import { FormContainer } from '../form-container';
import {
FormControl,
FormField,
@@ -14,6 +13,7 @@ import {
FormLabel,
FormMessage,
} from '../ui/form';
+import { RAGFlowSelect } from '../ui/select';
import { Switch } from '../ui/switch';
const excludedTagParseMethods = [
@@ -48,22 +48,6 @@ type GraphRagItemsProps = {
marginBottom?: boolean;
};
-export function UseGraphRagItem() {
- const { t } = useTranslate('knowledgeConfiguration');
-
- return (
-
-
-
- );
-}
-
export function UseGraphRagFormField() {
const form = useFormContext();
const { t } = useTranslate('knowledgeConfiguration');
@@ -93,6 +77,12 @@ export function UseGraphRagFormField() {
// The three types "table", "resume" and "one" do not display this configuration.
const GraphRagItems = ({ marginBottom = false }: GraphRagItemsProps) => {
const { t } = useTranslate('knowledgeConfiguration');
+ const form = useFormContext();
+
+ const useRaptor = useWatch({
+ control: form.control,
+ name: 'parser_config.graphrag.use_graphrag',
+ });
const methodOptions = useMemo(() => {
return [MethodValue.Light, MethodValue.General].map((x) => ({
@@ -103,39 +93,23 @@ const GraphRagItems = ({ marginBottom = false }: GraphRagItemsProps) => {
const renderWideTooltip = useCallback(
(title: React.ReactNode | string) => {
- return {
- title: typeof title === 'string' ? t(title) : title,
- overlayInnerStyle: { width: '32vw' },
- };
+ return typeof title === 'string' ? t(title) : title;
},
[t],
);
return (
-
-
-
- prevValues.parser_config.graphrag.use_graphrag !==
- curValues.parser_config.graphrag.use_graphrag
- }
- >
- {({ getFieldValue }) => {
- const useRaptor = getFieldValue([
- 'parser_config',
- 'graphrag',
- 'use_graphrag',
- ]);
-
- return (
- useRaptor && (
- <>
-
-
+
+ {useRaptor && (
+ <>
+
+ (
+
+ {
}}
>,
)}
- initialValue={MethodValue.Light}
>
-
-
-
-
-
-
-
-
- >
- )
- );
- }}
-
-
+ {t('graphRagMethod')}
+
+
+
+
+
+
+ )}
+ />
+
+ (
+
+
+ {t('resolution')}
+
+
+
+
+
+
+ )}
+ />
+
+ (
+
+
+ {t('community')}
+
+
+
+
+
+
+ )}
+ />
+ >
+ )}
+
);
};
diff --git a/web/src/pages/dataset/setting/category-panel.tsx b/web/src/pages/dataset/setting/category-panel.tsx
new file mode 100644
index 000000000..4e96fefcc
--- /dev/null
+++ b/web/src/pages/dataset/setting/category-panel.tsx
@@ -0,0 +1,77 @@
+import SvgIcon from '@/components/svg-icon';
+import { useTranslate } from '@/hooks/common-hooks';
+import { useSelectParserList } from '@/hooks/user-setting-hooks';
+import { Col, Divider, Empty, Row, Typography } from 'antd';
+import DOMPurify from 'dompurify';
+import camelCase from 'lodash/camelCase';
+import { useMemo } from 'react';
+import styles from './index.less';
+import { TagTabs } from './tag-tabs';
+import { ImageMap } from './utils';
+
+const { Text } = Typography;
+
+const CategoryPanel = ({ chunkMethod }: { chunkMethod: string }) => {
+ const parserList = useSelectParserList();
+ const { t } = useTranslate('knowledgeConfiguration');
+
+ const item = useMemo(() => {
+ const item = parserList.find((x) => x.value === chunkMethod);
+ if (item) {
+ return {
+ title: item.label,
+ description: t(camelCase(item.value)),
+ };
+ }
+ return { title: '', description: '' };
+ }, [parserList, chunkMethod, t]);
+
+ const imageList = useMemo(() => {
+ if (chunkMethod in ImageMap) {
+ return ImageMap[chunkMethod as keyof typeof ImageMap];
+ }
+ return [];
+ }, [chunkMethod]);
+
+ return (
+
+ {imageList.length > 0 ? (
+ <>
+
+ {`"${item.title}" ${t('methodTitle')}`}
+
+
+ {`"${item.title}" ${t('methodExamples')}`}
+ {t('methodExamplesDescription')}
+
+ {imageList.map((x) => (
+
+
+
+ ))}
+
+
+ {item.title} {t('dialogueExamplesTitle')}
+
+
+ >
+ ) : (
+
+ {t('methodEmpty')}
+
+
+ )}
+ {chunkMethod === 'tag' && }
+
+ );
+};
+
+export default CategoryPanel;
diff --git a/web/src/pages/dataset/setting/chunk-method-form.tsx b/web/src/pages/dataset/setting/chunk-method-form.tsx
new file mode 100644
index 000000000..6ff706d98
--- /dev/null
+++ b/web/src/pages/dataset/setting/chunk-method-form.tsx
@@ -0,0 +1,78 @@
+import { useFormContext, useWatch } from 'react-hook-form';
+import { useTranslation } from 'react-i18next';
+
+import { DocumentParserType } from '@/constants/knowledge';
+import { useMemo, useState } from 'react';
+import { AudioConfiguration } from './configuration/audio';
+import { BookConfiguration } from './configuration/book';
+import { EmailConfiguration } from './configuration/email';
+import { KnowledgeGraphConfiguration } from './configuration/knowledge-graph';
+import { LawsConfiguration } from './configuration/laws';
+import { ManualConfiguration } from './configuration/manual';
+import { NaiveConfiguration } from './configuration/naive';
+import { OneConfiguration } from './configuration/one';
+import { PaperConfiguration } from './configuration/paper';
+import { PictureConfiguration } from './configuration/picture';
+import { PresentationConfiguration } from './configuration/presentation';
+import { QAConfiguration } from './configuration/qa';
+import { ResumeConfiguration } from './configuration/resume';
+import { TableConfiguration } from './configuration/table';
+import { TagConfiguration } from './configuration/tag';
+import { useFetchKnowledgeConfigurationOnMount } from './hooks';
+
+const ConfigurationComponentMap = {
+ [DocumentParserType.Naive]: NaiveConfiguration,
+ [DocumentParserType.Qa]: QAConfiguration,
+ [DocumentParserType.Resume]: ResumeConfiguration,
+ [DocumentParserType.Manual]: ManualConfiguration,
+ [DocumentParserType.Table]: TableConfiguration,
+ [DocumentParserType.Paper]: PaperConfiguration,
+ [DocumentParserType.Book]: BookConfiguration,
+ [DocumentParserType.Laws]: LawsConfiguration,
+ [DocumentParserType.Presentation]: PresentationConfiguration,
+ [DocumentParserType.Picture]: PictureConfiguration,
+ [DocumentParserType.One]: OneConfiguration,
+ [DocumentParserType.Audio]: AudioConfiguration,
+ [DocumentParserType.Email]: EmailConfiguration,
+ [DocumentParserType.Tag]: TagConfiguration,
+ [DocumentParserType.KnowledgeGraph]: KnowledgeGraphConfiguration,
+};
+
+function EmptyComponent() {
+ return ;
+}
+
+export function ChunkMethodForm() {
+ const form = useFormContext();
+ const { t } = useTranslation();
+ const [finalParserId, setFinalParserId] = useState(
+ DocumentParserType.Naive,
+ );
+
+ const knowledgeDetails = useFetchKnowledgeConfigurationOnMount(form);
+
+ const parserId: DocumentParserType = useWatch({
+ control: form.control,
+ name: 'parser_id',
+ });
+
+ const ConfigurationComponent = useMemo(() => {
+ return finalParserId
+ ? ConfigurationComponentMap[finalParserId]
+ : EmptyComponent;
+ }, [finalParserId]);
+
+ // useEffect(() => {
+ // setFinalParserId(parserId);
+ // }, [parserId]);
+
+ // useEffect(() => {
+ // setFinalParserId(knowledgeDetails.parser_id as DocumentParserType);
+ // }, [knowledgeDetails.parser_id]);
+
+ return (
+
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/audio.tsx b/web/src/pages/dataset/setting/configuration/audio.tsx
new file mode 100644
index 000000000..f1a810c2f
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/audio.tsx
@@ -0,0 +1,31 @@
+import {
+ AutoKeywordsFormField,
+ AutoQuestionsFormField,
+} from '@/components/auto-keywords-form-field';
+import PageRankFormField from '@/components/page-rank-form-field';
+import GraphRagItems from '@/components/parse-configuration/graph-rag-form-fields';
+import RaptorFormFields from '@/components/parse-configuration/raptor-form-fields';
+import { TagItems } from '../tag-item';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function AudioConfiguration() {
+ return (
+ <>
+
+
+
+
+
+ <>
+
+
+ >
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/book.tsx b/web/src/pages/dataset/setting/configuration/book.tsx
new file mode 100644
index 000000000..28261e2d9
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/book.tsx
@@ -0,0 +1,33 @@
+import {
+ AutoKeywordsFormField,
+ AutoQuestionsFormField,
+} from '@/components/auto-keywords-form-field';
+import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
+import PageRankFormField from '@/components/page-rank-form-field';
+import GraphRagItems from '@/components/parse-configuration/graph-rag-form-fields';
+import RaptorFormFields from '@/components/parse-configuration/raptor-form-fields';
+import { TagItems } from '../tag-item';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function BookConfiguration() {
+ return (
+ <>
+
+
+
+
+
+
+ <>
+
+
+ >
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/common-item.tsx b/web/src/pages/dataset/setting/configuration/common-item.tsx
new file mode 100644
index 000000000..1f63b0440
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/common-item.tsx
@@ -0,0 +1,75 @@
+import {
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from '@/components/ui/form';
+import { RAGFlowSelect } from '@/components/ui/select';
+import { useTranslate } from '@/hooks/common-hooks';
+import { useFormContext } from 'react-hook-form';
+import {
+ useHasParsedDocument,
+ useSelectChunkMethodList,
+ useSelectEmbeddingModelOptions,
+} from '../hooks';
+
+export function ChunkMethodItem() {
+ const { t } = useTranslate('knowledgeConfiguration');
+ const form = useFormContext();
+ // const handleChunkMethodSelectChange = useHandleChunkMethodSelectChange(form);
+ const parserList = useSelectChunkMethodList();
+
+ return (
+ (
+
+
+ {t('chunkMethod')}
+
+
+
+
+
+
+ )}
+ />
+ );
+}
+
+export function EmbeddingModelItem() {
+ const { t } = useTranslate('knowledgeConfiguration');
+ const form = useFormContext();
+ const embeddingModelOptions = useSelectEmbeddingModelOptions();
+ const disabled = useHasParsedDocument();
+
+ return (
+ (
+
+
+ {t('embeddingModel')}
+
+
+
+
+
+
+ )}
+ />
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/email.tsx b/web/src/pages/dataset/setting/configuration/email.tsx
new file mode 100644
index 000000000..4d4e730e0
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/email.tsx
@@ -0,0 +1,31 @@
+import {
+ AutoKeywordsFormField,
+ AutoQuestionsFormField,
+} from '@/components/auto-keywords-form-field';
+import PageRankFormField from '@/components/page-rank-form-field';
+import GraphRagItems from '@/components/parse-configuration/graph-rag-form-fields';
+import RaptorFormFields from '@/components/parse-configuration/raptor-form-fields';
+import { TagItems } from '../tag-item';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function EmailConfiguration() {
+ return (
+ <>
+
+
+
+
+
+ <>
+
+
+ >
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/knowledge-graph.tsx b/web/src/pages/dataset/setting/configuration/knowledge-graph.tsx
new file mode 100644
index 000000000..8e82b9490
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/knowledge-graph.tsx
@@ -0,0 +1,22 @@
+import { DelimiterFormField } from '@/components/delimiter-form-field';
+import { EntityTypesFormField } from '@/components/entity-types-form-field';
+import { MaxTokenNumberFormField } from '@/components/max-token-number-from-field';
+import PageRankFormField from '@/components/page-rank-form-field';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function KnowledgeGraphConfiguration() {
+ return (
+ <>
+
+
+
+
+
+ <>
+
+
+
+ >
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/laws.tsx b/web/src/pages/dataset/setting/configuration/laws.tsx
new file mode 100644
index 000000000..e6201c3b7
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/laws.tsx
@@ -0,0 +1,33 @@
+import {
+ AutoKeywordsFormField,
+ AutoQuestionsFormField,
+} from '@/components/auto-keywords-form-field';
+import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
+import PageRankFormField from '@/components/page-rank-form-field';
+import GraphRagItems from '@/components/parse-configuration/graph-rag-form-fields';
+import RaptorFormFields from '@/components/parse-configuration/raptor-form-fields';
+import { TagItems } from '../tag-item';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function LawsConfiguration() {
+ return (
+ <>
+
+
+
+
+
+
+ <>
+
+
+ >
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/manual.tsx b/web/src/pages/dataset/setting/configuration/manual.tsx
new file mode 100644
index 000000000..f82756e27
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/manual.tsx
@@ -0,0 +1,33 @@
+import {
+ AutoKeywordsFormField,
+ AutoQuestionsFormField,
+} from '@/components/auto-keywords-form-field';
+import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
+import PageRankFormField from '@/components/page-rank-form-field';
+import GraphRagItems from '@/components/parse-configuration/graph-rag-form-fields';
+import RaptorFormFields from '@/components/parse-configuration/raptor-form-fields';
+import { TagItems } from '../tag-item';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function ManualConfiguration() {
+ return (
+ <>
+
+
+
+
+
+
+ <>
+
+
+ >
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/naive.tsx b/web/src/pages/dataset/setting/configuration/naive.tsx
new file mode 100644
index 000000000..2423642c6
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/naive.tsx
@@ -0,0 +1,39 @@
+import {
+ AutoKeywordsFormField,
+ AutoQuestionsFormField,
+} from '@/components/auto-keywords-form-field';
+import { DelimiterFormField } from '@/components/delimiter-form-field';
+import { ExcelToHtmlFormField } from '@/components/excel-to-html-form-field';
+import { FormContainer } from '@/components/form-container';
+import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
+import { MaxTokenNumberFormField } from '@/components/max-token-number-from-field';
+import PageRankFormField from '@/components/page-rank-form-field';
+import GraphRagItems from '@/components/parse-configuration/graph-rag-form-fields';
+import RaptorFormFields from '@/components/parse-configuration/raptor-form-fields';
+import { TagItems } from '../tag-item';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function NaiveConfiguration() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/one.tsx b/web/src/pages/dataset/setting/configuration/one.tsx
new file mode 100644
index 000000000..3a9f6efc2
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/one.tsx
@@ -0,0 +1,30 @@
+import {
+ AutoKeywordsFormField,
+ AutoQuestionsFormField,
+} from '@/components/auto-keywords-form-field';
+import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
+import PageRankFormField from '@/components/page-rank-form-field';
+import GraphRagItems from '@/components/parse-configuration/graph-rag-form-fields';
+import { TagItems } from '../tag-item';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function OneConfiguration() {
+ return (
+ <>
+
+
+
+
+
+
+ <>
+
+
+ >
+
+
+
+
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/paper.tsx b/web/src/pages/dataset/setting/configuration/paper.tsx
new file mode 100644
index 000000000..9e1922a7a
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/paper.tsx
@@ -0,0 +1,33 @@
+import {
+ AutoKeywordsFormField,
+ AutoQuestionsFormField,
+} from '@/components/auto-keywords-form-field';
+import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
+import PageRankFormField from '@/components/page-rank-form-field';
+import GraphRagItems from '@/components/parse-configuration/graph-rag-form-fields';
+import RaptorFormFields from '@/components/parse-configuration/raptor-form-fields';
+import { TagItems } from '../tag-item';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function PaperConfiguration() {
+ return (
+ <>
+
+
+
+
+
+
+ <>
+
+
+ >
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/picture.tsx b/web/src/pages/dataset/setting/configuration/picture.tsx
new file mode 100644
index 000000000..3720d1920
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/picture.tsx
@@ -0,0 +1,24 @@
+import {
+ AutoKeywordsFormField,
+ AutoQuestionsFormField,
+} from '@/components/auto-keywords-form-field';
+import PageRankFormField from '@/components/page-rank-form-field';
+import { TagItems } from '../tag-item';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function PictureConfiguration() {
+ return (
+ <>
+
+
+
+
+
+ <>
+
+
+ >
+
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/presentation.tsx b/web/src/pages/dataset/setting/configuration/presentation.tsx
new file mode 100644
index 000000000..6db4c5aea
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/presentation.tsx
@@ -0,0 +1,33 @@
+import {
+ AutoKeywordsFormField,
+ AutoQuestionsFormField,
+} from '@/components/auto-keywords-form-field';
+import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
+import PageRankFormField from '@/components/page-rank-form-field';
+import GraphRagItems from '@/components/parse-configuration/graph-rag-form-fields';
+import RaptorFormFields from '@/components/parse-configuration/raptor-form-fields';
+import { TagItems } from '../tag-item';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function PresentationConfiguration() {
+ return (
+ <>
+
+
+
+
+
+
+ <>
+
+
+ >
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/qa.tsx b/web/src/pages/dataset/setting/configuration/qa.tsx
new file mode 100644
index 000000000..f76074307
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/qa.tsx
@@ -0,0 +1,16 @@
+import PageRankFormField from '@/components/page-rank-form-field';
+import { TagItems } from '../tag-item';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function QAConfiguration() {
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/resume.tsx b/web/src/pages/dataset/setting/configuration/resume.tsx
new file mode 100644
index 000000000..8a67d9af3
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/resume.tsx
@@ -0,0 +1,16 @@
+import PageRankFormField from '@/components/page-rank-form-field';
+import { TagItems } from '../tag-item';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function ResumeConfiguration() {
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/table.tsx b/web/src/pages/dataset/setting/configuration/table.tsx
new file mode 100644
index 000000000..0e6aecd37
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/table.tsx
@@ -0,0 +1,13 @@
+import PageRankFormField from '@/components/page-rank-form-field';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function TableConfiguration() {
+ return (
+ <>
+
+
+
+
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/configuration/tag.tsx b/web/src/pages/dataset/setting/configuration/tag.tsx
new file mode 100644
index 000000000..65ce9cb99
--- /dev/null
+++ b/web/src/pages/dataset/setting/configuration/tag.tsx
@@ -0,0 +1,13 @@
+import PageRankFormField from '@/components/page-rank-form-field';
+import { ChunkMethodItem, EmbeddingModelItem } from './common-item';
+
+export function TagConfiguration() {
+ return (
+ <>
+
+
+
+
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/general-form.tsx b/web/src/pages/dataset/setting/general-form.tsx
new file mode 100644
index 000000000..c298ce707
--- /dev/null
+++ b/web/src/pages/dataset/setting/general-form.tsx
@@ -0,0 +1,108 @@
+import { FileUploader } from '@/components/file-uploader';
+import { FormContainer } from '@/components/form-container';
+import {
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from '@/components/ui/form';
+import { Input } from '@/components/ui/input';
+import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
+import { useFormContext } from 'react-hook-form';
+import { useTranslation } from 'react-i18next';
+
+export function GeneralForm() {
+ const form = useFormContext();
+ const { t } = useTranslation();
+
+ return (
+
+ (
+
+ {t('knowledgeConfiguration.name')}
+
+
+
+
+
+ )}
+ />
+ (
+
+ {t('knowledgeConfiguration.description')}
+
+
+
+
+
+ )}
+ />
+ (
+
+ {t('knowledgeConfiguration.photo')}
+
+
+
+
+
+ )}
+ />
+
+ (
+
+
+ {t('knowledgeConfiguration.permissions')}
+
+
+
+
+
+
+
+
+ {t('knowledgeConfiguration.me')}
+
+
+
+
+
+
+
+ {t('knowledgeConfiguration.team')}
+
+
+
+
+
+
+ )}
+ />
+
+ );
+}
diff --git a/web/src/pages/dataset/setting/hooks.ts b/web/src/pages/dataset/setting/hooks.ts
new file mode 100644
index 000000000..e20b63516
--- /dev/null
+++ b/web/src/pages/dataset/setting/hooks.ts
@@ -0,0 +1,123 @@
+import { LlmModelType } from '@/constants/knowledge';
+import { useSetModalState } from '@/hooks/common-hooks';
+
+import { useSelectLlmOptionsByModelType } from '@/hooks/llm-hooks';
+import { useNavigateToDataset } from '@/hooks/route-hook';
+import {
+ useFetchKnowledgeBaseConfiguration,
+ useUpdateKnowledge,
+} from '@/hooks/use-knowledge-request';
+import { useSelectParserList } from '@/hooks/user-setting-hooks';
+import {
+ getBase64FromUploadFileList,
+ getUploadFileListFromBase64,
+} from '@/utils/file-util';
+import { useIsFetching } from '@tanstack/react-query';
+import { Form, UploadFile } from 'antd';
+import { FormInstance } from 'antd/lib';
+import pick from 'lodash/pick';
+import { useCallback, useEffect, useState } from 'react';
+import { UseFormReturn } from 'react-hook-form';
+
+export const useSubmitKnowledgeConfiguration = (form: FormInstance) => {
+ const { saveKnowledgeConfiguration, loading } = useUpdateKnowledge();
+ const navigateToDataset = useNavigateToDataset();
+
+ const submitKnowledgeConfiguration = useCallback(async () => {
+ const values = await form.validateFields();
+ const avatar = await getBase64FromUploadFileList(values.avatar);
+ saveKnowledgeConfiguration({
+ ...values,
+ avatar,
+ });
+ navigateToDataset();
+ }, [saveKnowledgeConfiguration, form, navigateToDataset]);
+
+ return {
+ submitKnowledgeConfiguration,
+ submitLoading: loading,
+ navigateToDataset,
+ };
+};
+
+// The value that does not need to be displayed in the analysis method Select
+const HiddenFields = ['email', 'picture', 'audio'];
+
+export function useSelectChunkMethodList() {
+ const parserList = useSelectParserList();
+
+ return parserList.filter((x) => !HiddenFields.some((y) => y === x.value));
+}
+
+export function useSelectEmbeddingModelOptions() {
+ const allOptions = useSelectLlmOptionsByModelType();
+ return allOptions[LlmModelType.Embedding];
+}
+
+export function useHasParsedDocument() {
+ const { data: knowledgeDetails } = useFetchKnowledgeBaseConfiguration();
+ return knowledgeDetails.chunk_num > 0;
+}
+
+export const useFetchKnowledgeConfigurationOnMount = (form: UseFormReturn) => {
+ const { data: knowledgeDetails } = useFetchKnowledgeBaseConfiguration();
+
+ useEffect(() => {
+ const fileList: UploadFile[] = getUploadFileListFromBase64(
+ knowledgeDetails.avatar,
+ );
+ form.reset({
+ ...pick(knowledgeDetails, [
+ 'description',
+ 'name',
+ 'permission',
+ 'embd_id',
+ 'parser_id',
+ 'language',
+ 'parser_config',
+ 'pagerank',
+ ]),
+ avatar: fileList,
+ });
+ }, [form, knowledgeDetails]);
+
+ return knowledgeDetails;
+};
+
+export const useSelectKnowledgeDetailsLoading = () =>
+ useIsFetching({ queryKey: ['fetchKnowledgeDetail'] }) > 0;
+
+export const useHandleChunkMethodChange = () => {
+ const [form] = Form.useForm();
+ const chunkMethod = Form.useWatch('parser_id', form);
+
+ useEffect(() => {
+ console.log('🚀 ~ useHandleChunkMethodChange ~ chunkMethod:', chunkMethod);
+ }, [chunkMethod]);
+
+ return { form, chunkMethod };
+};
+
+export const useRenameKnowledgeTag = () => {
+ const [tag, setTag] = useState('');
+ const {
+ visible: tagRenameVisible,
+ hideModal: hideTagRenameModal,
+ showModal: showFileRenameModal,
+ } = useSetModalState();
+
+ const handleShowTagRenameModal = useCallback(
+ (record: string) => {
+ setTag(record);
+ showFileRenameModal();
+ },
+ [showFileRenameModal],
+ );
+
+ return {
+ initialName: tag,
+ tagRenameVisible,
+ hideTagRenameModal,
+ showTagRenameModal: handleShowTagRenameModal,
+ };
+};
diff --git a/web/src/pages/dataset/setting/index.tsx b/web/src/pages/dataset/setting/index.tsx
index 93278fc6d..bbbb73ee6 100644
--- a/web/src/pages/dataset/setting/index.tsx
+++ b/web/src/pages/dataset/setting/index.tsx
@@ -1,25 +1,137 @@
-import { Card, CardContent } from '@/components/ui/card';
-import AdvancedSettingForm from './advanced-setting-form';
-import BasicSettingForm from './basic-setting-form';
+import { Form } from '@/components/ui/form';
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
+import { DocumentParserType } from '@/constants/knowledge';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { useForm } from 'react-hook-form';
+import { z } from 'zod';
+import CategoryPanel from './category-panel';
+import { ChunkMethodForm } from './chunk-method-form';
+import { GeneralForm } from './general-form';
+
+const enum DocumentType {
+ DeepDOC = 'DeepDOC',
+ PlainText = 'Plain Text',
+}
+
+const initialEntityTypes = [
+ 'organization',
+ 'person',
+ 'geo',
+ 'event',
+ 'category',
+];
+
+const enum MethodValue {
+ General = 'general',
+ Light = 'light',
+}
export default function DatasetSettings() {
- return (
-
- Basic settings
-
-
-
-
-
-
-
+ const formSchema = z.object({
+ name: z.string().min(1, {
+ message: 'Username must be at least 2 characters.',
+ }),
+ description: z.string().min(2, {
+ message: 'Username must be at least 2 characters.',
+ }),
+ avatar: z.instanceof(File),
+ permission: z.string(),
+ parser_id: z.string(),
+ parser_config: z.object({
+ layout_recognize: z.string(),
+ chunk_token_num: z.number(),
+ delimiter: z.string(),
+ auto_keywords: z.number(),
+ auto_questions: z.number(),
+ html4excel: z.boolean(),
+ tag_kb_ids: z.array(z.string()),
+ topn_tags: z.number(),
+ raptor: z.object({
+ use_raptor: z.boolean(),
+ prompt: z.string(),
+ max_token: z.number(),
+ threshold: z.number(),
+ max_cluster: z.number(),
+ random_seed: z.number(),
+ }),
+ graphrag: z.object({
+ use_graphrag: z.boolean(),
+ entity_types: z.array(z.string()),
+ method: z.string(),
+ resolution: z.boolean(),
+ community: z.boolean(),
+ }),
+ }),
+ pagerank: z.number(),
+ // icon: z.array(z.instanceof(File)),
+ });
- Advanced settings
-
-
-
-
-
+ const form = useForm>({
+ resolver: zodResolver(formSchema),
+ defaultValues: {
+ name: '',
+ parser_id: DocumentParserType.Naive,
+ permission: 'me',
+ parser_config: {
+ layout_recognize: DocumentType.DeepDOC,
+ chunk_token_num: 512,
+ delimiter: `\n`,
+ auto_keywords: 0,
+ auto_questions: 0,
+ html4excel: false,
+ topn_tags: 3,
+ raptor: {
+ use_raptor: false,
+ max_token: 256,
+ threshold: 0.1,
+ max_cluster: 64,
+ random_seed: 0,
+ },
+ graphrag: {
+ use_graphrag: false,
+ entity_types: initialEntityTypes,
+ method: MethodValue.Light,
+ },
+ },
+ pagerank: 0,
+ },
+ });
+
+ async function onSubmit(data: z.infer) {
+ console.log('🚀 ~ DatasetSettings ~ data:', data);
+ }
+
+ return (
+
+
+
Configuration
+
+ Update your knowledge base configuration here, particularly the chunk
+ method.
+
+
+
+
+
+
+
);
}
diff --git a/web/src/pages/dataset/setting/tag-item.tsx b/web/src/pages/dataset/setting/tag-item.tsx
new file mode 100644
index 000000000..01c5c6f3f
--- /dev/null
+++ b/web/src/pages/dataset/setting/tag-item.tsx
@@ -0,0 +1,144 @@
+import { SliderInputFormField } from '@/components/slider-input-form-field';
+import {
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from '@/components/ui/form';
+import { MultiSelect } from '@/components/ui/multi-select';
+import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks';
+import { UserOutlined } from '@ant-design/icons';
+import { Avatar, Flex, Form, InputNumber, Select, Slider, Space } from 'antd';
+import DOMPurify from 'dompurify';
+import { useFormContext, useWatch } from 'react-hook-form';
+import { useTranslation } from 'react-i18next';
+
+export const TagSetItem = () => {
+ const { t } = useTranslation();
+ const form = useFormContext();
+
+ const { list: knowledgeList } = useFetchKnowledgeList(true);
+
+ const knowledgeOptions = knowledgeList
+ .filter((x) => x.parser_id === 'tag')
+ .map((x) => ({
+ label: x.name,
+ value: x.id,
+ icon: () => (
+
+ } src={x.avatar} />
+ {x.name}
+
+ ),
+ }));
+
+ return (
+ (
+
+
+ }
+ >
+ {t('knowledgeConfiguration.tagSet')}
+
+
+
+
+
+
+ )}
+ />
+ );
+
+ return (
+
+ }
+ rules={[
+ {
+ message: t('chat.knowledgeBasesMessage'),
+ type: 'array',
+ },
+ ]}
+ >
+
+
+ );
+};
+
+export const TopNTagsItem = () => {
+ const { t } = useTranslation();
+
+ return (
+
+ );
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export function TagItems() {
+ const form = useFormContext();
+ const ids: string[] = useWatch({
+ control: form.control,
+ name: 'parser_config.tag_kb_ids',
+ });
+
+ return (
+ <>
+
+ {Array.isArray(ids) && ids.length > 0 && }
+ >
+ );
+}
diff --git a/web/src/pages/dataset/setting/tag-table/index.tsx b/web/src/pages/dataset/setting/tag-table/index.tsx
new file mode 100644
index 000000000..0ab25a86e
--- /dev/null
+++ b/web/src/pages/dataset/setting/tag-table/index.tsx
@@ -0,0 +1,307 @@
+'use client';
+
+import {
+ ColumnDef,
+ ColumnFiltersState,
+ SortingState,
+ VisibilityState,
+ flexRender,
+ getCoreRowModel,
+ getFilteredRowModel,
+ getPaginationRowModel,
+ getSortedRowModel,
+ useReactTable,
+} from '@tanstack/react-table';
+import { ArrowUpDown, Pencil, Trash2 } from 'lucide-react';
+import * as React from 'react';
+
+import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
+import { Button } from '@/components/ui/button';
+import { Checkbox } from '@/components/ui/checkbox';
+import { Input } from '@/components/ui/input';
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from '@/components/ui/table';
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from '@/components/ui/tooltip';
+import { useDeleteTag, useFetchTagList } from '@/hooks/knowledge-hooks';
+import { useCallback, useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useRenameKnowledgeTag } from '../hooks';
+import { RenameDialog } from './rename-dialog';
+
+export type ITag = {
+ tag: string;
+ frequency: number;
+};
+
+export function TagTable() {
+ const { t } = useTranslation();
+ const { list } = useFetchTagList();
+ const [tagList, setTagList] = useState([]);
+
+ const [sorting, setSorting] = React.useState([]);
+ const [columnFilters, setColumnFilters] = React.useState(
+ [],
+ );
+ const [columnVisibility, setColumnVisibility] =
+ React.useState({});
+ const [rowSelection, setRowSelection] = useState({});
+
+ const { deleteTag } = useDeleteTag();
+
+ useEffect(() => {
+ setTagList(list.map((x) => ({ tag: x[0], frequency: x[1] })));
+ }, [list]);
+
+ const handleDeleteTag = useCallback(
+ (tags: string[]) => () => {
+ deleteTag(tags);
+ },
+ [deleteTag],
+ );
+
+ const {
+ showTagRenameModal,
+ hideTagRenameModal,
+ tagRenameVisible,
+ initialName,
+ } = useRenameKnowledgeTag();
+
+ const columns: ColumnDef[] = [
+ {
+ id: 'select',
+ header: ({ table }) => (
+ table.toggleAllPageRowsSelected(!!value)}
+ aria-label="Select all"
+ />
+ ),
+ cell: ({ row }) => (
+ row.toggleSelected(!!value)}
+ aria-label="Select row"
+ />
+ ),
+ enableSorting: false,
+ enableHiding: false,
+ },
+ {
+ accessorKey: 'tag',
+ header: ({ column }) => {
+ return (
+
+ );
+ },
+ cell: ({ row }) => {
+ const value: string = row.getValue('tag');
+ return {value}
;
+ },
+ },
+ {
+ accessorKey: 'frequency',
+ header: ({ column }) => {
+ return (
+
+ );
+ },
+ cell: ({ row }) => (
+ {row.getValue('frequency')}
+ ),
+ },
+ {
+ id: 'actions',
+ enableHiding: false,
+ header: t('common.action'),
+ cell: ({ row }) => {
+ return (
+
+
+
+
+
+
+
+
+ {t('common.delete')}
+
+
+
+
+
+
+
+ {t('common.rename')}
+
+
+
+ );
+ },
+ },
+ ];
+
+ const table = useReactTable({
+ data: tagList,
+ columns,
+ onSortingChange: setSorting,
+ onColumnFiltersChange: setColumnFilters,
+ getCoreRowModel: getCoreRowModel(),
+ getPaginationRowModel: getPaginationRowModel(),
+ getSortedRowModel: getSortedRowModel(),
+ getFilteredRowModel: getFilteredRowModel(),
+ onColumnVisibilityChange: setColumnVisibility,
+ onRowSelectionChange: setRowSelection,
+ state: {
+ sorting,
+ columnFilters,
+ columnVisibility,
+ rowSelection,
+ },
+ });
+
+ const selectedRowLength = table.getFilteredSelectedRowModel().rows.length;
+
+ return (
+
+
+
+
+ table.getColumn('tag')?.setFilterValue(event.target.value)
+ }
+ className="w-1/2"
+ />
+ {selectedRowLength > 0 && (
+ x.original.tag),
+ )}
+ >
+
+
+ )}
+
+
+
+
+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => {
+ return (
+
+ {header.isPlaceholder
+ ? null
+ : flexRender(
+ header.column.columnDef.header,
+ header.getContext(),
+ )}
+
+ );
+ })}
+
+ ))}
+
+
+ {table.getRowModel().rows?.length ? (
+ table.getRowModel().rows.map((row) => (
+
+ {row.getVisibleCells().map((cell) => (
+
+ {flexRender(
+ cell.column.columnDef.cell,
+ cell.getContext(),
+ )}
+
+ ))}
+
+ ))
+ ) : (
+
+
+ No results.
+
+
+ )}
+
+
+
+
+
+ {selectedRowLength} of {table.getFilteredRowModel().rows.length}{' '}
+ row(s) selected.
+
+
+
+
+
+
+
+ {tagRenameVisible && (
+
+ )}
+
+ );
+}
diff --git a/web/src/pages/dataset/setting/tag-table/rename-dialog/index.tsx b/web/src/pages/dataset/setting/tag-table/rename-dialog/index.tsx
new file mode 100644
index 000000000..b95907f92
--- /dev/null
+++ b/web/src/pages/dataset/setting/tag-table/rename-dialog/index.tsx
@@ -0,0 +1,40 @@
+import {
+ Dialog,
+ DialogContent,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from '@/components/ui/dialog';
+import { LoadingButton } from '@/components/ui/loading-button';
+import { useTagIsRenaming } from '@/hooks/knowledge-hooks';
+import { IModalProps } from '@/interfaces/common';
+import { TagRenameId } from '@/pages/add-knowledge/constant';
+import { useTranslation } from 'react-i18next';
+import { RenameForm } from './rename-form';
+
+export function RenameDialog({
+ hideModal,
+ initialName,
+}: IModalProps & { initialName: string }) {
+ const { t } = useTranslation();
+ const loading = useTagIsRenaming();
+
+ return (
+
+ );
+}
diff --git a/web/src/pages/dataset/setting/tag-table/rename-dialog/rename-form.tsx b/web/src/pages/dataset/setting/tag-table/rename-dialog/rename-form.tsx
new file mode 100644
index 000000000..9c8f1cf7e
--- /dev/null
+++ b/web/src/pages/dataset/setting/tag-table/rename-dialog/rename-form.tsx
@@ -0,0 +1,83 @@
+'use client';
+
+import { zodResolver } from '@hookform/resolvers/zod';
+import { useForm } from 'react-hook-form';
+import { z } from 'zod';
+
+import {
+ Form,
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from '@/components/ui/form';
+import { Input } from '@/components/ui/input';
+import { useRenameTag } from '@/hooks/knowledge-hooks';
+import { IModalProps } from '@/interfaces/common';
+import { TagRenameId } from '@/pages/add-knowledge/constant';
+import { useEffect } from 'react';
+import { useTranslation } from 'react-i18next';
+
+export function RenameForm({
+ initialName,
+ hideModal,
+}: IModalProps & { initialName: string }) {
+ const { t } = useTranslation();
+ const FormSchema = z.object({
+ name: z
+ .string()
+ .min(1, {
+ message: t('common.namePlaceholder'),
+ })
+ .trim(),
+ });
+
+ const form = useForm>({
+ resolver: zodResolver(FormSchema),
+ defaultValues: {
+ name: '',
+ },
+ });
+
+ const { renameTag } = useRenameTag();
+
+ async function onSubmit(data: z.infer) {
+ const ret = await renameTag({ fromTag: initialName, toTag: data.name });
+ if (ret) {
+ hideModal?.();
+ }
+ }
+
+ useEffect(() => {
+ form.setValue('name', initialName);
+ }, [form, initialName]);
+
+ return (
+
+
+ );
+}
diff --git a/web/src/pages/dataset/setting/tag-tabs.tsx b/web/src/pages/dataset/setting/tag-tabs.tsx
new file mode 100644
index 000000000..abcd3f673
--- /dev/null
+++ b/web/src/pages/dataset/setting/tag-tabs.tsx
@@ -0,0 +1,40 @@
+import { Segmented } from 'antd';
+import { SegmentedLabeledOption } from 'antd/es/segmented';
+import { upperFirst } from 'lodash';
+import { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { TagTable } from './tag-table';
+import { TagWordCloud } from './tag-word-cloud';
+
+enum TagType {
+ Cloud = 'cloud',
+ Table = 'table',
+}
+
+const TagContentMap = {
+ [TagType.Cloud]: ,
+ [TagType.Table]: ,
+};
+
+export function TagTabs() {
+ const [value, setValue] = useState(TagType.Cloud);
+ const { t } = useTranslation();
+
+ const options: SegmentedLabeledOption[] = [TagType.Cloud, TagType.Table].map(
+ (x) => ({
+ label: t(`knowledgeConfiguration.tag${upperFirst(x)}`),
+ value: x,
+ }),
+ );
+
+ return (
+
+ setValue(val as TagType)}
+ />
+ {TagContentMap[value]}
+
+ );
+}
diff --git a/web/src/pages/dataset/setting/tag-word-cloud.tsx b/web/src/pages/dataset/setting/tag-word-cloud.tsx
new file mode 100644
index 000000000..b71ed69af
--- /dev/null
+++ b/web/src/pages/dataset/setting/tag-word-cloud.tsx
@@ -0,0 +1,62 @@
+import { useFetchTagList } from '@/hooks/knowledge-hooks';
+import { Chart } from '@antv/g2';
+import { sumBy } from 'lodash';
+import { useCallback, useEffect, useMemo, useRef } from 'react';
+
+export function TagWordCloud() {
+ const domRef = useRef(null);
+ let chartRef = useRef();
+ const { list } = useFetchTagList();
+
+ const { list: tagList } = useMemo(() => {
+ const nextList = list.sort((a, b) => b[1] - a[1]).slice(0, 256);
+
+ return {
+ list: nextList.map((x) => ({ text: x[0], value: x[1], name: x[0] })),
+ sumValue: sumBy(nextList, (x: [string, number]) => x[1]),
+ length: nextList.length,
+ };
+ }, [list]);
+
+ const renderWordCloud = useCallback(() => {
+ if (domRef.current) {
+ chartRef.current = new Chart({ container: domRef.current });
+
+ chartRef.current.options({
+ type: 'wordCloud',
+ autoFit: true,
+ layout: {
+ fontSize: [10, 50],
+ // fontSize: (d: any) => {
+ // if (d.value) {
+ // return (d.value / sumValue) * 100 * (length / 10);
+ // }
+ // return 0;
+ // },
+ },
+ data: {
+ type: 'inline',
+ value: tagList,
+ },
+ encode: { color: 'text' },
+ legend: false,
+ tooltip: {
+ title: 'name', // title
+ items: ['value'], // data item
+ },
+ });
+
+ chartRef.current.render();
+ }
+ }, [tagList]);
+
+ useEffect(() => {
+ renderWordCloud();
+
+ return () => {
+ chartRef.current?.destroy();
+ };
+ }, [renderWordCloud]);
+
+ return ;
+}