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

@ -254,7 +254,7 @@ class CommonService:
# Returns:
# Number of records deleted
return cls.model.delete().where(cls.model.id == pid).execute()
@classmethod
@DB.connection_context()
def delete_by_ids(cls, pids):

View File

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

View File

@ -1,6 +1,9 @@
import NewDocumentLink from '@/components/new-document-link';
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 { EyeOutlined } from '@ant-design/icons';
import { Button, Table, TableProps, Tooltip } from 'antd';
@ -12,6 +15,9 @@ interface IProps {
const SelectFiles = ({ setSelectedDocumentIds, handleTesting }: IProps) => {
const { documents } = useSelectTestingResult();
const { documents: documentsAll } = useAllTestingResult();
const useDocuments =
documentsAll?.length > documents?.length ? documentsAll : documents;
const { t } = useTranslate('fileManager');
const columns: TableProps<ITestingDocument>['columns'] = [
@ -62,7 +68,7 @@ const SelectFiles = ({ setSelectedDocumentIds, handleTesting }: IProps) => {
return (
<Table
columns={columns}
dataSource={documents}
dataSource={useDocuments}
showHeader={false}
rowSelection={rowSelection}
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 = () => {
return useIsMutating({ mutationKey: ['testChunk'] }) > 0;
};
@ -288,6 +333,30 @@ export const useSelectIsTestingSuccess = () => {
});
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
//#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 TestingControl from './testing-control';
import TestingResult from './testing-result';
import { useState } from 'react';
import styles from './index.less';
const KnowledgeTesting = () => {
const [form] = Form.useForm();
const { testChunk } = useTestChunkRetrieval();
const { testChunkAll } = useTestChunkAllRetrieval();
const [selectedDocumentIds, setSelectedDocumentIds] = useState<string[]>([]);
const handleTesting = async (documentIds: string[] = []) => {
const values = await form.validateFields();
@ -16,6 +22,12 @@ const KnowledgeTesting = () => {
doc_ids: Array.isArray(documentIds) ? documentIds : [],
vector_similarity_weight: 1 - values.vector_similarity_weight,
});
testChunkAll({
...values,
doc_ids: [],
vector_similarity_weight: 1 - values.vector_similarity_weight,
});
};
return (
@ -23,8 +35,13 @@ const KnowledgeTesting = () => {
<TestingControl
form={form}
handleTesting={handleTesting}
selectedDocumentIds={selectedDocumentIds}
></TestingControl>
<TestingResult handleTesting={handleTesting}></TestingResult>
<TestingResult
handleTesting={handleTesting}
selectedDocumentIds={selectedDocumentIds}
setSelectedDocumentIds={setSelectedDocumentIds}
></TestingResult>
</Flex>
);
};

View File

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

View File

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

View File

@ -1,6 +1,6 @@
import NewDocumentLink from '@/components/new-document-link';
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 { EyeOutlined } from '@ant-design/icons';
import { Button, Table, TableProps, Tooltip } from 'antd';
@ -11,7 +11,7 @@ interface IProps {
}
const SelectFiles = ({ setSelectedDocumentIds, handleTesting }: IProps) => {
const { documents } = useSelectTestingResult();
const { documents } = useAllTestingResult();
const { t } = useTranslate('fileManager');
const columns: TableProps<ITestingDocument>['columns'] = [
@ -50,8 +50,8 @@ const SelectFiles = ({ setSelectedDocumentIds, handleTesting }: IProps) => {
const rowSelection = {
onChange: (selectedRowKeys: React.Key[]) => {
handleTesting(selectedRowKeys as string[]);
setSelectedDocumentIds(selectedRowKeys as string[]);
handleTesting(selectedRowKeys as string[]);
},
getCheckboxProps: (record: ITestingDocument) => ({
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 { useSetModalState } from '@/hooks/common-hooks';
import { useTestChunkRetrieval } from '@/hooks/knowledge-hooks';
import {
useTestChunkAllRetrieval,
useTestChunkRetrieval,
} from '@/hooks/knowledge-hooks';
import {
useGetPaginationWithRouter,
useSendMessageWithSse,
@ -21,6 +24,7 @@ export const useSendQuestion = (kbIds: string[]) => {
api.ask,
);
const { testChunk, loading } = useTestChunkRetrieval();
const { testChunkAll, loading: loadingAll } = useTestChunkAllRetrieval();
const [sendingLoading, setSendingLoading] = useState(false);
const [currentAnswer, setCurrentAnswer] = useState({} as IAnswer);
const { fetchRelatedQuestions, data: relatedQuestions } =
@ -88,6 +92,15 @@ export const useSendQuestion = (kbIds: string[]) => {
page,
size,
});
testChunkAll({
kb_id: kbIds,
highlight: true,
question: q,
doc_ids: [],
page,
size,
});
},
[sendingLoading, searchStr, kbIds, testChunk, selectedDocumentIds],
);