diff --git a/web/src/components/list-filter-bar/index.tsx b/web/src/components/list-filter-bar/index.tsx index f62e9a8f3..9271aa14d 100644 --- a/web/src/components/list-filter-bar/index.tsx +++ b/web/src/components/list-filter-bar/index.tsx @@ -19,7 +19,7 @@ interface IProps { leftPanel?: ReactNode; } -const FilterButton = React.forwardRef< +export const FilterButton = React.forwardRef< HTMLButtonElement, ButtonProps & { count?: number } >(({ count = 0, ...props }, ref) => { diff --git a/web/src/components/rerank.tsx b/web/src/components/rerank.tsx index 232b3a275..528c65a82 100644 --- a/web/src/components/rerank.tsx +++ b/web/src/components/rerank.tsx @@ -4,7 +4,8 @@ import { useSelectLlmOptionsByModelType } from '@/hooks/llm-hooks'; import { Select as AntSelect, Form, message, Slider } from 'antd'; import { useCallback } from 'react'; import { useFormContext } from 'react-hook-form'; -import { SingleFormSlider } from './ui/dual-range-slider'; +import { z } from 'zod'; +import { SliderInputFormField } from './slider-input-form-field'; import { FormControl, FormField, @@ -63,6 +64,14 @@ export const RerankItem = () => { ); }; +export const topKSchema = { + top_k: z.number().optional(), +}; + +export const initialTopKValue = { + top_k: 1024, +}; + const Rerank = () => { const { t } = useTranslate('knowledgeDetails'); @@ -143,7 +152,7 @@ function RerankFormField() { } export function RerankFormFields() { - const { control, watch } = useFormContext(); + const { watch } = useFormContext(); const { t } = useTranslate('knowledgeDetails'); const rerankId = watch(RerankId); @@ -151,23 +160,13 @@ export function RerankFormFields() { <> {rerankId && ( - ( - - {t('topK')} - - - - - - )} - /> + label={t('topK')} + max={2048} + min={1} + tooltip={t('topKTip')} + > )} ); diff --git a/web/src/components/similarity-slider/index.tsx b/web/src/components/similarity-slider/index.tsx index 37a3f0aad..4dbab5e74 100644 --- a/web/src/components/similarity-slider/index.tsx +++ b/web/src/components/similarity-slider/index.tsx @@ -1,15 +1,7 @@ import { useTranslate } from '@/hooks/common-hooks'; import { Form, Slider } from 'antd'; -import { useFormContext } from 'react-hook-form'; import { z } from 'zod'; -import { SingleFormSlider } from '../ui/dual-range-slider'; -import { - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '../ui/form'; +import { SliderInputFormField } from '../slider-input-form-field'; type FieldType = { similarity_threshold?: number; @@ -73,51 +65,24 @@ export function SimilaritySliderFormField({ vectorSimilarityWeightName = 'vector_similarity_weight', isTooltipShown, }: SimilaritySliderFormFieldProps) { - const form = useFormContext(); const { t } = useTranslate('knowledgeDetails'); return ( <> - ( - - - {t('similarityThreshold')} - - - - - - - )} - /> - + ( - - - {t('vectorSimilarityWeight')} - - - - - - - )} - /> + label={t('vectorSimilarityWeight')} + max={1} + step={0.01} + tooltip={isTooltipShown && t('vectorSimilarityWeightTip')} + > ); } diff --git a/web/src/components/slider-input-form-field.tsx b/web/src/components/slider-input-form-field.tsx index 1639194ae..4a1db2662 100644 --- a/web/src/components/slider-input-form-field.tsx +++ b/web/src/components/slider-input-form-field.tsx @@ -1,3 +1,4 @@ +import { cn } from '@/lib/utils'; import { ReactNode } from 'react'; import { useFormContext } from 'react-hook-form'; import { SingleFormSlider } from './ui/dual-range-slider'; @@ -18,6 +19,7 @@ type SliderInputFormFieldProps = { label: string; tooltip?: ReactNode; defaultValue?: number; + className?: string; }; export function SliderInputFormField({ @@ -28,6 +30,7 @@ export function SliderInputFormField({ name, tooltip, defaultValue, + className, }: SliderInputFormFieldProps) { const form = useFormContext(); @@ -39,7 +42,12 @@ export function SliderInputFormField({ render={({ field }) => ( {label} -
+
{ export const useTestRetrieval = () => { const knowledgeBaseId = useKnowledgeBaseId(); - const { page, size: pageSize } = useSetPaginationParams(); const [values, setValues] = useState(); + const mountedRef = useRef(false); + const { filterValue, handleFilterSubmit } = useHandleFilterSubmit(); + + const [page, setPage] = useState(1); + const [pageSize, setPageSize] = useState(10); + + const onPaginationChange = useCallback((page: number, pageSize: number) => { + setPage(page); + setPageSize(pageSize); + }, []); const queryParams = useMemo(() => { return { @@ -44,15 +52,16 @@ export const useTestRetrieval = () => { kb_id: values?.kb_id || knowledgeBaseId, page, size: pageSize, + doc_ids: filterValue.doc_ids, }; - }, [knowledgeBaseId, page, pageSize, values]); + }, [filterValue, knowledgeBaseId, page, pageSize, values]); const { data, isFetching: loading, refetch, } = useQuery({ - queryKey: [KnowledgeApiAction.TestRetrieval, queryParams], + queryKey: [KnowledgeApiAction.TestRetrieval, queryParams, page, pageSize], initialData: { chunks: [], doc_aggs: [], @@ -62,12 +71,27 @@ export const useTestRetrieval = () => { gcTime: 0, queryFn: async () => { const { data } = await kbService.retrieval_test(queryParams); - console.log('🚀 ~ queryFn: ~ data:', data); return data?.data ?? {}; }, }); - return { data, loading, setValues, refetch }; + useEffect(() => { + if (mountedRef.current) { + refetch(); + } + mountedRef.current = true; + }, [page, pageSize, refetch, filterValue]); + + return { + data, + loading, + setValues, + refetch, + onPaginationChange, + page, + pageSize, + handleFilterSubmit, + }; }; export const useFetchNextKnowledgeListByPage = () => { diff --git a/web/src/pages/chat/markdown-content/index.tsx b/web/src/pages/chat/markdown-content/index.tsx index 26671b70b..cfa911d1a 100644 --- a/web/src/pages/chat/markdown-content/index.tsx +++ b/web/src/pages/chat/markdown-content/index.tsx @@ -50,7 +50,8 @@ const MarkdownContent = ({ const { setDocumentIds, data: fileThumbnails } = useFetchDocumentThumbnailsByIds(); const contentWithCursor = useMemo(() => { - let text = DOMPurify.sanitize(content); + // let text = DOMPurify.sanitize(content); + let text = content; if (text === '') { text = t('chat.searching'); } diff --git a/web/src/pages/dataset/dataset-title.tsx b/web/src/pages/dataset/dataset-title.tsx new file mode 100644 index 000000000..60eb46033 --- /dev/null +++ b/web/src/pages/dataset/dataset-title.tsx @@ -0,0 +1,15 @@ +import { ReactNode } from 'react'; + +type TopTitleProps = { + title: ReactNode; + description: ReactNode; +}; + +export function TopTitle({ title, description }: TopTitleProps) { + return ( +
+
{title}
+

{description}

+
+ ); +} diff --git a/web/src/pages/dataset/setting/index.tsx b/web/src/pages/dataset/setting/index.tsx index 21af68879..a27e248b6 100644 --- a/web/src/pages/dataset/setting/index.tsx +++ b/web/src/pages/dataset/setting/index.tsx @@ -5,6 +5,7 @@ import { DocumentParserType } from '@/constants/knowledge'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm, useWatch } from 'react-hook-form'; import { z } from 'zod'; +import { TopTitle } from '../dataset-title'; import CategoryPanel from './category-panel'; import { ChunkMethodForm } from './chunk-method-form'; import { formSchema } from './form-schema'; @@ -74,13 +75,11 @@ export default function DatasetSettings() { return (
-
-
Configuration
-

- Update your knowledge base configuration here, particularly the chunk - method. -

-
+
= [ @@ -14,7 +22,7 @@ const similarityList: Array<{ field: keyof ITestingChunk; label: string }> = [ const ChunkTitle = ({ item }: { item: ITestingChunk }) => { const { t } = useTranslate('knowledgeDetails'); return ( -
+
{similarityList.map((x) => (
{((item[x.field] as number) * 100).toFixed(2)} @@ -26,43 +34,83 @@ const ChunkTitle = ({ item }: { item: ITestingChunk }) => { }; export default function RetrievalTesting() { - const { loading, setValues, refetch, data } = useTestRetrieval(); + const { + loading, + setValues, + refetch, + data, + onPaginationChange, + page, + pageSize, + handleFilterSubmit, + } = useTestRetrieval(); + + const filters: FilterCollection[] = useMemo(() => { + return [ + { + field: 'doc_ids', + label: 'File', + list: + data.doc_aggs?.map((x) => ({ + id: x.doc_id, + label: x.doc_name, + count: x.count, + })) ?? [], + }, + ]; + }, [data.doc_aggs]); return ( -
-
- -
-
-

- 15 Results from 3 files -

-
- {data.chunks.map((x) => ( - - - -
- -
-
-
- -

- {x.content_with_weight} -

-
-
- ))} -
-
-
+
+
+ + +
+
+
+
+ + Test setting + + +
+ +
+
+
+ + Test results + + + + +
+
+ {data.chunks?.map((x) => ( + + +

{x.content_with_weight}

+
+ ))} +
+ +
+
+
); } diff --git a/web/src/pages/dataset/testing/testing-form.tsx b/web/src/pages/dataset/testing/testing-form.tsx index 4a1c4fcb9..5c8cf0ae5 100644 --- a/web/src/pages/dataset/testing/testing-form.tsx +++ b/web/src/pages/dataset/testing/testing-form.tsx @@ -4,7 +4,12 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { useForm, useWatch } from 'react-hook-form'; import { z } from 'zod'; -import { RerankFormFields } from '@/components/rerank'; +import { FormContainer } from '@/components/form-container'; +import { + initialTopKValue, + RerankFormFields, + topKSchema, +} from '@/components/rerank'; import { initialKeywordsSimilarityWeightValue, initialSimilarityThresholdValue, @@ -12,6 +17,7 @@ import { SimilaritySliderFormField, similarityThresholdSchema, } from '@/components/similarity-slider'; +import { ButtonLoading } from '@/components/ui/button'; import { Form, FormControl, @@ -20,7 +26,6 @@ import { FormLabel, FormMessage, } from '@/components/ui/form'; -import { LoadingButton } from '@/components/ui/loading-button'; import { Textarea } from '@/components/ui/textarea'; import { UseKnowledgeGraphFormField } from '@/components/use-knowledge-graph-item'; import { useTestRetrieval } from '@/hooks/use-knowledge-request'; @@ -46,6 +51,7 @@ export default function TestingForm({ }), ...similarityThresholdSchema, ...keywordsSimilarityWeightSchema, + ...topKSchema, }); const form = useForm>({ @@ -53,6 +59,7 @@ export default function TestingForm({ defaultValues: { ...initialSimilarityThresholdValue, ...initialKeywordsSimilarityWeightValue, + ...initialTopKValue, }, }); @@ -71,12 +78,14 @@ export default function TestingForm({ return ( - - - + + + + + )} /> - {t('knowledgeDetails.testingLabel')} - + );