mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Display the document configuration dialog with shadcn #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
30
web/src/components/auto-keywords-form-field.tsx
Normal file
30
web/src/components/auto-keywords-form-field.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
|
import { SliderInputFormField } from './slider-input-form-field';
|
||||||
|
|
||||||
|
export function AutoKeywordsFormField() {
|
||||||
|
const { t } = useTranslate('knowledgeDetails');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SliderInputFormField
|
||||||
|
name={'parser_config.auto_keywords'}
|
||||||
|
label={t('autoKeywords')}
|
||||||
|
max={30}
|
||||||
|
min={0}
|
||||||
|
tooltip={t('autoKeywordsTip')}
|
||||||
|
></SliderInputFormField>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AutoQuestionsFormField() {
|
||||||
|
const { t } = useTranslate('knowledgeDetails');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SliderInputFormField
|
||||||
|
name={'parser_config.auto_questions'}
|
||||||
|
label={t('autoQuestions')}
|
||||||
|
max={10}
|
||||||
|
min={0}
|
||||||
|
tooltip={t('autoQuestionsTip')}
|
||||||
|
></SliderInputFormField>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -14,21 +14,42 @@ import {
|
|||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage,
|
||||||
} from '@/components/ui/form';
|
} from '@/components/ui/form';
|
||||||
|
import { DocumentParserType } from '@/constants/knowledge';
|
||||||
import { useTranslate } from '@/hooks/common-hooks';
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
|
import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request';
|
||||||
import { IModalProps } from '@/interfaces/common';
|
import { IModalProps } from '@/interfaces/common';
|
||||||
import { IParserConfig } from '@/interfaces/database/document';
|
import { IParserConfig } from '@/interfaces/database/document';
|
||||||
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { useForm } from 'react-hook-form';
|
import {} from 'module';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useForm, useWatch } from 'react-hook-form';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import {
|
import {
|
||||||
Select,
|
AutoKeywordsFormField,
|
||||||
SelectContent,
|
AutoQuestionsFormField,
|
||||||
SelectItem,
|
} from '../auto-keywords-form-field';
|
||||||
SelectTrigger,
|
import { DatasetConfigurationContainer } from '../dataset-configuration-container';
|
||||||
SelectValue,
|
import { DelimiterFormField } from '../delimiter-form-field';
|
||||||
} from '../ui/select';
|
import { EntityTypesFormField } from '../entity-types-form-field';
|
||||||
import { useFetchParserListOnMount } from './hooks';
|
import { ExcelToHtmlFormField } from '../excel-to-html-form-field';
|
||||||
|
import {
|
||||||
|
DocumentType,
|
||||||
|
LayoutRecognizeFormField,
|
||||||
|
} from '../layout-recognize-form-field';
|
||||||
|
import { MaxTokenNumberFormField } from '../max-token-number-from-field';
|
||||||
|
import {
|
||||||
|
UseGraphRagFormField,
|
||||||
|
showGraphRagItems,
|
||||||
|
} from '../parse-configuration/graph-rag-form-fields';
|
||||||
|
import RaptorFormFields, {
|
||||||
|
showRaptorParseConfiguration,
|
||||||
|
} from '../parse-configuration/raptor-form-fields';
|
||||||
|
import { Input } from '../ui/input';
|
||||||
|
import { RAGFlowSelect } from '../ui/select';
|
||||||
|
import { useFetchParserListOnMount, useShowAutoKeywords } from './hooks';
|
||||||
|
|
||||||
|
const FormId = 'ChunkMethodDialogForm';
|
||||||
|
|
||||||
interface IProps
|
interface IProps
|
||||||
extends IModalProps<{
|
extends IModalProps<{
|
||||||
@ -42,6 +63,15 @@ interface IProps
|
|||||||
documentId: string;
|
documentId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hidePagesChunkMethods = [
|
||||||
|
DocumentParserType.Qa,
|
||||||
|
DocumentParserType.Table,
|
||||||
|
DocumentParserType.Picture,
|
||||||
|
DocumentParserType.Resume,
|
||||||
|
DocumentParserType.One,
|
||||||
|
DocumentParserType.KnowledgeGraph,
|
||||||
|
];
|
||||||
|
|
||||||
export function ChunkMethodDialog({
|
export function ChunkMethodDialog({
|
||||||
hideModal,
|
hideModal,
|
||||||
onOk,
|
onOk,
|
||||||
@ -58,68 +88,171 @@ export function ChunkMethodDialog({
|
|||||||
// form,
|
// form,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { data: knowledgeDetails } = useFetchKnowledgeBaseConfiguration();
|
||||||
|
|
||||||
|
const useGraphRag = useMemo(() => {
|
||||||
|
return knowledgeDetails.parser_config?.graphrag?.use_graphrag;
|
||||||
|
}, [knowledgeDetails.parser_config?.graphrag?.use_graphrag]);
|
||||||
|
|
||||||
const FormSchema = z.object({
|
const FormSchema = z.object({
|
||||||
name: z
|
parser_id: z
|
||||||
.string()
|
.string()
|
||||||
.min(1, {
|
.min(1, {
|
||||||
message: 'namePlaceholder',
|
message: 'namePlaceholder',
|
||||||
})
|
})
|
||||||
.trim(),
|
.trim(),
|
||||||
|
parser_config: z.object({
|
||||||
|
task_page_size: z.coerce.number(),
|
||||||
|
layout_recognize: z.string(),
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
const form = useForm<z.infer<typeof FormSchema>>({
|
const form = useForm<z.infer<typeof FormSchema>>({
|
||||||
resolver: zodResolver(FormSchema),
|
resolver: zodResolver(FormSchema),
|
||||||
defaultValues: { name: '' },
|
defaultValues: {
|
||||||
|
parser_id: parserId,
|
||||||
|
parser_config: {
|
||||||
|
task_page_size: 12,
|
||||||
|
layout_recognize: DocumentType.DeepDOC,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const layoutRecognize = useWatch({
|
||||||
|
name: 'parser_config.layout_recognize',
|
||||||
|
control: form.control,
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedTag = useWatch({
|
||||||
|
name: 'parser_id',
|
||||||
|
control: form.control,
|
||||||
|
});
|
||||||
|
|
||||||
|
const isPdf = documentExtension === 'pdf';
|
||||||
|
|
||||||
|
const showPages = useMemo(() => {
|
||||||
|
return isPdf && hidePagesChunkMethods.every((x) => x !== selectedTag);
|
||||||
|
}, [selectedTag, isPdf]);
|
||||||
|
|
||||||
|
const showOne = useMemo(() => {
|
||||||
|
return (
|
||||||
|
isPdf &&
|
||||||
|
hidePagesChunkMethods
|
||||||
|
.filter((x) => x !== DocumentParserType.One)
|
||||||
|
.every((x) => x !== selectedTag)
|
||||||
|
);
|
||||||
|
}, [selectedTag, isPdf]);
|
||||||
|
|
||||||
|
const showMaxTokenNumber =
|
||||||
|
selectedTag === DocumentParserType.Naive ||
|
||||||
|
selectedTag === DocumentParserType.KnowledgeGraph;
|
||||||
|
|
||||||
|
const showEntityTypes = selectedTag === DocumentParserType.KnowledgeGraph;
|
||||||
|
|
||||||
|
const showExcelToHtml =
|
||||||
|
selectedTag === DocumentParserType.Naive && documentExtension === 'xlsx';
|
||||||
|
|
||||||
|
const showAutoKeywords = useShowAutoKeywords();
|
||||||
|
|
||||||
async function onSubmit(data: z.infer<typeof FormSchema>) {
|
async function onSubmit(data: z.infer<typeof FormSchema>) {
|
||||||
const ret = await onOk?.();
|
console.log('🚀 ~ onSubmit ~ data:', data);
|
||||||
if (ret) {
|
// const ret = await onOk?.();
|
||||||
hideModal?.();
|
// if (ret) {
|
||||||
}
|
// hideModal?.();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open onOpenChange={hideModal}>
|
<Dialog open onOpenChange={hideModal}>
|
||||||
<DialogContent>
|
<DialogContent className="max-w-[50vw]">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{t('chunkMethod')}</DialogTitle>
|
<DialogTitle>{t('chunkMethod')}</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
<form
|
||||||
|
onSubmit={form.handleSubmit(onSubmit)}
|
||||||
|
className="space-y-6"
|
||||||
|
id={FormId}
|
||||||
|
>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="name"
|
name="parser_id"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('name')}</FormLabel>
|
<FormLabel>{t('name')}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Select
|
<RAGFlowSelect
|
||||||
{...field}
|
{...field}
|
||||||
autoComplete="off"
|
options={parserList}
|
||||||
onValueChange={field.onChange}
|
></RAGFlowSelect>
|
||||||
>
|
|
||||||
<FormControl>
|
|
||||||
<SelectTrigger>
|
|
||||||
<SelectValue placeholder="Select a verified email to display" />
|
|
||||||
</SelectTrigger>
|
|
||||||
</FormControl>
|
|
||||||
<SelectContent>
|
|
||||||
{parserList.map((x) => (
|
|
||||||
<SelectItem value={x.value} key={x.value}>
|
|
||||||
{x.label}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
{showPages && layoutRecognize && (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="parser_config.task_page_size"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel tooltip={t('taskPageSizeTip')}>
|
||||||
|
{t('taskPageSize')}
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
{...field}
|
||||||
|
type={'number'}
|
||||||
|
min={1}
|
||||||
|
max={128}
|
||||||
|
></Input>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<DatasetConfigurationContainer show={showOne || showMaxTokenNumber}>
|
||||||
|
{showOne && <LayoutRecognizeFormField></LayoutRecognizeFormField>}
|
||||||
|
{showMaxTokenNumber && (
|
||||||
|
<>
|
||||||
|
<MaxTokenNumberFormField
|
||||||
|
max={
|
||||||
|
selectedTag === DocumentParserType.KnowledgeGraph
|
||||||
|
? 8192 * 2
|
||||||
|
: 2048
|
||||||
|
}
|
||||||
|
></MaxTokenNumberFormField>
|
||||||
|
<DelimiterFormField></DelimiterFormField>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</DatasetConfigurationContainer>
|
||||||
|
<DatasetConfigurationContainer
|
||||||
|
show={showAutoKeywords(selectedTag) || showExcelToHtml}
|
||||||
|
>
|
||||||
|
{showAutoKeywords(selectedTag) && (
|
||||||
|
<>
|
||||||
|
<AutoKeywordsFormField></AutoKeywordsFormField>
|
||||||
|
<AutoQuestionsFormField></AutoQuestionsFormField>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{showExcelToHtml && <ExcelToHtmlFormField></ExcelToHtmlFormField>}
|
||||||
|
</DatasetConfigurationContainer>
|
||||||
|
{showRaptorParseConfiguration(
|
||||||
|
selectedTag as DocumentParserType,
|
||||||
|
) && (
|
||||||
|
<DatasetConfigurationContainer>
|
||||||
|
<RaptorFormFields></RaptorFormFields>
|
||||||
|
</DatasetConfigurationContainer>
|
||||||
|
)}
|
||||||
|
{showGraphRagItems(selectedTag as DocumentParserType) &&
|
||||||
|
useGraphRag && <UseGraphRagFormField></UseGraphRagFormField>}
|
||||||
|
{showEntityTypes && <EntityTypesFormField></EntityTypesFormField>}
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button type="submit">Save changes</Button>
|
<Button type="submit" form={FormId}>
|
||||||
|
Save changes
|
||||||
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
59
web/src/components/delimiter-form-field.tsx
Normal file
59
web/src/components/delimiter-form-field.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { forwardRef } from 'react';
|
||||||
|
import { useFormContext } from 'react-hook-form';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from './ui/form';
|
||||||
|
import { Input, InputProps } from './ui/input';
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
value?: string | undefined;
|
||||||
|
onChange?: (val: string | undefined) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DelimiterInput = forwardRef<HTMLInputElement, InputProps & IProps>(
|
||||||
|
({ value, onChange, maxLength, defaultValue }, ref) => {
|
||||||
|
const nextValue = value?.replaceAll('\n', '\\n');
|
||||||
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const val = e.target.value;
|
||||||
|
const nextValue = val.replaceAll('\\n', '\n');
|
||||||
|
onChange?.(nextValue);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
value={nextValue}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
maxLength={maxLength}
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
ref={ref}
|
||||||
|
></Input>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export function DelimiterFormField() {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const form = useFormContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={'parser_config.delimiter'}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel tooltip={t('knowledgeDetails.delimiterTip')}>
|
||||||
|
{t('knowledgeDetails.delimiter')}
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl defaultValue={`\n`}>
|
||||||
|
<DelimiterInput {...field}></DelimiterInput>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
37
web/src/components/entity-types-form-field.tsx
Normal file
37
web/src/components/entity-types-form-field.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
|
import { useFormContext } from 'react-hook-form';
|
||||||
|
import EditTag from './edit-tag';
|
||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from './ui/form';
|
||||||
|
|
||||||
|
type EntityTypesFormFieldProps = {
|
||||||
|
name?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function EntityTypesFormField({
|
||||||
|
name = 'parser_config.entity_types',
|
||||||
|
}: EntityTypesFormFieldProps) {
|
||||||
|
const { t } = useTranslate('knowledgeConfiguration');
|
||||||
|
const form = useFormContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={name}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>{t('entityTypes')}</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<EditTag {...field}></EditTag>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
34
web/src/components/excel-to-html-form-field.tsx
Normal file
34
web/src/components/excel-to-html-form-field.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
|
import { useFormContext } from 'react-hook-form';
|
||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from './ui/form';
|
||||||
|
import { Switch } from './ui/switch';
|
||||||
|
|
||||||
|
export function ExcelToHtmlFormField() {
|
||||||
|
const form = useFormContext();
|
||||||
|
const { t } = useTranslate('knowledgeDetails');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="parser_config.html4excel"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem defaultChecked={false}>
|
||||||
|
<FormLabel tooltip={t('html4excelTip')}>{t('html4excel')}</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Switch
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
></Switch>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
70
web/src/components/layout-recognize-form-field.tsx
Normal file
70
web/src/components/layout-recognize-form-field.tsx
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { LlmModelType } from '@/constants/knowledge';
|
||||||
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
|
import { useSelectLlmOptionsByModelType } from '@/hooks/llm-hooks';
|
||||||
|
import { camelCase } from 'lodash';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useFormContext } from 'react-hook-form';
|
||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from './ui/form';
|
||||||
|
import { RAGFlowSelect } from './ui/select';
|
||||||
|
|
||||||
|
export const enum DocumentType {
|
||||||
|
DeepDOC = 'DeepDOC',
|
||||||
|
PlainText = 'Plain Text',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LayoutRecognizeFormField() {
|
||||||
|
const form = useFormContext();
|
||||||
|
|
||||||
|
const { t } = useTranslate('knowledgeDetails');
|
||||||
|
const allOptions = useSelectLlmOptionsByModelType();
|
||||||
|
|
||||||
|
const options = useMemo(() => {
|
||||||
|
const list = [DocumentType.DeepDOC, DocumentType.PlainText].map((x) => ({
|
||||||
|
label: x === DocumentType.PlainText ? t(camelCase(x)) : 'DeepDoc',
|
||||||
|
value: x,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const image2TextList = allOptions[LlmModelType.Image2text].map((x) => {
|
||||||
|
return {
|
||||||
|
...x,
|
||||||
|
options: x.options.map((y) => {
|
||||||
|
return {
|
||||||
|
...y,
|
||||||
|
label: (
|
||||||
|
<div className="flex justify-between items-center gap-2">
|
||||||
|
{y.label}
|
||||||
|
<span className="text-red-500 text-sm">Experimental</span>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return [...list, ...image2TextList];
|
||||||
|
}, [allOptions, t]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="parser_config.layout_recognize"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel tooltip={t('layoutRecognizeTip')}>
|
||||||
|
{t('layoutRecognize')}
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<RAGFlowSelect {...field} options={options}></RAGFlowSelect>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
19
web/src/components/max-token-number-from-field.tsx
Normal file
19
web/src/components/max-token-number-from-field.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
|
import { SliderInputFormField } from './slider-input-form-field';
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
initialValue?: number;
|
||||||
|
max?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MaxTokenNumberFormField({ max = 2048 }: IProps) {
|
||||||
|
const { t } = useTranslate('knowledgeConfiguration');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SliderInputFormField
|
||||||
|
name={'parser_config.chunk_token_num'}
|
||||||
|
label={t('chunkTokenNumber')}
|
||||||
|
max={max}
|
||||||
|
></SliderInputFormField>
|
||||||
|
);
|
||||||
|
}
|
||||||
173
web/src/components/parse-configuration/graph-rag-form-fields.tsx
Normal file
173
web/src/components/parse-configuration/graph-rag-form-fields.tsx
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
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 {
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from '../ui/form';
|
||||||
|
import { Switch } from '../ui/switch';
|
||||||
|
|
||||||
|
const excludedTagParseMethods = [
|
||||||
|
DocumentParserType.Table,
|
||||||
|
DocumentParserType.KnowledgeGraph,
|
||||||
|
DocumentParserType.Tag,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const showTagItems = (parserId: DocumentParserType) => {
|
||||||
|
return !excludedTagParseMethods.includes(parserId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const enum MethodValue {
|
||||||
|
General = 'general',
|
||||||
|
Light = 'light',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const excludedParseMethods = [
|
||||||
|
DocumentParserType.Table,
|
||||||
|
DocumentParserType.Resume,
|
||||||
|
DocumentParserType.Picture,
|
||||||
|
DocumentParserType.KnowledgeGraph,
|
||||||
|
DocumentParserType.Qa,
|
||||||
|
DocumentParserType.Tag,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const showGraphRagItems = (parserId: DocumentParserType | undefined) => {
|
||||||
|
return !excludedParseMethods.some((x) => x === parserId);
|
||||||
|
};
|
||||||
|
|
||||||
|
type GraphRagItemsProps = {
|
||||||
|
marginBottom?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function UseGraphRagItem() {
|
||||||
|
const { t } = useTranslate('knowledgeConfiguration');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
name={['parser_config', 'graphrag', 'use_graphrag']}
|
||||||
|
label={t('useGraphRag')}
|
||||||
|
initialValue={false}
|
||||||
|
valuePropName="checked"
|
||||||
|
tooltip={t('useGraphRagTip')}
|
||||||
|
>
|
||||||
|
<AntSwitch />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UseGraphRagFormField() {
|
||||||
|
const form = useFormContext();
|
||||||
|
const { t } = useTranslate('knowledgeConfiguration');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="parser_config.graphrag.use_graphrag"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem defaultChecked={false}>
|
||||||
|
<FormLabel tooltip={t('useGraphRagTip')}>
|
||||||
|
{t('useGraphRag')}
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Switch
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
></Switch>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The three types "table", "resume" and "one" do not display this configuration.
|
||||||
|
const GraphRagItems = ({ marginBottom = false }: GraphRagItemsProps) => {
|
||||||
|
const { t } = useTranslate('knowledgeConfiguration');
|
||||||
|
|
||||||
|
const methodOptions = useMemo(() => {
|
||||||
|
return [MethodValue.Light, MethodValue.General].map((x) => ({
|
||||||
|
value: x,
|
||||||
|
label: upperFirst(x),
|
||||||
|
}));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const renderWideTooltip = useCallback(
|
||||||
|
(title: React.ReactNode | string) => {
|
||||||
|
return {
|
||||||
|
title: typeof title === 'string' ? t(title) : title,
|
||||||
|
overlayInnerStyle: { width: '32vw' },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[t],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DatasetConfigurationContainer className={cn({ 'mb-4': marginBottom })}>
|
||||||
|
<UseGraphRagItem></UseGraphRagItem>
|
||||||
|
<Form.Item
|
||||||
|
shouldUpdate={(prevValues, curValues) =>
|
||||||
|
prevValues.parser_config.graphrag.use_graphrag !==
|
||||||
|
curValues.parser_config.graphrag.use_graphrag
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{({ getFieldValue }) => {
|
||||||
|
const useRaptor = getFieldValue([
|
||||||
|
'parser_config',
|
||||||
|
'graphrag',
|
||||||
|
'use_graphrag',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
useRaptor && (
|
||||||
|
<>
|
||||||
|
<EntityTypesItem
|
||||||
|
field={['parser_config', 'graphrag', 'entity_types']}
|
||||||
|
></EntityTypesItem>
|
||||||
|
<Form.Item
|
||||||
|
name={['parser_config', 'graphrag', 'method']}
|
||||||
|
label={t('graphRagMethod')}
|
||||||
|
tooltip={renderWideTooltip(
|
||||||
|
<div
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: t('graphRagMethodTip'),
|
||||||
|
}}
|
||||||
|
></div>,
|
||||||
|
)}
|
||||||
|
initialValue={MethodValue.Light}
|
||||||
|
>
|
||||||
|
<Select options={methodOptions} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name={['parser_config', 'graphrag', 'resolution']}
|
||||||
|
label={t('resolution')}
|
||||||
|
tooltip={renderWideTooltip('resolutionTip')}
|
||||||
|
>
|
||||||
|
<AntSwitch />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name={['parser_config', 'graphrag', 'community']}
|
||||||
|
label={t('community')}
|
||||||
|
tooltip={renderWideTooltip('communityTip')}
|
||||||
|
>
|
||||||
|
<AntSwitch />
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
</DatasetConfigurationContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GraphRagItems;
|
||||||
142
web/src/components/parse-configuration/raptor-form-fields.tsx
Normal file
142
web/src/components/parse-configuration/raptor-form-fields.tsx
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
import { DocumentParserType } from '@/constants/knowledge';
|
||||||
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
|
import random from 'lodash/random';
|
||||||
|
import { Plus } from 'lucide-react';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useFormContext, useWatch } from 'react-hook-form';
|
||||||
|
import { SliderInputFormField } from '../slider-input-form-field';
|
||||||
|
import { Button } from '../ui/button';
|
||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from '../ui/form';
|
||||||
|
import { Input } from '../ui/input';
|
||||||
|
import { Switch } from '../ui/switch';
|
||||||
|
import { Textarea } from '../ui/textarea';
|
||||||
|
|
||||||
|
export const excludedParseMethods = [
|
||||||
|
DocumentParserType.Table,
|
||||||
|
DocumentParserType.Resume,
|
||||||
|
DocumentParserType.One,
|
||||||
|
DocumentParserType.Picture,
|
||||||
|
DocumentParserType.KnowledgeGraph,
|
||||||
|
DocumentParserType.Qa,
|
||||||
|
DocumentParserType.Tag,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const showRaptorParseConfiguration = (
|
||||||
|
parserId: DocumentParserType | undefined,
|
||||||
|
) => {
|
||||||
|
return !excludedParseMethods.some((x) => x === parserId);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const excludedTagParseMethods = [
|
||||||
|
DocumentParserType.Table,
|
||||||
|
DocumentParserType.KnowledgeGraph,
|
||||||
|
DocumentParserType.Tag,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const showTagItems = (parserId: DocumentParserType) => {
|
||||||
|
return !excludedTagParseMethods.includes(parserId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const UseRaptorField = 'parser_config.raptor.use_raptor';
|
||||||
|
const RandomSeedField = 'parser_config.raptor.random_seed';
|
||||||
|
|
||||||
|
// The three types "table", "resume" and "one" do not display this configuration.
|
||||||
|
|
||||||
|
const RaptorFormFields = () => {
|
||||||
|
const form = useFormContext();
|
||||||
|
const { t } = useTranslate('knowledgeConfiguration');
|
||||||
|
const useRaptor = useWatch({ name: UseRaptorField });
|
||||||
|
|
||||||
|
const handleGenerate = useCallback(() => {
|
||||||
|
form.setValue(RandomSeedField, random(10000));
|
||||||
|
}, [form]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={UseRaptorField}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem defaultChecked={false}>
|
||||||
|
<FormLabel tooltip={t('useRaptorTip')}>{t('useRaptor')}</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Switch
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
></Switch>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{useRaptor && (
|
||||||
|
<>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={'parser_config.raptor.prompt'}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel tooltip={t('promptTip')}>{t('prompt')}</FormLabel>
|
||||||
|
<FormControl defaultValue={t('promptText')}>
|
||||||
|
<Textarea {...field} rows={8} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<SliderInputFormField
|
||||||
|
name={'parser_config.raptor.max_token'}
|
||||||
|
label={t('maxToken')}
|
||||||
|
tooltip={t('maxTokenTip')}
|
||||||
|
defaultValue={256}
|
||||||
|
max={2048}
|
||||||
|
min={0}
|
||||||
|
></SliderInputFormField>
|
||||||
|
<SliderInputFormField
|
||||||
|
name={'parser_config.raptor.threshold'}
|
||||||
|
label={t('threshold')}
|
||||||
|
tooltip={t('thresholdTip')}
|
||||||
|
defaultValue={0.1}
|
||||||
|
step={0.01}
|
||||||
|
max={1}
|
||||||
|
min={0}
|
||||||
|
></SliderInputFormField>
|
||||||
|
<SliderInputFormField
|
||||||
|
name={'parser_config.raptor.max_cluster'}
|
||||||
|
label={t('maxCluster')}
|
||||||
|
tooltip={t('maxClusterTip')}
|
||||||
|
defaultValue={64}
|
||||||
|
max={1024}
|
||||||
|
min={1}
|
||||||
|
></SliderInputFormField>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={'parser_config.raptor.random_seed'}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>{t('randomSeed')}</FormLabel>
|
||||||
|
<FormControl defaultValue={0}>
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<Input {...field} />
|
||||||
|
<Button size={'sm'} onClick={handleGenerate}>
|
||||||
|
<Plus />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RaptorFormFields;
|
||||||
71
web/src/components/slider-input-form-field.tsx
Normal file
71
web/src/components/slider-input-form-field.tsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
import { useFormContext } from 'react-hook-form';
|
||||||
|
import { SingleFormSlider } from './ui/dual-range-slider';
|
||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from './ui/form';
|
||||||
|
import { Input } from './ui/input';
|
||||||
|
|
||||||
|
type SliderInputFormFieldProps = {
|
||||||
|
max?: number;
|
||||||
|
min?: number;
|
||||||
|
step?: number;
|
||||||
|
name: string;
|
||||||
|
label: string;
|
||||||
|
tooltip?: ReactNode;
|
||||||
|
defaultValue?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function SliderInputFormField({
|
||||||
|
max,
|
||||||
|
min,
|
||||||
|
step,
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
tooltip,
|
||||||
|
defaultValue,
|
||||||
|
}: SliderInputFormFieldProps) {
|
||||||
|
const form = useFormContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={name}
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<FormLabel tooltip={tooltip}>{label}</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
type={'number'}
|
||||||
|
className="h-7 w-20"
|
||||||
|
max={max}
|
||||||
|
min={min}
|
||||||
|
step={step}
|
||||||
|
{...field}
|
||||||
|
// defaultValue={defaultValue}
|
||||||
|
></Input>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
<FormControl>
|
||||||
|
<SingleFormSlider
|
||||||
|
{...field}
|
||||||
|
max={max}
|
||||||
|
min={min}
|
||||||
|
step={step}
|
||||||
|
// defaultValue={
|
||||||
|
// typeof defaultValue === 'number' ? [defaultValue] : undefined
|
||||||
|
// }
|
||||||
|
></SingleFormSlider>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -222,11 +222,12 @@ export const RAGFlowSelect = forwardRef<
|
|||||||
allowClear,
|
allowClear,
|
||||||
placeholder,
|
placeholder,
|
||||||
contentProps = {},
|
contentProps = {},
|
||||||
|
defaultValue,
|
||||||
},
|
},
|
||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
const [key, setKey] = React.useState(+new Date());
|
const [key, setKey] = React.useState(+new Date());
|
||||||
const [value, setValue] = React.useState<string | undefined>(undefined);
|
const [value, setValue] = React.useState<string | undefined>(defaultValue);
|
||||||
|
|
||||||
const FormControlWidget = FormControlComponent
|
const FormControlWidget = FormControlComponent
|
||||||
? FormControlComponent
|
? FormControlComponent
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { IDocumentInfo } from '@/interfaces/database/document';
|
import { IDocumentInfo } from '@/interfaces/database/document';
|
||||||
|
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
||||||
import i18n from '@/locales/config';
|
import i18n from '@/locales/config';
|
||||||
import kbService from '@/services/knowledge-service';
|
import kbService from '@/services/knowledge-service';
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
@ -20,6 +21,7 @@ export const enum DocumentApiAction {
|
|||||||
RunDocumentByIds = 'runDocumentByIds',
|
RunDocumentByIds = 'runDocumentByIds',
|
||||||
RemoveDocument = 'removeDocument',
|
RemoveDocument = 'removeDocument',
|
||||||
SaveDocumentName = 'saveDocumentName',
|
SaveDocumentName = 'saveDocumentName',
|
||||||
|
SetDocumentParser = 'setDocumentParser',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useUploadNextDocument = () => {
|
export const useUploadNextDocument = () => {
|
||||||
@ -247,3 +249,40 @@ export const useSaveDocumentName = () => {
|
|||||||
|
|
||||||
return { loading, saveName: mutateAsync, data };
|
return { loading, saveName: mutateAsync, data };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useSetDocumentParser = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isPending: loading,
|
||||||
|
mutateAsync,
|
||||||
|
} = useMutation({
|
||||||
|
mutationKey: [DocumentApiAction.SetDocumentParser],
|
||||||
|
mutationFn: async ({
|
||||||
|
parserId,
|
||||||
|
documentId,
|
||||||
|
parserConfig,
|
||||||
|
}: {
|
||||||
|
parserId: string;
|
||||||
|
documentId: string;
|
||||||
|
parserConfig: IChangeParserConfigRequestBody;
|
||||||
|
}) => {
|
||||||
|
const { data } = await kbService.document_change_parser({
|
||||||
|
parser_id: parserId,
|
||||||
|
doc_id: documentId,
|
||||||
|
parser_config: parserConfig,
|
||||||
|
});
|
||||||
|
if (data.code === 0) {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: [DocumentApiAction.FetchDocumentList],
|
||||||
|
});
|
||||||
|
|
||||||
|
message.success(i18n.t('message.modified'));
|
||||||
|
}
|
||||||
|
return data.code;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { setDocumentParser: mutateAsync, data, loading };
|
||||||
|
};
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
IKnowledge,
|
||||||
IKnowledgeResult,
|
IKnowledgeResult,
|
||||||
INextTestingResult,
|
INextTestingResult,
|
||||||
} from '@/interfaces/database/knowledge';
|
} from '@/interfaces/database/knowledge';
|
||||||
@ -22,6 +23,7 @@ export const enum KnowledgeApiAction {
|
|||||||
CreateKnowledge = 'createKnowledge',
|
CreateKnowledge = 'createKnowledge',
|
||||||
DeleteKnowledge = 'deleteKnowledge',
|
DeleteKnowledge = 'deleteKnowledge',
|
||||||
SaveKnowledge = 'saveKnowledge',
|
SaveKnowledge = 'saveKnowledge',
|
||||||
|
FetchKnowledgeDetail = 'fetchKnowledgeDetail',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useKnowledgeBaseId = () => {
|
export const useKnowledgeBaseId = () => {
|
||||||
@ -204,3 +206,21 @@ export const useUpdateKnowledge = (shouldFetchList = false) => {
|
|||||||
|
|
||||||
return { data, loading, saveKnowledgeConfiguration: mutateAsync };
|
return { data, loading, saveKnowledgeConfiguration: mutateAsync };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useFetchKnowledgeBaseConfiguration = () => {
|
||||||
|
const { id } = useParams();
|
||||||
|
|
||||||
|
const { data, isFetching: loading } = useQuery<IKnowledge>({
|
||||||
|
queryKey: [KnowledgeApiAction.FetchKnowledgeDetail],
|
||||||
|
initialData: {} as IKnowledge,
|
||||||
|
gcTime: 0,
|
||||||
|
queryFn: async () => {
|
||||||
|
const { data } = await kbService.get_kb_detail({
|
||||||
|
kb_id: id,
|
||||||
|
});
|
||||||
|
return data?.data ?? {};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading };
|
||||||
|
};
|
||||||
|
|||||||
@ -29,7 +29,7 @@ import { useFetchDocumentList } from '@/hooks/use-document-request';
|
|||||||
import { IDocumentInfo } from '@/interfaces/database/document';
|
import { IDocumentInfo } from '@/interfaces/database/document';
|
||||||
import { getExtension } from '@/utils/document-util';
|
import { getExtension } from '@/utils/document-util';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useChangeDocumentParser } from './hooks';
|
import { useChangeDocumentParser } from './use-change-document-parser';
|
||||||
import { useDatasetTableColumns } from './use-dataset-table-columns';
|
import { useDatasetTableColumns } from './use-dataset-table-columns';
|
||||||
import { useRenameDocument } from './use-rename-document';
|
import { useRenameDocument } from './use-rename-document';
|
||||||
|
|
||||||
@ -57,7 +57,8 @@ export function DatasetTable() {
|
|||||||
changeParserVisible,
|
changeParserVisible,
|
||||||
hideChangeParserModal,
|
hideChangeParserModal,
|
||||||
showChangeParserModal,
|
showChangeParserModal,
|
||||||
} = useChangeDocumentParser(currentRecord.id);
|
changeParserRecord,
|
||||||
|
} = useChangeDocumentParser();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
renameLoading,
|
renameLoading,
|
||||||
@ -198,10 +199,10 @@ export function DatasetTable() {
|
|||||||
</div>
|
</div>
|
||||||
{changeParserVisible && (
|
{changeParserVisible && (
|
||||||
<ChunkMethodDialog
|
<ChunkMethodDialog
|
||||||
documentId={currentRecord.id}
|
documentId={changeParserRecord.id}
|
||||||
parserId={currentRecord.parser_id}
|
parserId={changeParserRecord.parser_id}
|
||||||
parserConfig={currentRecord.parser_config}
|
parserConfig={changeParserRecord.parser_config}
|
||||||
documentExtension={getExtension(currentRecord.name)}
|
documentExtension={getExtension(changeParserRecord.name)}
|
||||||
onOk={onChangeParserOk}
|
onOk={onChangeParserOk}
|
||||||
visible={changeParserVisible}
|
visible={changeParserVisible}
|
||||||
hideModal={hideChangeParserModal}
|
hideModal={hideChangeParserModal}
|
||||||
|
|||||||
@ -1,11 +1,6 @@
|
|||||||
import { useSetModalState } from '@/hooks/common-hooks';
|
import { useSetModalState } from '@/hooks/common-hooks';
|
||||||
import {
|
import { useCreateNextDocument, useNextWebCrawl } from '@/hooks/document-hooks';
|
||||||
useCreateNextDocument,
|
|
||||||
useNextWebCrawl,
|
|
||||||
useSetNextDocumentParser,
|
|
||||||
} from '@/hooks/document-hooks';
|
|
||||||
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
import { useGetKnowledgeSearchParams } from '@/hooks/route-hook';
|
||||||
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { useNavigate } from 'umi';
|
import { useNavigate } from 'umi';
|
||||||
|
|
||||||
@ -50,44 +45,6 @@ export const useCreateEmptyDocument = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useChangeDocumentParser = (documentId: string) => {
|
|
||||||
const { setDocumentParser, loading } = useSetNextDocumentParser();
|
|
||||||
|
|
||||||
const {
|
|
||||||
visible: changeParserVisible,
|
|
||||||
hideModal: hideChangeParserModal,
|
|
||||||
showModal: showChangeParserModal,
|
|
||||||
} = useSetModalState();
|
|
||||||
|
|
||||||
const onChangeParserOk = useCallback(
|
|
||||||
async ({
|
|
||||||
parserId,
|
|
||||||
parserConfig,
|
|
||||||
}: {
|
|
||||||
parserId: string;
|
|
||||||
parserConfig: IChangeParserConfigRequestBody;
|
|
||||||
}) => {
|
|
||||||
const ret = await setDocumentParser({
|
|
||||||
parserId,
|
|
||||||
documentId,
|
|
||||||
parserConfig,
|
|
||||||
});
|
|
||||||
if (ret === 0) {
|
|
||||||
hideChangeParserModal();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[hideChangeParserModal, setDocumentParser, documentId],
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
changeParserLoading: loading,
|
|
||||||
onChangeParserOk,
|
|
||||||
changeParserVisible,
|
|
||||||
hideChangeParserModal,
|
|
||||||
showChangeParserModal,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useGetRowSelection = () => {
|
export const useGetRowSelection = () => {
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,20 @@
|
|||||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
HoverCard,
|
||||||
|
HoverCardContent,
|
||||||
|
HoverCardTrigger,
|
||||||
|
} from '@/components/ui/hover-card';
|
||||||
import { Progress } from '@/components/ui/progress';
|
import { Progress } from '@/components/ui/progress';
|
||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
import { IDocumentInfo } from '@/interfaces/database/document';
|
import { IDocumentInfo } from '@/interfaces/database/document';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
import { CircleX, Play, RefreshCw } from 'lucide-react';
|
import { CircleX, Play, RefreshCw } from 'lucide-react';
|
||||||
|
import { PropsWithChildren, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { RunningStatus } from './constant';
|
import { RunningStatus } from './constant';
|
||||||
import { ParsingCard } from './parsing-card';
|
import { ParsingCard } from './parsing-card';
|
||||||
|
import { UseChangeDocumentParserShowType } from './use-change-document-parser';
|
||||||
import { useHandleRunDocumentByIds } from './use-run-document';
|
import { useHandleRunDocumentByIds } from './use-run-document';
|
||||||
import { isParserRunning } from './utils';
|
import { isParserRunning } from './utils';
|
||||||
|
|
||||||
@ -18,7 +26,26 @@ const IconMap = {
|
|||||||
[RunningStatus.FAIL]: <RefreshCw />,
|
[RunningStatus.FAIL]: <RefreshCw />,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ParsingStatusCell({ record }: { record: IDocumentInfo }) {
|
function MenuItem({
|
||||||
|
children,
|
||||||
|
onClick,
|
||||||
|
}: PropsWithChildren & { onClick?(): void }) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={onClick}
|
||||||
|
className={cn(
|
||||||
|
'relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ParsingStatusCell({
|
||||||
|
record,
|
||||||
|
showChangeParserModal,
|
||||||
|
}: { record: IDocumentInfo } & UseChangeDocumentParserShowType) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { run, parser_id, progress, chunk_num, id } = record;
|
const { run, parser_id, progress, chunk_num, id } = record;
|
||||||
const operationIcon = IconMap[run];
|
const operationIcon = IconMap[run];
|
||||||
@ -33,12 +60,27 @@ export function ParsingStatusCell({ record }: { record: IDocumentInfo }) {
|
|||||||
handleRunDocumentByIds(record.id, isRunning, shouldDelete);
|
handleRunDocumentByIds(record.id, isRunning, shouldDelete);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleShowChangeParserModal = useCallback(() => {
|
||||||
|
showChangeParserModal(record);
|
||||||
|
}, [record, showChangeParserModal]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="flex gap-2 items-center ">
|
<section className="flex gap-2 items-center ">
|
||||||
<div>
|
<div>
|
||||||
<Button variant={'ghost'} size={'sm'}>
|
<HoverCard>
|
||||||
{parser_id}
|
<HoverCardTrigger>
|
||||||
</Button>
|
<Button variant={'ghost'} size={'sm'}>
|
||||||
|
{parser_id}
|
||||||
|
</Button>
|
||||||
|
</HoverCardTrigger>
|
||||||
|
<HoverCardContent>
|
||||||
|
<MenuItem onClick={handleShowChangeParserModal}>
|
||||||
|
{t('knowledgeDetails.chunkMethod')}
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem>{t('knowledgeDetails.setMetaData')}</MenuItem>
|
||||||
|
</HoverCardContent>
|
||||||
|
</HoverCard>
|
||||||
|
|
||||||
<Separator orientation="vertical" />
|
<Separator orientation="vertical" />
|
||||||
</div>
|
</div>
|
||||||
<ConfirmDeleteDialog
|
<ConfirmDeleteDialog
|
||||||
|
|||||||
54
web/src/pages/dataset/dataset/use-change-document-parser.ts
Normal file
54
web/src/pages/dataset/dataset/use-change-document-parser.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { useSetModalState } from '@/hooks/common-hooks';
|
||||||
|
import { useSetDocumentParser } from '@/hooks/use-document-request';
|
||||||
|
import { IDocumentInfo } from '@/interfaces/database/document';
|
||||||
|
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
export const useChangeDocumentParser = () => {
|
||||||
|
const { setDocumentParser, loading } = useSetDocumentParser();
|
||||||
|
const [record, setRecord] = useState<IDocumentInfo>({} as IDocumentInfo);
|
||||||
|
|
||||||
|
const {
|
||||||
|
visible: changeParserVisible,
|
||||||
|
hideModal: hideChangeParserModal,
|
||||||
|
showModal: showChangeParserModal,
|
||||||
|
} = useSetModalState();
|
||||||
|
|
||||||
|
const onChangeParserOk = useCallback(
|
||||||
|
async (parserId: string, parserConfig: IChangeParserConfigRequestBody) => {
|
||||||
|
if (record?.id) {
|
||||||
|
const ret = await setDocumentParser({
|
||||||
|
parserId,
|
||||||
|
documentId: record?.id,
|
||||||
|
parserConfig,
|
||||||
|
});
|
||||||
|
if (ret === 0) {
|
||||||
|
hideChangeParserModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[record?.id, setDocumentParser, hideChangeParserModal],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleShowChangeParserModal = useCallback(
|
||||||
|
(row: IDocumentInfo) => {
|
||||||
|
setRecord(row);
|
||||||
|
showChangeParserModal();
|
||||||
|
},
|
||||||
|
[showChangeParserModal],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
changeParserLoading: loading,
|
||||||
|
onChangeParserOk,
|
||||||
|
changeParserVisible,
|
||||||
|
hideChangeParserModal,
|
||||||
|
showChangeParserModal: handleShowChangeParserModal,
|
||||||
|
changeParserRecord: record,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UseChangeDocumentParserShowType = Pick<
|
||||||
|
ReturnType<typeof useChangeDocumentParser>,
|
||||||
|
'showChangeParserModal'
|
||||||
|
>;
|
||||||
@ -15,17 +15,13 @@ import { formatDate } from '@/utils/date';
|
|||||||
import { getExtension } from '@/utils/document-util';
|
import { getExtension } from '@/utils/document-util';
|
||||||
import { ColumnDef } from '@tanstack/table-core';
|
import { ColumnDef } from '@tanstack/table-core';
|
||||||
import { ArrowUpDown } from 'lucide-react';
|
import { ArrowUpDown } from 'lucide-react';
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { DatasetActionCell } from './dataset-action-cell';
|
import { DatasetActionCell } from './dataset-action-cell';
|
||||||
import { useChangeDocumentParser } from './hooks';
|
|
||||||
import { ParsingStatusCell } from './parsing-status-cell';
|
import { ParsingStatusCell } from './parsing-status-cell';
|
||||||
|
import { UseChangeDocumentParserShowType } from './use-change-document-parser';
|
||||||
import { UseRenameDocumentShowType } from './use-rename-document';
|
import { UseRenameDocumentShowType } from './use-rename-document';
|
||||||
|
|
||||||
type UseDatasetTableColumnsType = Pick<
|
type UseDatasetTableColumnsType = UseChangeDocumentParserShowType & {
|
||||||
ReturnType<typeof useChangeDocumentParser>,
|
|
||||||
'showChangeParserModal'
|
|
||||||
> & {
|
|
||||||
setCurrentRecord: (record: IDocumentInfo) => void;
|
setCurrentRecord: (record: IDocumentInfo) => void;
|
||||||
} & UseRenameDocumentShowType;
|
} & UseRenameDocumentShowType;
|
||||||
|
|
||||||
@ -42,13 +38,6 @@ export function useDatasetTableColumns({
|
|||||||
// setCurrentRecord(record);
|
// setCurrentRecord(record);
|
||||||
// showRenameModal();
|
// showRenameModal();
|
||||||
// };
|
// };
|
||||||
const onShowChangeParserModal = useCallback(
|
|
||||||
(record: IDocumentInfo) => () => {
|
|
||||||
setCurrentRecord(record);
|
|
||||||
showChangeParserModal();
|
|
||||||
},
|
|
||||||
[setCurrentRecord, showChangeParserModal],
|
|
||||||
);
|
|
||||||
|
|
||||||
// const onShowSetMetaModal = useCallback(() => {
|
// const onShowSetMetaModal = useCallback(() => {
|
||||||
// setRecord();
|
// setRecord();
|
||||||
@ -168,7 +157,12 @@ export function useDatasetTableColumns({
|
|||||||
header: t('parsingStatus'),
|
header: t('parsingStatus'),
|
||||||
// meta: { cellClassName: 'min-w-[20vw]' },
|
// meta: { cellClassName: 'min-w-[20vw]' },
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
return <ParsingStatusCell record={row.original}></ParsingStatusCell>;
|
return (
|
||||||
|
<ParsingStatusCell
|
||||||
|
record={row.original}
|
||||||
|
showChangeParserModal={showChangeParserModal}
|
||||||
|
></ParsingStatusCell>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user