mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-26 00:46:52 +08:00
### What problem does this PR solve? feat: Added UI functions related to data-flow knowledge base #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
31
web/src/pages/dataset/dataset-setting/chunk-method-form.tsx
Normal file
31
web/src/pages/dataset/dataset-setting/chunk-method-form.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { NaiveConfiguration } from './naive';
|
||||
import { SavingButton } from './saving-button';
|
||||
|
||||
export function ChunkMethodForm() {
|
||||
const form = useFormContext();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<section className="h-full flex flex-col">
|
||||
<div className="overflow-auto flex-1 min-h-0">
|
||||
<NaiveConfiguration></NaiveConfiguration>
|
||||
</div>
|
||||
<div className="text-right pt-4 flex justify-end gap-3">
|
||||
<Button
|
||||
type="reset"
|
||||
className="bg-transparent text-color-white hover:bg-transparent border-gray-500 border-[1px]"
|
||||
onClick={() => {
|
||||
form.reset();
|
||||
}}
|
||||
>
|
||||
{t('knowledgeConfiguration.cancel')}
|
||||
</Button>
|
||||
<SavingButton></SavingButton>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
155
web/src/pages/dataset/dataset-setting/components/tag-item.tsx
Normal file
155
web/src/pages/dataset/dataset-setting/components/tag-item.tsx
Normal file
@ -0,0 +1,155 @@
|
||||
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
|
||||
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 { 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: () => (
|
||||
<Space>
|
||||
<RAGFlowAvatar
|
||||
name={x.name}
|
||||
avatar={x.avatar}
|
||||
className="size-4"
|
||||
></RAGFlowAvatar>
|
||||
</Space>
|
||||
),
|
||||
}));
|
||||
|
||||
return (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="parser_config.tag_kb_ids"
|
||||
render={({ field }) => (
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="flex items-center">
|
||||
<FormLabel
|
||||
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
|
||||
tooltip={
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: DOMPurify.sanitize(
|
||||
t('knowledgeConfiguration.tagSetTip'),
|
||||
),
|
||||
}}
|
||||
></div>
|
||||
}
|
||||
>
|
||||
{t('knowledgeConfiguration.tagSet')}
|
||||
</FormLabel>
|
||||
<div className="w-3/4">
|
||||
<FormControl>
|
||||
<MultiSelect
|
||||
options={knowledgeOptions}
|
||||
onValueChange={field.onChange}
|
||||
placeholder={t('chat.knowledgeBasesMessage')}
|
||||
variant="inverted"
|
||||
maxCount={10}
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<Form.Item
|
||||
label={t('knowledgeConfiguration.tagSet')}
|
||||
name={['parser_config', 'tag_kb_ids']}
|
||||
tooltip={
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: DOMPurify.sanitize(t('knowledgeConfiguration.tagSetTip')),
|
||||
}}
|
||||
></div>
|
||||
}
|
||||
rules={[
|
||||
{
|
||||
message: t('chat.knowledgeBasesMessage'),
|
||||
type: 'array',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select
|
||||
mode="multiple"
|
||||
options={knowledgeOptions}
|
||||
placeholder={t('chat.knowledgeBasesMessage')}
|
||||
></Select>
|
||||
</Form.Item>
|
||||
);
|
||||
};
|
||||
|
||||
export const TopNTagsItem = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<SliderInputFormField
|
||||
name={'parser_config.topn_tags'}
|
||||
label={t('knowledgeConfiguration.topnTags')}
|
||||
max={10}
|
||||
min={1}
|
||||
defaultValue={3}
|
||||
></SliderInputFormField>
|
||||
);
|
||||
|
||||
return (
|
||||
<Form.Item label={t('knowledgeConfiguration.topnTags')}>
|
||||
<Flex gap={20} align="center">
|
||||
<Flex flex={1}>
|
||||
<Form.Item
|
||||
name={['parser_config', 'topn_tags']}
|
||||
noStyle
|
||||
initialValue={3}
|
||||
>
|
||||
<Slider max={10} min={1} style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
<Form.Item name={['parser_config', 'topn_tags']} noStyle>
|
||||
<InputNumber max={10} min={1} />
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
</Form.Item>
|
||||
);
|
||||
};
|
||||
|
||||
export function TagItems() {
|
||||
const form = useFormContext();
|
||||
const ids: string[] = useWatch({
|
||||
control: form.control,
|
||||
name: 'parser_config.tag_kb_ids',
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<TagSetItem></TagSetItem>
|
||||
{Array.isArray(ids) && ids.length > 0 && <TopNTagsItem></TopNTagsItem>}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
import { FormContainerProps } from '@/components/form-container';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { PropsWithChildren } from 'react';
|
||||
|
||||
export function ConfigurationFormContainer({
|
||||
children,
|
||||
className,
|
||||
}: FormContainerProps) {
|
||||
return <section className={cn('space-y-4', className)}>{children}</section>;
|
||||
}
|
||||
|
||||
export function MainContainer({ children }: PropsWithChildren) {
|
||||
return <section className="space-y-5">{children}</section>;
|
||||
}
|
||||
@ -0,0 +1,328 @@
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Radio } from '@/components/ui/radio';
|
||||
import { RAGFlowSelect } from '@/components/ui/select';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { ArrowUpRight } from 'lucide-react';
|
||||
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 (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={'parser_id'}
|
||||
render={({ field }) => (
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="flex items-center">
|
||||
<FormLabel
|
||||
required
|
||||
tooltip={t('chunkMethodTip')}
|
||||
className="text-sm text-muted-foreground whitespace-wrap w-1/4"
|
||||
>
|
||||
{t('chunkMethod')}
|
||||
</FormLabel>
|
||||
<div className="w-3/4 ">
|
||||
<FormControl>
|
||||
<RAGFlowSelect
|
||||
{...field}
|
||||
options={parserList}
|
||||
placeholder={t('chunkMethodPlaceholder')}
|
||||
// onChange={handleChunkMethodSelectChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function EmbeddingModelItem({ line = 1 }: { line?: 1 | 2 }) {
|
||||
const { t } = useTranslate('knowledgeConfiguration');
|
||||
const form = useFormContext();
|
||||
const embeddingModelOptions = useSelectEmbeddingModelOptions();
|
||||
const disabled = useHasParsedDocument();
|
||||
|
||||
return (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={'embd_id'}
|
||||
render={({ field }) => (
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className={cn({ 'flex items-center': line === 1 })}>
|
||||
<FormLabel
|
||||
required
|
||||
tooltip={t('embeddingModelTip')}
|
||||
className={cn('text-sm whitespace-wrap ', {
|
||||
'w-1/4': line === 1,
|
||||
})}
|
||||
>
|
||||
{t('embeddingModel')}
|
||||
</FormLabel>
|
||||
<div
|
||||
className={cn('text-muted-foreground', { 'w-3/4': line === 1 })}
|
||||
>
|
||||
<FormControl>
|
||||
<RAGFlowSelect
|
||||
{...field}
|
||||
options={embeddingModelOptions}
|
||||
disabled={disabled}
|
||||
placeholder={t('embeddingModelPlaceholder')}
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function ParseTypeItem() {
|
||||
const { t } = useTranslate('knowledgeConfiguration');
|
||||
const form = useFormContext();
|
||||
|
||||
return (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={'parseType'}
|
||||
render={({ field }) => (
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="">
|
||||
<FormLabel
|
||||
tooltip={t('parseTypeTip')}
|
||||
className="text-sm whitespace-wrap "
|
||||
>
|
||||
{t('parseType')}
|
||||
</FormLabel>
|
||||
<div className="text-muted-foreground">
|
||||
<FormControl>
|
||||
<Radio.Group {...field}>
|
||||
<div className="w-3/4 flex gap-2 justify-between text-muted-foreground">
|
||||
<Radio value={1}>{t('builtIn')}</Radio>
|
||||
<Radio value={2}>{t('manualSetup')}</Radio>
|
||||
</div>
|
||||
</Radio.Group>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function DataFlowItem() {
|
||||
const { t } = useTranslate('knowledgeConfiguration');
|
||||
const form = useFormContext();
|
||||
|
||||
return (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={'data_flow'}
|
||||
render={({ field }) => (
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="">
|
||||
<div className="flex gap-2 justify-between ">
|
||||
<FormLabel
|
||||
tooltip={t('dataFlowTip')}
|
||||
className="text-sm text-text-primary whitespace-wrap "
|
||||
>
|
||||
{t('dataFlow')}
|
||||
</FormLabel>
|
||||
<div className="text-sm flex text-text-primary">
|
||||
{t('buildItFromScratch')}
|
||||
<ArrowUpRight size={14} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-muted-foreground">
|
||||
<FormControl>
|
||||
<RAGFlowSelect
|
||||
{...field}
|
||||
placeholder={t('dataFlowPlaceholder')}
|
||||
options={[{ value: '0', label: t('dataFlowDefault') }]}
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function DataExtractKnowledgeItem() {
|
||||
const { t } = useTranslate('knowledgeConfiguration');
|
||||
const form = useFormContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
{' '}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={'extractKnowledgeGraph'}
|
||||
render={({ field }) => (
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="">
|
||||
<FormLabel
|
||||
tooltip={t('extractKnowledgeGraphTip')}
|
||||
className="text-sm whitespace-wrap "
|
||||
>
|
||||
{t('extractKnowledgeGraph')}
|
||||
</FormLabel>
|
||||
<div className="text-muted-foreground">
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>{' '}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={'useRAPTORToEnhanceRetrieval'}
|
||||
render={({ field }) => (
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="">
|
||||
<FormLabel
|
||||
tooltip={t('useRAPTORToEnhanceRetrievalTip')}
|
||||
className="text-sm whitespace-wrap "
|
||||
>
|
||||
{t('useRAPTORToEnhanceRetrieval')}
|
||||
</FormLabel>
|
||||
<div className="text-muted-foreground">
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function TeamItem() {
|
||||
const { t } = useTranslate('knowledgeConfiguration');
|
||||
const form = useFormContext();
|
||||
|
||||
return (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={'team'}
|
||||
render={({ field }) => (
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="">
|
||||
<FormLabel
|
||||
tooltip={t('teamTip')}
|
||||
className="text-sm whitespace-wrap "
|
||||
>
|
||||
<span className="text-destructive mr-1"> *</span>
|
||||
{t('team')}
|
||||
</FormLabel>
|
||||
<div className="text-muted-foreground">
|
||||
<FormControl>
|
||||
<RAGFlowSelect
|
||||
{...field}
|
||||
placeholder={t('teamPlaceholder')}
|
||||
options={[{ value: '0', label: t('teamDefault') }]}
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function EnableAutoGenerateItem() {
|
||||
const { t } = useTranslate('knowledgeConfiguration');
|
||||
const form = useFormContext();
|
||||
|
||||
return (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={'enableAutoGenerate'}
|
||||
render={({ field }) => (
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="flex items-center">
|
||||
<FormLabel
|
||||
tooltip={t('enableAutoGenerateTip')}
|
||||
className="text-sm whitespace-wrap w-1/4"
|
||||
>
|
||||
{t('enableAutoGenerate')}
|
||||
</FormLabel>
|
||||
<div className="text-muted-foreground w-3/4">
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
73
web/src/pages/dataset/dataset-setting/form-schema.ts
Normal file
73
web/src/pages/dataset/dataset-setting/form-schema.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export 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),
|
||||
avatar: z.any().nullish(),
|
||||
permission: z.string().optional(),
|
||||
parser_id: z.string(),
|
||||
embd_id: z.string(),
|
||||
parser_config: z
|
||||
.object({
|
||||
layout_recognize: z.string(),
|
||||
chunk_token_num: z.number(),
|
||||
delimiter: z.string(),
|
||||
auto_keywords: z.number().optional(),
|
||||
auto_questions: z.number().optional(),
|
||||
html4excel: z.boolean(),
|
||||
tag_kb_ids: z.array(z.string()).nullish(),
|
||||
topn_tags: z.number().optional(),
|
||||
raptor: z
|
||||
.object({
|
||||
use_raptor: z.boolean().optional(),
|
||||
prompt: z.string().optional(),
|
||||
max_token: z.number().optional(),
|
||||
threshold: z.number().optional(),
|
||||
max_cluster: z.number().optional(),
|
||||
random_seed: z.number().optional(),
|
||||
})
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.use_raptor && !data.prompt) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: 'Prompt is required',
|
||||
path: ['prompt'],
|
||||
},
|
||||
),
|
||||
graphrag: z
|
||||
.object({
|
||||
use_graphrag: z.boolean().optional(),
|
||||
entity_types: z.array(z.string()).optional(),
|
||||
method: z.string().optional(),
|
||||
resolution: z.boolean().optional(),
|
||||
community: z.boolean().optional(),
|
||||
})
|
||||
.refine(
|
||||
(data) => {
|
||||
if (
|
||||
data.use_graphrag &&
|
||||
(!data.entity_types || data.entity_types.length === 0)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: 'Please enter Entity types',
|
||||
path: ['entity_types'],
|
||||
},
|
||||
),
|
||||
})
|
||||
.optional(),
|
||||
pagerank: z.number(),
|
||||
// icon: z.array(z.instanceof(File)),
|
||||
});
|
||||
92
web/src/pages/dataset/dataset-setting/general-form.tsx
Normal file
92
web/src/pages/dataset/dataset-setting/general-form.tsx
Normal file
@ -0,0 +1,92 @@
|
||||
import { AvatarUpload } from '@/components/avatar-upload';
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { EmbeddingModelItem } from './configuration/common-item';
|
||||
import { PermissionFormField } from './permission-form-field';
|
||||
|
||||
export function GeneralForm() {
|
||||
const form = useFormContext();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<section className="space-y-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem className="items-center space-y-0">
|
||||
<div className="flex">
|
||||
<FormLabel className="text-sm text-muted-foreground whitespace-nowrap w-1/4">
|
||||
<span className="text-red-600">*</span>
|
||||
{t('common.name')}
|
||||
</FormLabel>
|
||||
<FormControl className="w-3/4">
|
||||
<Input {...field}></Input>
|
||||
</FormControl>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="avatar"
|
||||
render={({ field }) => (
|
||||
<FormItem className="items-center space-y-0">
|
||||
<div className="flex">
|
||||
<FormLabel className="text-sm text-muted-foreground whitespace-nowrap w-1/4">
|
||||
{t('setting.avatar')}
|
||||
</FormLabel>
|
||||
<FormControl className="w-3/4">
|
||||
<AvatarUpload {...field}></AvatarUpload>
|
||||
</FormControl>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="description"
|
||||
render={({ field }) => {
|
||||
// null initialize empty string
|
||||
if (typeof field.value === 'object' && !field.value) {
|
||||
form.setValue('description', ' ');
|
||||
}
|
||||
return (
|
||||
<FormItem className="items-center space-y-0">
|
||||
<div className="flex">
|
||||
<FormLabel className="text-sm text-muted-foreground whitespace-nowrap w-1/4">
|
||||
{t('flow.description')}
|
||||
</FormLabel>
|
||||
<FormControl className="w-3/4">
|
||||
<Input {...field}></Input>
|
||||
</FormControl>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<PermissionFormField></PermissionFormField>
|
||||
<EmbeddingModelItem></EmbeddingModelItem>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
87
web/src/pages/dataset/dataset-setting/hooks.ts
Normal file
87
web/src/pages/dataset/dataset-setting/hooks.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import { LlmModelType } from '@/constants/knowledge';
|
||||
import { useSetModalState } from '@/hooks/common-hooks';
|
||||
|
||||
import { useSelectLlmOptionsByModelType } from '@/hooks/llm-hooks';
|
||||
import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request';
|
||||
import { useSelectParserList } from '@/hooks/user-setting-hooks';
|
||||
import { useIsFetching } from '@tanstack/react-query';
|
||||
import { pick } from 'lodash';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { UseFormReturn } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import { formSchema } from './form-schema';
|
||||
|
||||
// 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<z.infer<typeof formSchema>, any, undefined>,
|
||||
) => {
|
||||
const { data: knowledgeDetails } = useFetchKnowledgeBaseConfiguration();
|
||||
|
||||
useEffect(() => {
|
||||
const parser_config = {
|
||||
...form.formState?.defaultValues?.parser_config,
|
||||
...knowledgeDetails.parser_config,
|
||||
};
|
||||
const formValues = {
|
||||
...pick({ ...knowledgeDetails, parser_config: parser_config }, [
|
||||
'description',
|
||||
'name',
|
||||
'permission',
|
||||
'embd_id',
|
||||
'parser_id',
|
||||
'language',
|
||||
'parser_config',
|
||||
'pagerank',
|
||||
'avatar',
|
||||
]),
|
||||
};
|
||||
form.reset(formValues);
|
||||
}, [form, knowledgeDetails]);
|
||||
|
||||
return knowledgeDetails;
|
||||
};
|
||||
|
||||
export const useSelectKnowledgeDetailsLoading = () =>
|
||||
useIsFetching({ queryKey: ['fetchKnowledgeDetail'] }) > 0;
|
||||
|
||||
export const useRenameKnowledgeTag = () => {
|
||||
const [tag, setTag] = useState<string>('');
|
||||
const {
|
||||
visible: tagRenameVisible,
|
||||
hideModal: hideTagRenameModal,
|
||||
showModal: showFileRenameModal,
|
||||
} = useSetModalState();
|
||||
|
||||
const handleShowTagRenameModal = useCallback(
|
||||
(record: string) => {
|
||||
setTag(record);
|
||||
showFileRenameModal();
|
||||
},
|
||||
[showFileRenameModal],
|
||||
);
|
||||
|
||||
return {
|
||||
initialName: tag,
|
||||
tagRenameVisible,
|
||||
hideTagRenameModal,
|
||||
showTagRenameModal: handleShowTagRenameModal,
|
||||
};
|
||||
};
|
||||
88
web/src/pages/dataset/dataset-setting/index.tsx
Normal file
88
web/src/pages/dataset/dataset-setting/index.tsx
Normal file
@ -0,0 +1,88 @@
|
||||
import { Form } from '@/components/ui/form';
|
||||
import { DocumentParserType } from '@/constants/knowledge';
|
||||
import { PermissionRole } from '@/constants/permission';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { z } from 'zod';
|
||||
import { TopTitle } from '../dataset-title';
|
||||
import { ChunkMethodForm } from './chunk-method-form';
|
||||
import { formSchema } from './form-schema';
|
||||
import { GeneralForm } from './general-form';
|
||||
import { useFetchKnowledgeConfigurationOnMount } from './hooks';
|
||||
|
||||
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() {
|
||||
const { t } = useTranslation();
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
name: '',
|
||||
parser_id: DocumentParserType.Naive,
|
||||
permission: PermissionRole.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,
|
||||
},
|
||||
graphrag: {
|
||||
use_graphrag: false,
|
||||
entity_types: initialEntityTypes,
|
||||
method: MethodValue.Light,
|
||||
},
|
||||
},
|
||||
pagerank: 0,
|
||||
},
|
||||
});
|
||||
|
||||
useFetchKnowledgeConfigurationOnMount(form);
|
||||
|
||||
async function onSubmit(data: z.infer<typeof formSchema>) {
|
||||
console.log('🚀 ~ DatasetSettings ~ data:', data);
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="p-5 h-full flex flex-col">
|
||||
<TopTitle
|
||||
title={t('knowledgeDetails.configuration')}
|
||||
description={t('knowledgeConfiguration.titleDescription')}
|
||||
></TopTitle>
|
||||
<div className="flex gap-14 flex-1 min-h-0">
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="space-y-6 flex-1"
|
||||
>
|
||||
<div className="w-[768px]">
|
||||
<GeneralForm></GeneralForm>
|
||||
<ChunkMethodForm></ChunkMethodForm>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
33
web/src/pages/dataset/dataset-setting/naive.tsx
Normal file
33
web/src/pages/dataset/dataset-setting/naive.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import GraphRagItems from '@/components/parse-configuration/graph-rag-form-fields';
|
||||
import RaptorFormFields from '@/components/parse-configuration/raptor-form-fields';
|
||||
import {
|
||||
ConfigurationFormContainer,
|
||||
MainContainer,
|
||||
} from './configuration-form-container';
|
||||
import { EnableAutoGenerateItem } from './configuration/common-item';
|
||||
|
||||
export function NaiveConfiguration() {
|
||||
return (
|
||||
<MainContainer>
|
||||
<GraphRagItems className="border-none p-0"></GraphRagItems>
|
||||
<ConfigurationFormContainer>
|
||||
<RaptorFormFields></RaptorFormFields>
|
||||
</ConfigurationFormContainer>
|
||||
<EnableAutoGenerateItem />
|
||||
{/* <ConfigurationFormContainer>
|
||||
<ChunkMethodItem></ChunkMethodItem>
|
||||
<LayoutRecognizeFormField></LayoutRecognizeFormField>
|
||||
|
||||
<MaxTokenNumberFormField initialValue={512}></MaxTokenNumberFormField>
|
||||
<DelimiterFormField></DelimiterFormField>
|
||||
</ConfigurationFormContainer>
|
||||
<ConfigurationFormContainer>
|
||||
<PageRankFormField></PageRankFormField>
|
||||
<AutoKeywordsFormField></AutoKeywordsFormField>
|
||||
<AutoQuestionsFormField></AutoQuestionsFormField>
|
||||
<ExcelToHtmlFormField></ExcelToHtmlFormField>
|
||||
<TagItems></TagItems>
|
||||
</ConfigurationFormContainer> */}
|
||||
</MainContainer>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
import { SelectWithSearch } from '@/components/originui/select-with-search';
|
||||
import { RAGFlowFormItem } from '@/components/ragflow-form';
|
||||
import { PermissionRole } from '@/constants/permission';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export function PermissionFormField() {
|
||||
const { t } = useTranslation();
|
||||
const teamOptions = useMemo(() => {
|
||||
return Object.values(PermissionRole).map((x) => ({
|
||||
label: t('knowledgeConfiguration.' + x),
|
||||
value: x,
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<RAGFlowFormItem
|
||||
name="permission"
|
||||
label={t('knowledgeConfiguration.permissions')}
|
||||
tooltip={t('knowledgeConfiguration.permissionsTip')}
|
||||
horizontal
|
||||
>
|
||||
<SelectWithSearch
|
||||
options={teamOptions}
|
||||
triggerClassName="w-3/4"
|
||||
></SelectWithSearch>
|
||||
</RAGFlowFormItem>
|
||||
);
|
||||
}
|
||||
82
web/src/pages/dataset/dataset-setting/saving-button.tsx
Normal file
82
web/src/pages/dataset/dataset-setting/saving-button.tsx
Normal file
@ -0,0 +1,82 @@
|
||||
import { ButtonLoading } from '@/components/ui/button';
|
||||
import { useUpdateKnowledge } from '@/hooks/use-knowledge-request';
|
||||
import { useMemo } from 'react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useParams } from 'umi';
|
||||
|
||||
export function GeneralSavingButton() {
|
||||
const form = useFormContext();
|
||||
const { saveKnowledgeConfiguration, loading: submitLoading } =
|
||||
useUpdateKnowledge();
|
||||
const { id: kb_id } = useParams();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => form.formState.defaultValues ?? {},
|
||||
[form.formState.defaultValues],
|
||||
);
|
||||
const parser_id = defaultValues['parser_id'];
|
||||
|
||||
return (
|
||||
<ButtonLoading
|
||||
type="button"
|
||||
loading={submitLoading}
|
||||
onClick={() => {
|
||||
(async () => {
|
||||
let isValidate = await form.trigger('name');
|
||||
const { name, description, permission, avatar } = form.getValues();
|
||||
|
||||
if (isValidate) {
|
||||
saveKnowledgeConfiguration({
|
||||
kb_id,
|
||||
parser_id,
|
||||
name,
|
||||
description,
|
||||
avatar,
|
||||
permission,
|
||||
});
|
||||
}
|
||||
})();
|
||||
}}
|
||||
>
|
||||
{t('knowledgeConfiguration.save')}
|
||||
</ButtonLoading>
|
||||
);
|
||||
}
|
||||
|
||||
export function SavingButton() {
|
||||
const { saveKnowledgeConfiguration, loading: submitLoading } =
|
||||
useUpdateKnowledge();
|
||||
const form = useFormContext();
|
||||
const { id: kb_id } = useParams();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<ButtonLoading
|
||||
loading={submitLoading}
|
||||
onClick={() => {
|
||||
(async () => {
|
||||
try {
|
||||
let beValid = await form.formControl.trigger();
|
||||
if (beValid) {
|
||||
form.handleSubmit(async (values) => {
|
||||
console.log('saveKnowledgeConfiguration: ', values);
|
||||
delete values['avatar'];
|
||||
await saveKnowledgeConfiguration({
|
||||
kb_id,
|
||||
...values,
|
||||
});
|
||||
})();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
} finally {
|
||||
}
|
||||
})();
|
||||
}}
|
||||
>
|
||||
{t('knowledgeConfiguration.save')}
|
||||
</ButtonLoading>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user