mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-06-30 15:55:13 +08:00
### What problem does this PR solve? Feat: Retrieval test #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
db82c15de4
commit
86f76df586
@ -106,7 +106,7 @@ function RerankFormField() {
|
|||||||
name={RerankId}
|
name={RerankId}
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('rerankModel')}</FormLabel>
|
<FormLabel tooltip={t('rerankTip')}>{t('rerankModel')}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Select onValueChange={field.onChange} {...field}>
|
<Select onValueChange={field.onChange} {...field}>
|
||||||
<SelectTrigger
|
<SelectTrigger
|
||||||
@ -156,7 +156,7 @@ export function RerankFormFields() {
|
|||||||
name={'top_k'}
|
name={'top_k'}
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('topK')}</FormLabel>
|
<FormLabel tooltip={t('topKTip')}>{t('topK')}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SingleFormSlider
|
<SingleFormSlider
|
||||||
{...field}
|
{...field}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { useTranslate } from '@/hooks/common-hooks';
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
import { Form, Slider } from 'antd';
|
import { Form, Slider } from 'antd';
|
||||||
import { useFormContext } from 'react-hook-form';
|
import { useFormContext } from 'react-hook-form';
|
||||||
|
import { z } from 'zod';
|
||||||
import { SingleFormSlider } from '../ui/dual-range-slider';
|
import { SingleFormSlider } from '../ui/dual-range-slider';
|
||||||
import {
|
import {
|
||||||
FormControl,
|
FormControl,
|
||||||
@ -55,6 +56,19 @@ interface SimilaritySliderFormFieldProps {
|
|||||||
isTooltipShown?: boolean;
|
isTooltipShown?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const initialSimilarityThresholdValue = {
|
||||||
|
similarity_threshold: 0.2,
|
||||||
|
};
|
||||||
|
export const initialKeywordsSimilarityWeightValue = {
|
||||||
|
keywords_similarity_weight: 0.7,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const similarityThresholdSchema = { similarity_threshold: z.number() };
|
||||||
|
|
||||||
|
export const keywordsSimilarityWeightSchema = {
|
||||||
|
keywords_similarity_weight: z.number(),
|
||||||
|
};
|
||||||
|
|
||||||
export function SimilaritySliderFormField({
|
export function SimilaritySliderFormField({
|
||||||
vectorSimilarityWeightName = 'vector_similarity_weight',
|
vectorSimilarityWeightName = 'vector_similarity_weight',
|
||||||
isTooltipShown,
|
isTooltipShown,
|
||||||
|
@ -5,15 +5,23 @@ import {
|
|||||||
FormLabel,
|
FormLabel,
|
||||||
} from '@/components/ui/form';
|
} from '@/components/ui/form';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import { useFormContext } from 'react-hook-form';
|
import { useFormContext } from 'react-hook-form';
|
||||||
|
|
||||||
interface SwitchFormItemProps {
|
interface SwitchFormItemProps {
|
||||||
name: string;
|
name: string;
|
||||||
label: ReactNode;
|
label: ReactNode;
|
||||||
|
vertical?: boolean;
|
||||||
|
tooltip?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SwitchFormField({ label, name }: SwitchFormItemProps) {
|
export function SwitchFormField({
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
vertical = true,
|
||||||
|
tooltip,
|
||||||
|
}: SwitchFormItemProps) {
|
||||||
const form = useFormContext();
|
const form = useFormContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -21,8 +29,14 @@ export function SwitchFormField({ label, name }: SwitchFormItemProps) {
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name={name}
|
name={name}
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="flex justify-between">
|
<FormItem
|
||||||
<FormLabel className="text-base">{label}</FormLabel>
|
className={cn('flex', {
|
||||||
|
'gap-2': vertical,
|
||||||
|
'flex-col': vertical,
|
||||||
|
'justify-between': !vertical,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<FormLabel tooltip={tooltip}>{label}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Switch
|
<Switch
|
||||||
checked={field.value}
|
checked={field.value}
|
||||||
|
@ -34,6 +34,7 @@ export function UseKnowledgeGraphFormField({
|
|||||||
<SwitchFormField
|
<SwitchFormField
|
||||||
name={name}
|
name={name}
|
||||||
label={t('chat.useKnowledgeGraph')}
|
label={t('chat.useKnowledgeGraph')}
|
||||||
|
tooltip={t('chat.useKnowledgeGraphTip')}
|
||||||
></SwitchFormField>
|
></SwitchFormField>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
49
web/src/hooks/use-knowledge-request.ts
Normal file
49
web/src/hooks/use-knowledge-request.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { ITestRetrievalRequestBody } from '@/interfaces/request/knowledge';
|
||||||
|
import kbService from '@/services/knowledge-service';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
import { useParams } from 'umi';
|
||||||
|
import { useSetPaginationParams } from './route-hook';
|
||||||
|
|
||||||
|
export const enum KnowledgeApiAction {
|
||||||
|
TestRetrieval = 'testRetrieval',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useKnowledgeBaseId = () => {
|
||||||
|
const { id } = useParams();
|
||||||
|
|
||||||
|
return id;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useTestRetrieval = () => {
|
||||||
|
const knowledgeBaseId = useKnowledgeBaseId();
|
||||||
|
const { page, size: pageSize } = useSetPaginationParams();
|
||||||
|
const [values, setValues] = useState<ITestRetrievalRequestBody>();
|
||||||
|
|
||||||
|
const queryParams = useMemo(() => {
|
||||||
|
return {
|
||||||
|
...values,
|
||||||
|
kb_id: values?.kb_id || knowledgeBaseId,
|
||||||
|
page,
|
||||||
|
size: pageSize,
|
||||||
|
};
|
||||||
|
}, [knowledgeBaseId, page, pageSize, values]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isFetching: loading,
|
||||||
|
refetch,
|
||||||
|
} = useQuery<any>({
|
||||||
|
queryKey: [KnowledgeApiAction.TestRetrieval, queryParams],
|
||||||
|
initialData: {},
|
||||||
|
// enabled: !!values?.question && !!knowledgeBaseId,
|
||||||
|
enabled: false,
|
||||||
|
gcTime: 0,
|
||||||
|
queryFn: async () => {
|
||||||
|
const { data } = await kbService.retrieval_test(queryParams);
|
||||||
|
return data?.data ?? {};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, setValues, refetch };
|
||||||
|
};
|
10
web/src/interfaces/request/knowledge.ts
Normal file
10
web/src/interfaces/request/knowledge.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export interface ITestRetrievalRequestBody {
|
||||||
|
question: string;
|
||||||
|
similarity_threshold: number;
|
||||||
|
keywords_similarity_weight: number;
|
||||||
|
rerank_id?: string;
|
||||||
|
top_k?: number;
|
||||||
|
use_kg?: boolean;
|
||||||
|
highlight?: boolean;
|
||||||
|
kb_id?: string[];
|
||||||
|
}
|
@ -2,7 +2,7 @@ import { Button } from '@/components/ui/button';
|
|||||||
import { useSecondPathName } from '@/hooks/route-hook';
|
import { useSecondPathName } from '@/hooks/route-hook';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { Routes } from '@/routes';
|
import { Routes } from '@/routes';
|
||||||
import { Banknote, LayoutGrid, Trash2, User } from 'lucide-react';
|
import { Banknote, LayoutGrid, User } from 'lucide-react';
|
||||||
import { useHandleMenuClick } from './hooks';
|
import { useHandleMenuClick } from './hooks';
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
@ -61,13 +61,6 @@ export function SideBar() {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
className="absolute bottom-6 left-6 right-6 text-colors-text-functional-danger border-colors-text-functional-danger"
|
|
||||||
>
|
|
||||||
<Trash2 />
|
|
||||||
Delete dataset
|
|
||||||
</Button>
|
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,160 +1,102 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm, useWatch } from 'react-hook-form';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Button } from '@/components/ui/button';
|
import { RerankFormFields } from '@/components/rerank';
|
||||||
|
import {
|
||||||
|
initialKeywordsSimilarityWeightValue,
|
||||||
|
initialSimilarityThresholdValue,
|
||||||
|
keywordsSimilarityWeightSchema,
|
||||||
|
SimilaritySliderFormField,
|
||||||
|
similarityThresholdSchema,
|
||||||
|
} from '@/components/similarity-slider';
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormControl,
|
FormControl,
|
||||||
FormDescription,
|
|
||||||
FormField,
|
FormField,
|
||||||
FormItem,
|
FormItem,
|
||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage,
|
||||||
} from '@/components/ui/form';
|
} from '@/components/ui/form';
|
||||||
import { RAGFlowSelect } from '@/components/ui/select';
|
import { LoadingButton } from '@/components/ui/loading-button';
|
||||||
import { FormSlider } from '@/components/ui/slider';
|
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
|
import { UseKnowledgeGraphFormField } from '@/components/use-knowledge-graph-item';
|
||||||
const options = [
|
import { useTestRetrieval } from '@/hooks/use-knowledge-request';
|
||||||
{ label: 'xx', value: 'xx' },
|
import { trim } from 'lodash';
|
||||||
{ label: 'ii', value: 'ii' },
|
import { useEffect } from 'react';
|
||||||
];
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const groupOptions = [
|
|
||||||
{ label: 'scsdv', options },
|
|
||||||
{ label: 'thtyu', options: [{ label: 'jj', value: 'jj' }] },
|
|
||||||
];
|
|
||||||
|
|
||||||
const formSchema = z.object({
|
|
||||||
username: z.number().min(2, {
|
|
||||||
message: 'Username must be at least 2 characters.',
|
|
||||||
}),
|
|
||||||
a: z.number().min(2, {
|
|
||||||
message: 'Username must be at least 2 characters.',
|
|
||||||
}),
|
|
||||||
b: z.string().min(2, {
|
|
||||||
message: 'Username must be at least 2 characters.',
|
|
||||||
}),
|
|
||||||
c: z.number().min(2, {
|
|
||||||
message: 'Username must be at least 2 characters.',
|
|
||||||
}),
|
|
||||||
d: z.string().min(2, {
|
|
||||||
message: 'Username must be at least 2 characters.',
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default function TestingForm() {
|
export default function TestingForm() {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const { loading, setValues, refetch } = useTestRetrieval();
|
||||||
|
|
||||||
|
const formSchema = z.object({
|
||||||
|
question: z.string().min(1, {
|
||||||
|
message: t('knowledgeDetails.testTextPlaceholder'),
|
||||||
|
}),
|
||||||
|
...similarityThresholdSchema,
|
||||||
|
...keywordsSimilarityWeightSchema,
|
||||||
|
});
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof formSchema>>({
|
const form = useForm<z.infer<typeof formSchema>>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
username: 0,
|
...initialSimilarityThresholdValue,
|
||||||
|
...initialKeywordsSimilarityWeightValue,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function onSubmit(values: z.infer<typeof formSchema>) {
|
const question = form.watch('question');
|
||||||
console.log(values);
|
|
||||||
|
const values = useWatch({ control: form.control });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setValues(values as Required<z.infer<typeof formSchema>>);
|
||||||
|
}, [setValues, values]);
|
||||||
|
|
||||||
|
function onSubmit() {
|
||||||
|
refetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
|
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
|
||||||
|
<SimilaritySliderFormField
|
||||||
|
vectorSimilarityWeightName="keywords_similarity_weight"
|
||||||
|
isTooltipShown
|
||||||
|
></SimilaritySliderFormField>
|
||||||
|
<RerankFormFields></RerankFormFields>
|
||||||
|
<UseKnowledgeGraphFormField name="use_kg"></UseKnowledgeGraphFormField>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="username"
|
name="question"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Username</FormLabel>
|
<FormLabel>{t('knowledgeDetails.testText')}</FormLabel>
|
||||||
<FormControl>
|
|
||||||
<FormSlider {...field}></FormSlider>
|
|
||||||
</FormControl>
|
|
||||||
<FormDescription>
|
|
||||||
This is your public display name.
|
|
||||||
</FormDescription>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="a"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Username</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<FormSlider {...field}></FormSlider>
|
|
||||||
</FormControl>
|
|
||||||
<FormDescription>
|
|
||||||
This is your public display name.
|
|
||||||
</FormDescription>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="b"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Username</FormLabel>
|
|
||||||
<RAGFlowSelect
|
|
||||||
value={field.value}
|
|
||||||
onChange={field.onChange}
|
|
||||||
FormControlComponent={FormControl}
|
|
||||||
options={groupOptions}
|
|
||||||
></RAGFlowSelect>
|
|
||||||
<FormDescription>
|
|
||||||
This is your public display name.
|
|
||||||
</FormDescription>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="c"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Username</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<FormSlider {...field}></FormSlider>
|
|
||||||
</FormControl>
|
|
||||||
<FormDescription>
|
|
||||||
This is your public display name.
|
|
||||||
</FormDescription>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="d"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>Username</FormLabel>
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Textarea
|
<Textarea
|
||||||
{...field}
|
{...field}
|
||||||
className="bg-colors-background-inverse-weak"
|
className="bg-colors-background-inverse-weak"
|
||||||
></Textarea>
|
></Textarea>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormDescription>
|
|
||||||
This is your public display name.
|
|
||||||
</FormDescription>
|
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Button
|
<LoadingButton
|
||||||
variant={'tertiary'}
|
variant={'tertiary'}
|
||||||
size={'sm'}
|
size={'sm'}
|
||||||
type="submit"
|
type="submit"
|
||||||
className="w-full"
|
className="w-full"
|
||||||
|
disabled={!!!trim(question)}
|
||||||
|
loading={loading}
|
||||||
>
|
>
|
||||||
Test
|
{t('knowledgeDetails.testingLabel')}
|
||||||
</Button>
|
</LoadingButton>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user