Fix: File selection in Retrieval testing causes other options to disappear (#7759)

### What problem does this PR solve?

https://github.com/infiniflow/ragflow/issues/7753

The internal is due to when the selected row keys change will trigger a
testing, but I do not know why.

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
Stephen Hu 2025-05-30 09:38:50 +08:00 committed by GitHub
parent e97fd2b5e6
commit a31ad7f960
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 150 additions and 18 deletions

View File

@ -2,7 +2,10 @@ import { ReactComponent as SelectedFilesCollapseIcon } from '@/assets/svg/select
import { Collapse, Flex, Space } from 'antd'; import { Collapse, Flex, Space } from 'antd';
import SelectFiles from './select-files'; import SelectFiles from './select-files';
import { useSelectTestingResult } from '@/hooks/knowledge-hooks'; import {
useAllTestingResult,
useSelectTestingResult,
} from '@/hooks/knowledge-hooks';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import styles from './index.less'; import styles from './index.less';
@ -18,7 +21,12 @@ const RetrievalDocuments = ({
setSelectedDocumentIds, setSelectedDocumentIds,
}: IProps) => { }: IProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { documents: documentsAll } = useAllTestingResult();
const { documents } = useSelectTestingResult(); const { documents } = useSelectTestingResult();
const { documents: useDocuments } = {
documents:
documentsAll?.length > documents?.length ? documentsAll : documents,
};
return ( return (
<Collapse <Collapse
@ -35,7 +43,7 @@ const RetrievalDocuments = ({
> >
<Space> <Space>
<span> <span>
{selectedDocumentIds?.length ?? 0}/{documents?.length ?? 0} {selectedDocumentIds?.length ?? 0}/{useDocuments?.length ?? 0}
</span> </span>
{t('knowledgeDetails.filesSelected')} {t('knowledgeDetails.filesSelected')}
</Space> </Space>

View File

@ -1,6 +1,9 @@
import NewDocumentLink from '@/components/new-document-link'; import NewDocumentLink from '@/components/new-document-link';
import { useTranslate } from '@/hooks/common-hooks'; import { useTranslate } from '@/hooks/common-hooks';
import { useSelectTestingResult } from '@/hooks/knowledge-hooks'; import {
useAllTestingResult,
useSelectTestingResult,
} from '@/hooks/knowledge-hooks';
import { ITestingDocument } from '@/interfaces/database/knowledge'; import { ITestingDocument } from '@/interfaces/database/knowledge';
import { EyeOutlined } from '@ant-design/icons'; import { EyeOutlined } from '@ant-design/icons';
import { Button, Table, TableProps, Tooltip } from 'antd'; import { Button, Table, TableProps, Tooltip } from 'antd';
@ -12,6 +15,9 @@ interface IProps {
const SelectFiles = ({ setSelectedDocumentIds, handleTesting }: IProps) => { const SelectFiles = ({ setSelectedDocumentIds, handleTesting }: IProps) => {
const { documents } = useSelectTestingResult(); const { documents } = useSelectTestingResult();
const { documents: documentsAll } = useAllTestingResult();
const useDocuments =
documentsAll?.length > documents?.length ? documentsAll : documents;
const { t } = useTranslate('fileManager'); const { t } = useTranslate('fileManager');
const columns: TableProps<ITestingDocument>['columns'] = [ const columns: TableProps<ITestingDocument>['columns'] = [
@ -62,7 +68,7 @@ const SelectFiles = ({ setSelectedDocumentIds, handleTesting }: IProps) => {
return ( return (
<Table <Table
columns={columns} columns={columns}
dataSource={documents} dataSource={useDocuments}
showHeader={false} showHeader={false}
rowSelection={rowSelection} rowSelection={rowSelection}
rowKey={'doc_id'} rowKey={'doc_id'}

View File

@ -261,6 +261,51 @@ export const useTestChunkRetrieval = (): ResponsePostType<ITestingResult> & {
}; };
}; };
export const useTestChunkAllRetrieval = (): ResponsePostType<ITestingResult> & {
testChunkAll: (...params: any[]) => void;
} => {
const knowledgeBaseId = useKnowledgeBaseId();
const { page, size: pageSize } = useSetPaginationParams();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: ['testChunkAll'], // This method is invalid
gcTime: 0,
mutationFn: async (values: any) => {
const { data } = await kbService.retrieval_test({
...values,
kb_id: values.kb_id ?? knowledgeBaseId,
doc_ids: [],
page,
size: pageSize,
});
if (data.code === 0) {
const res = data.data;
return {
...res,
documents: res.doc_aggs,
};
}
return (
data?.data ?? {
chunks: [],
documents: [],
total: 0,
}
);
},
});
return {
data: data ?? { chunks: [], documents: [], total: 0 },
loading,
testChunkAll: mutateAsync,
};
};
export const useChunkIsTesting = () => { export const useChunkIsTesting = () => {
return useIsMutating({ mutationKey: ['testChunk'] }) > 0; return useIsMutating({ mutationKey: ['testChunk'] }) > 0;
}; };
@ -288,6 +333,30 @@ export const useSelectIsTestingSuccess = () => {
}); });
return status.at(-1) === 'success'; return status.at(-1) === 'success';
}; };
export const useAllTestingSuccess = () => {
const status = useMutationState({
filters: { mutationKey: ['testChunkAll'] },
select: (mutation) => {
return mutation.state.status;
},
});
return status.at(-1) === 'success';
};
export const useAllTestingResult = (): ITestingResult => {
const data = useMutationState({
filters: { mutationKey: ['testChunkAll'] },
select: (mutation) => {
return mutation.state.data;
},
});
return (data.at(-1) ?? {
chunks: [],
documents: [],
total: 0,
}) as ITestingResult;
};
//#endregion //#endregion
//#region tags //#region tags

View File

@ -1,13 +1,19 @@
import { useTestChunkRetrieval } from '@/hooks/knowledge-hooks'; import {
useTestChunkAllRetrieval,
useTestChunkRetrieval,
} from '@/hooks/knowledge-hooks';
import { Flex, Form } from 'antd'; import { Flex, Form } from 'antd';
import TestingControl from './testing-control'; import TestingControl from './testing-control';
import TestingResult from './testing-result'; import TestingResult from './testing-result';
import { useState } from 'react';
import styles from './index.less'; import styles from './index.less';
const KnowledgeTesting = () => { const KnowledgeTesting = () => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const { testChunk } = useTestChunkRetrieval(); const { testChunk } = useTestChunkRetrieval();
const { testChunkAll } = useTestChunkAllRetrieval();
const [selectedDocumentIds, setSelectedDocumentIds] = useState<string[]>([]);
const handleTesting = async (documentIds: string[] = []) => { const handleTesting = async (documentIds: string[] = []) => {
const values = await form.validateFields(); const values = await form.validateFields();
@ -16,6 +22,12 @@ const KnowledgeTesting = () => {
doc_ids: Array.isArray(documentIds) ? documentIds : [], doc_ids: Array.isArray(documentIds) ? documentIds : [],
vector_similarity_weight: 1 - values.vector_similarity_weight, vector_similarity_weight: 1 - values.vector_similarity_weight,
}); });
testChunkAll({
...values,
doc_ids: [],
vector_similarity_weight: 1 - values.vector_similarity_weight,
});
}; };
return ( return (
@ -23,8 +35,13 @@ const KnowledgeTesting = () => {
<TestingControl <TestingControl
form={form} form={form}
handleTesting={handleTesting} handleTesting={handleTesting}
selectedDocumentIds={selectedDocumentIds}
></TestingControl> ></TestingControl>
<TestingResult handleTesting={handleTesting}></TestingResult> <TestingResult
handleTesting={handleTesting}
selectedDocumentIds={selectedDocumentIds}
setSelectedDocumentIds={setSelectedDocumentIds}
></TestingResult>
</Flex> </Flex>
); );
}; };

View File

@ -18,10 +18,15 @@ type FieldType = {
interface IProps { interface IProps {
form: FormInstance; form: FormInstance;
handleTesting: () => Promise<any>; handleTesting: (documentIds?: string[]) => Promise<any>;
selectedDocumentIds: string[];
} }
const TestingControl = ({ form, handleTesting }: IProps) => { const TestingControl = ({
form,
handleTesting,
selectedDocumentIds,
}: IProps) => {
const question = Form.useWatch('question', { form, preserve: true }); const question = Form.useWatch('question', { form, preserve: true });
const loading = useChunkIsTesting(); const loading = useChunkIsTesting();
const { t } = useTranslate('knowledgeDetails'); const { t } = useTranslate('knowledgeDetails');
@ -29,6 +34,10 @@ const TestingControl = ({ form, handleTesting }: IProps) => {
const buttonDisabled = const buttonDisabled =
!question || (typeof question === 'string' && question.trim() === ''); !question || (typeof question === 'string' && question.trim() === '');
const onClick = () => {
handleTesting(selectedDocumentIds);
};
return ( return (
<section className={styles.testingControlWrapper}> <section className={styles.testingControlWrapper}>
<div> <div>
@ -53,7 +62,7 @@ const TestingControl = ({ form, handleTesting }: IProps) => {
<Button <Button
type="primary" type="primary"
size="small" size="small"
onClick={handleTesting} onClick={onClick}
disabled={buttonDisabled} disabled={buttonDisabled}
loading={loading} loading={loading}
> >

View File

@ -15,13 +15,15 @@ import camelCase from 'lodash/camelCase';
import SelectFiles from './select-files'; import SelectFiles from './select-files';
import { import {
useAllTestingResult,
useAllTestingSuccess,
useSelectIsTestingSuccess, useSelectIsTestingSuccess,
useSelectTestingResult, useSelectTestingResult,
} from '@/hooks/knowledge-hooks'; } from '@/hooks/knowledge-hooks';
import { useGetPaginationWithRouter } from '@/hooks/logic-hooks'; import { useGetPaginationWithRouter } from '@/hooks/logic-hooks';
import { api_host } from '@/utils/api'; import { api_host } from '@/utils/api';
import { showImage } from '@/utils/chat'; import { showImage } from '@/utils/chat';
import { useCallback, useState } from 'react'; import { useCallback } from 'react';
import styles from './index.less'; import styles from './index.less';
const similarityList: Array<{ field: keyof ITestingChunk; label: string }> = [ const similarityList: Array<{ field: keyof ITestingChunk; label: string }> = [
@ -48,14 +50,21 @@ const ChunkTitle = ({ item }: { item: ITestingChunk }) => {
interface IProps { interface IProps {
handleTesting: (documentIds?: string[]) => Promise<any>; handleTesting: (documentIds?: string[]) => Promise<any>;
selectedDocumentIds: string[];
setSelectedDocumentIds: (ids: string[]) => void;
} }
const TestingResult = ({ handleTesting }: IProps) => { const TestingResult = ({
const [selectedDocumentIds, setSelectedDocumentIds] = useState<string[]>([]); handleTesting,
selectedDocumentIds,
setSelectedDocumentIds,
}: IProps) => {
const { documents, chunks, total } = useSelectTestingResult(); const { documents, chunks, total } = useSelectTestingResult();
const { documents: documentsAll, total: totalAll } = useAllTestingResult();
const { t } = useTranslate('knowledgeDetails'); const { t } = useTranslate('knowledgeDetails');
const { pagination, setPagination } = useGetPaginationWithRouter(); const { pagination, setPagination } = useGetPaginationWithRouter();
const isSuccess = useSelectIsTestingSuccess(); const isSuccess = useSelectIsTestingSuccess();
const isAllSuccess = useAllTestingSuccess();
const onChange: PaginationProps['onChange'] = (pageNumber, pageSize) => { const onChange: PaginationProps['onChange'] = (pageNumber, pageSize) => {
pagination.onChange?.(pageNumber, pageSize); pagination.onChange?.(pageNumber, pageSize);
@ -88,7 +97,8 @@ const TestingResult = ({ handleTesting }: IProps) => {
> >
<Space> <Space>
<span> <span>
{selectedDocumentIds?.length ?? 0}/{documents?.length ?? 0} {selectedDocumentIds?.length ?? 0}/
{documentsAll?.length ?? 0}
</span> </span>
{t('filesSelected')} {t('filesSelected')}
</Space> </Space>

View File

@ -1,6 +1,6 @@
import NewDocumentLink from '@/components/new-document-link'; import NewDocumentLink from '@/components/new-document-link';
import { useTranslate } from '@/hooks/common-hooks'; import { useTranslate } from '@/hooks/common-hooks';
import { useSelectTestingResult } from '@/hooks/knowledge-hooks'; import { useAllTestingResult } from '@/hooks/knowledge-hooks';
import { ITestingDocument } from '@/interfaces/database/knowledge'; import { ITestingDocument } from '@/interfaces/database/knowledge';
import { EyeOutlined } from '@ant-design/icons'; import { EyeOutlined } from '@ant-design/icons';
import { Button, Table, TableProps, Tooltip } from 'antd'; import { Button, Table, TableProps, Tooltip } from 'antd';
@ -11,7 +11,7 @@ interface IProps {
} }
const SelectFiles = ({ setSelectedDocumentIds, handleTesting }: IProps) => { const SelectFiles = ({ setSelectedDocumentIds, handleTesting }: IProps) => {
const { documents } = useSelectTestingResult(); const { documents } = useAllTestingResult();
const { t } = useTranslate('fileManager'); const { t } = useTranslate('fileManager');
const columns: TableProps<ITestingDocument>['columns'] = [ const columns: TableProps<ITestingDocument>['columns'] = [
@ -50,8 +50,8 @@ const SelectFiles = ({ setSelectedDocumentIds, handleTesting }: IProps) => {
const rowSelection = { const rowSelection = {
onChange: (selectedRowKeys: React.Key[]) => { onChange: (selectedRowKeys: React.Key[]) => {
handleTesting(selectedRowKeys as string[]);
setSelectedDocumentIds(selectedRowKeys as string[]); setSelectedDocumentIds(selectedRowKeys as string[]);
handleTesting(selectedRowKeys as string[]);
}, },
getCheckboxProps: (record: ITestingDocument) => ({ getCheckboxProps: (record: ITestingDocument) => ({
disabled: record.doc_name === 'Disabled User', // Column configuration not to be checked disabled: record.doc_name === 'Disabled User', // Column configuration not to be checked

View File

@ -1,6 +1,9 @@
import { useFetchMindMap, useFetchRelatedQuestions } from '@/hooks/chat-hooks'; import { useFetchMindMap, useFetchRelatedQuestions } from '@/hooks/chat-hooks';
import { useSetModalState } from '@/hooks/common-hooks'; import { useSetModalState } from '@/hooks/common-hooks';
import { useTestChunkRetrieval } from '@/hooks/knowledge-hooks'; import {
useTestChunkAllRetrieval,
useTestChunkRetrieval,
} from '@/hooks/knowledge-hooks';
import { import {
useGetPaginationWithRouter, useGetPaginationWithRouter,
useSendMessageWithSse, useSendMessageWithSse,
@ -21,6 +24,7 @@ export const useSendQuestion = (kbIds: string[]) => {
api.ask, api.ask,
); );
const { testChunk, loading } = useTestChunkRetrieval(); const { testChunk, loading } = useTestChunkRetrieval();
const { testChunkAll, loading: loadingAll } = useTestChunkAllRetrieval();
const [sendingLoading, setSendingLoading] = useState(false); const [sendingLoading, setSendingLoading] = useState(false);
const [currentAnswer, setCurrentAnswer] = useState({} as IAnswer); const [currentAnswer, setCurrentAnswer] = useState({} as IAnswer);
const { fetchRelatedQuestions, data: relatedQuestions } = const { fetchRelatedQuestions, data: relatedQuestions } =
@ -88,6 +92,15 @@ export const useSendQuestion = (kbIds: string[]) => {
page, page,
size, size,
}); });
testChunkAll({
kb_id: kbIds,
highlight: true,
question: q,
doc_ids: [],
page,
size,
});
}, },
[sendingLoading, searchStr, kbIds, testChunk, selectedDocumentIds], [sendingLoading, searchStr, kbIds, testChunk, selectedDocumentIds],
); );