mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
fix: Change the data in the dataset page to be obtained using the interface (#8726)
### What problem does this PR solve? Change the data in the dataset page to be obtained using the interface, and change the import to obtain all data every 15 seconds to obtain the data of the current page every 5 seconds when parsing the existing file. [#3221](https://github.com/infiniflow/ragflow/issues/3221) ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@ -24,6 +24,7 @@ export type CheckboxFormMultipleProps = {
|
|||||||
filters?: FilterCollection[];
|
filters?: FilterCollection[];
|
||||||
value?: FilterValue;
|
value?: FilterValue;
|
||||||
onChange?: FilterChange;
|
onChange?: FilterChange;
|
||||||
|
onOpenChange?: (open: boolean) => void;
|
||||||
setOpen(open: boolean): void;
|
setOpen(open: boolean): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -148,12 +149,19 @@ export function FilterPopover({
|
|||||||
children,
|
children,
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
|
onOpenChange,
|
||||||
filters,
|
filters,
|
||||||
}: PropsWithChildren & Omit<CheckboxFormMultipleProps, 'setOpen'>) {
|
}: PropsWithChildren & Omit<CheckboxFormMultipleProps, 'setOpen'>) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
const onOpenChangeFun = useCallback(
|
||||||
|
(e: boolean) => {
|
||||||
|
onOpenChange?.(e);
|
||||||
|
setOpen(e);
|
||||||
|
},
|
||||||
|
[onOpenChange],
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<Popover open={open} onOpenChange={setOpen}>
|
<Popover open={open} onOpenChange={onOpenChangeFun}>
|
||||||
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
||||||
<PopoverContent className="p-0">
|
<PopoverContent className="p-0">
|
||||||
<CheckboxFormMultiple
|
<CheckboxFormMultiple
|
||||||
|
|||||||
@ -52,6 +52,7 @@ export default function ListFilterBar({
|
|||||||
leftPanel,
|
leftPanel,
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
|
onOpenChange,
|
||||||
filters,
|
filters,
|
||||||
className,
|
className,
|
||||||
icon,
|
icon,
|
||||||
@ -79,7 +80,12 @@ export default function ListFilterBar({
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex gap-5 items-center">
|
<div className="flex gap-5 items-center">
|
||||||
{showFilter && (
|
{showFilter && (
|
||||||
<FilterPopover value={value} onChange={onChange} filters={filters}>
|
<FilterPopover
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
filters={filters}
|
||||||
|
onOpenChange={onOpenChange}
|
||||||
|
>
|
||||||
<FilterButton count={filterCount}></FilterButton>
|
<FilterButton count={filterCount}></FilterButton>
|
||||||
</FilterPopover>
|
</FilterPopover>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
import { useHandleFilterSubmit } from '@/components/list-filter-bar/use-handle-filter-submit';
|
import { useHandleFilterSubmit } from '@/components/list-filter-bar/use-handle-filter-submit';
|
||||||
import { IDocumentInfo } from '@/interfaces/database/document';
|
import {
|
||||||
|
IDocumentInfo,
|
||||||
|
IDocumentInfoFilter,
|
||||||
|
} from '@/interfaces/database/document';
|
||||||
import {
|
import {
|
||||||
IChangeParserConfigRequestBody,
|
IChangeParserConfigRequestBody,
|
||||||
IDocumentMetaRequestBody,
|
IDocumentMetaRequestBody,
|
||||||
@ -10,7 +13,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|||||||
import { useDebounce } from 'ahooks';
|
import { useDebounce } from 'ahooks';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import { useCallback } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import { useParams } from 'umi';
|
import { useParams } from 'umi';
|
||||||
import {
|
import {
|
||||||
useGetPaginationWithRouter,
|
useGetPaginationWithRouter,
|
||||||
@ -30,7 +33,7 @@ export const enum DocumentApiAction {
|
|||||||
SaveDocumentName = 'saveDocumentName',
|
SaveDocumentName = 'saveDocumentName',
|
||||||
SetDocumentParser = 'setDocumentParser',
|
SetDocumentParser = 'setDocumentParser',
|
||||||
SetDocumentMeta = 'setDocumentMeta',
|
SetDocumentMeta = 'setDocumentMeta',
|
||||||
FetchAllDocumentList = 'fetchAllDocumentList',
|
FetchDocumentFilter = 'fetchDocumentFilter',
|
||||||
CreateDocument = 'createDocument',
|
CreateDocument = 'createDocument',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +84,10 @@ export const useFetchDocumentList = () => {
|
|||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const debouncedSearchString = useDebounce(searchString, { wait: 500 });
|
const debouncedSearchString = useDebounce(searchString, { wait: 500 });
|
||||||
const { filterValue, handleFilterSubmit } = useHandleFilterSubmit();
|
const { filterValue, handleFilterSubmit } = useHandleFilterSubmit();
|
||||||
|
const [docs, setDocs] = useState<IDocumentInfo[]>([]);
|
||||||
|
const isLoop = useMemo(() => {
|
||||||
|
return docs.some((doc) => doc.run === '1');
|
||||||
|
}, [docs]);
|
||||||
|
|
||||||
const { data, isFetching: loading } = useQuery<{
|
const { data, isFetching: loading } = useQuery<{
|
||||||
docs: IDocumentInfo[];
|
docs: IDocumentInfo[];
|
||||||
@ -93,7 +100,7 @@ export const useFetchDocumentList = () => {
|
|||||||
filterValue,
|
filterValue,
|
||||||
],
|
],
|
||||||
initialData: { docs: [], total: 0 },
|
initialData: { docs: [], total: 0 },
|
||||||
// refetchInterval: 15000,
|
refetchInterval: isLoop ? 5000 : false,
|
||||||
enabled: !!knowledgeId || !!id,
|
enabled: !!knowledgeId || !!id,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const ret = await listDocument(
|
const ret = await listDocument(
|
||||||
@ -104,7 +111,7 @@ export const useFetchDocumentList = () => {
|
|||||||
page: pagination.current,
|
page: pagination.current,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
types: filterValue.type,
|
suffix: filterValue.type,
|
||||||
run_status: filterValue.run,
|
run_status: filterValue.run,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -118,7 +125,9 @@ export const useFetchDocumentList = () => {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
useMemo(() => {
|
||||||
|
setDocs(data.docs);
|
||||||
|
}, [data.docs]);
|
||||||
const onInputChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(
|
const onInputChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(
|
||||||
(e) => {
|
(e) => {
|
||||||
setPagination({ page: 1 });
|
setPagination({ page: 1 });
|
||||||
@ -139,34 +148,48 @@ export const useFetchDocumentList = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useFetchAllDocumentList() {
|
// get document filter
|
||||||
|
export const useGetDocumentFilter = (): {
|
||||||
|
filter: IDocumentInfoFilter;
|
||||||
|
onOpenChange: (open: boolean) => void;
|
||||||
|
} => {
|
||||||
|
const { knowledgeId } = useGetKnowledgeSearchParams();
|
||||||
|
const { searchString } = useHandleSearchChange();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const { data, isFetching: loading } = useQuery<{
|
const debouncedSearchString = useDebounce(searchString, { wait: 500 });
|
||||||
docs: IDocumentInfo[];
|
const [open, setOpen] = useState<number>(0);
|
||||||
total: number;
|
const { data } = useQuery({
|
||||||
}>({
|
queryKey: [
|
||||||
queryKey: [DocumentApiAction.FetchAllDocumentList],
|
DocumentApiAction.FetchDocumentFilter,
|
||||||
initialData: { docs: [], total: 0 },
|
debouncedSearchString,
|
||||||
refetchInterval: 15000,
|
knowledgeId,
|
||||||
enabled: !!id,
|
open,
|
||||||
|
],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const ret = await listDocument({
|
const { data } = await kbService.documentFilter({
|
||||||
kb_id: id,
|
kb_id: knowledgeId || id,
|
||||||
|
keywords: debouncedSearchString,
|
||||||
});
|
});
|
||||||
if (ret.data.code === 0) {
|
if (data.code === 0) {
|
||||||
return ret.data.data;
|
return data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
docs: [],
|
|
||||||
total: 0,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const handleOnpenChange = (e: boolean) => {
|
||||||
return { data, loading };
|
if (e) {
|
||||||
}
|
const currentOpen = open + 1;
|
||||||
|
setOpen(currentOpen);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
filter: data?.filter || {
|
||||||
|
run_status: {},
|
||||||
|
suffix: {},
|
||||||
|
},
|
||||||
|
onOpenChange: handleOnpenChange,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// update document status
|
||||||
export const useSetDocumentStatus = () => {
|
export const useSetDocumentStatus = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
@ -200,6 +223,7 @@ export const useSetDocumentStatus = () => {
|
|||||||
return { setDocumentStatus: mutateAsync, data, loading };
|
return { setDocumentStatus: mutateAsync, data, loading };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This hook is used to run a document by its IDs
|
||||||
export const useRunDocument = () => {
|
export const useRunDocument = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
|||||||
@ -47,3 +47,8 @@ interface GraphRag {
|
|||||||
resolution?: boolean;
|
resolution?: boolean;
|
||||||
use_graphrag?: boolean;
|
use_graphrag?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type IDocumentInfoFilter = {
|
||||||
|
run_status: Record<number, number>;
|
||||||
|
suffix: Record<string, number>;
|
||||||
|
};
|
||||||
|
|||||||
@ -21,6 +21,6 @@ export interface IFetchKnowledgeListRequestParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IFetchDocumentListRequestBody {
|
export interface IFetchDocumentListRequestBody {
|
||||||
types?: string[];
|
suffix?: string[];
|
||||||
run_status?: string[];
|
run_status?: string[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -407,6 +407,11 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
|
|||||||
mind: 'Mind map',
|
mind: 'Mind map',
|
||||||
question: 'Question',
|
question: 'Question',
|
||||||
questionTip: `If there are given questions, the embedding of the chunk will be based on them.`,
|
questionTip: `If there are given questions, the embedding of the chunk will be based on them.`,
|
||||||
|
chunkResult: 'Chunk Result',
|
||||||
|
chunkResultTip: `View the chunked segments used for embedding and retrieval.`,
|
||||||
|
enable: 'Enable',
|
||||||
|
disable: 'Disable',
|
||||||
|
delete: 'Delete',
|
||||||
},
|
},
|
||||||
chat: {
|
chat: {
|
||||||
newConversation: 'New conversation',
|
newConversation: 'New conversation',
|
||||||
|
|||||||
@ -396,6 +396,11 @@ export default {
|
|||||||
mind: '心智圖',
|
mind: '心智圖',
|
||||||
question: '問題',
|
question: '問題',
|
||||||
questionTip: `如果存在給定的問題,則區塊的嵌入將基於它們。`,
|
questionTip: `如果存在給定的問題,則區塊的嵌入將基於它們。`,
|
||||||
|
chunkResult: '切片結果',
|
||||||
|
chunkResultTip: `查看用於嵌入和召回的切片段落`,
|
||||||
|
enable: '啟用',
|
||||||
|
disable: '禁用',
|
||||||
|
delete: '删除',
|
||||||
},
|
},
|
||||||
chat: {
|
chat: {
|
||||||
newConversation: '新會話',
|
newConversation: '新會話',
|
||||||
|
|||||||
@ -414,6 +414,11 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
|||||||
mind: '思维导图',
|
mind: '思维导图',
|
||||||
question: '问题',
|
question: '问题',
|
||||||
questionTip: `如果有给定的问题,则块的嵌入将基于它们。`,
|
questionTip: `如果有给定的问题,则块的嵌入将基于它们。`,
|
||||||
|
chunkResult: '切片结果',
|
||||||
|
chunkResultTip: `查看用于嵌入和召回的切片段落。`,
|
||||||
|
enable: '启用',
|
||||||
|
disable: '禁用',
|
||||||
|
delete: '删除',
|
||||||
},
|
},
|
||||||
chat: {
|
chat: {
|
||||||
newConversation: '新会话',
|
newConversation: '新会话',
|
||||||
|
|||||||
@ -24,11 +24,13 @@
|
|||||||
|
|
||||||
.chunkCard {
|
.chunkCard {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
padding: 18px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cardSelected {
|
.cardSelected {
|
||||||
background-color: @selectedBackgroundColor;
|
background-color: @selectedBackgroundColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cardSelectedDark {
|
.cardSelectedDark {
|
||||||
background-color: #ffffff2f;
|
background-color: #ffffff2f;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,18 @@
|
|||||||
import Image from '@/components/image';
|
import Image from '@/components/image';
|
||||||
|
import { useTheme } from '@/components/theme-provider';
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from '@/components/ui/popover';
|
||||||
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { IChunk } from '@/interfaces/database/knowledge';
|
import { IChunk } from '@/interfaces/database/knowledge';
|
||||||
import { Card, Checkbox, CheckboxProps, Flex, Popover, Switch } from 'antd';
|
import { CheckedState } from '@radix-ui/react-checkbox';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import DOMPurify from 'dompurify';
|
import DOMPurify from 'dompurify';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { useTheme } from '@/components/theme-provider';
|
|
||||||
import { ChunkTextMode } from '../../constant';
|
import { ChunkTextMode } from '../../constant';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
@ -39,8 +46,8 @@ const ChunkCard = ({
|
|||||||
switchChunk(available === 0 ? 1 : 0, [item.chunk_id]);
|
switchChunk(available === 0 ? 1 : 0, [item.chunk_id]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCheck: CheckboxProps['onChange'] = (e) => {
|
const handleCheck = (e: CheckedState) => {
|
||||||
handleCheckboxClick(item.chunk_id, e.target.checked);
|
handleCheckboxClick(item.chunk_id, e === 'indeterminate' ? false : e);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleContentDoubleClick = () => {
|
const handleContentDoubleClick = () => {
|
||||||
@ -54,7 +61,7 @@ const ChunkCard = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setEnabled(available === 1);
|
setEnabled(available === 1);
|
||||||
}, [available]);
|
}, [available]);
|
||||||
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
className={classNames(styles.chunkCard, {
|
className={classNames(styles.chunkCard, {
|
||||||
@ -62,19 +69,34 @@ const ChunkCard = ({
|
|||||||
selected,
|
selected,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Flex gap={'middle'} justify={'space-between'}>
|
<div className="flex items-start justify-between gap-2">
|
||||||
<Checkbox onChange={handleCheck} checked={checked}></Checkbox>
|
<Checkbox onCheckedChange={handleCheck} checked={checked}></Checkbox>
|
||||||
{item.image_id && (
|
{item.image_id && (
|
||||||
<Popover
|
<Popover open={open}>
|
||||||
placement="right"
|
<PopoverTrigger
|
||||||
content={
|
asChild
|
||||||
<Image id={item.image_id} className={styles.imagePreview}></Image>
|
onMouseEnter={() => setOpen(true)}
|
||||||
}
|
onMouseLeave={() => setOpen(false)}
|
||||||
>
|
>
|
||||||
|
<div>
|
||||||
<Image id={item.image_id} className={styles.image}></Image>
|
<Image id={item.image_id} className={styles.image}></Image>
|
||||||
|
</div>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent
|
||||||
|
className="p-0"
|
||||||
|
align={'start'}
|
||||||
|
side={'right'}
|
||||||
|
sideOffset={-20}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Image
|
||||||
|
id={item.image_id}
|
||||||
|
className={styles.imagePreview}
|
||||||
|
></Image>
|
||||||
|
</div>
|
||||||
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<section
|
<section
|
||||||
onDoubleClick={handleContentDoubleClick}
|
onDoubleClick={handleContentDoubleClick}
|
||||||
onClick={handleContentClick}
|
onClick={handleContentClick}
|
||||||
@ -89,11 +111,15 @@ const ChunkCard = ({
|
|||||||
})}
|
})}
|
||||||
></div>
|
></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Switch checked={enabled} onChange={onChange} />
|
<Switch
|
||||||
|
checked={enabled}
|
||||||
|
onCheckedChange={onChange}
|
||||||
|
aria-readonly
|
||||||
|
className="!m-0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Flex>
|
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Checkbox } from '@/components/ui/checkbox';
|
|||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { Ban, CircleCheck, Trash2 } from 'lucide-react';
|
import { Ban, CircleCheck, Trash2 } from 'lucide-react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
type ICheckboxSetProps = {
|
type ICheckboxSetProps = {
|
||||||
selectAllChunk: (e: any) => void;
|
selectAllChunk: (e: any) => void;
|
||||||
@ -11,6 +12,7 @@ type ICheckboxSetProps = {
|
|||||||
};
|
};
|
||||||
export default (props: ICheckboxSetProps) => {
|
export default (props: ICheckboxSetProps) => {
|
||||||
const { selectAllChunk, removeChunk, switchChunk, checked } = props;
|
const { selectAllChunk, removeChunk, switchChunk, checked } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
const handleSelectAllCheck = useCallback(
|
const handleSelectAllCheck = useCallback(
|
||||||
(e: any) => {
|
(e: any) => {
|
||||||
console.log('eee=', e);
|
console.log('eee=', e);
|
||||||
@ -33,35 +35,35 @@ export default (props: ICheckboxSetProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-[40px] p-4">
|
<div className="flex gap-[40px] p-4">
|
||||||
<div className="flex items-center gap-3 cursor-pointer">
|
<div className="flex items-center gap-3 cursor-pointer text-muted-foreground hover:text-white">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="all_chunks_checkbox"
|
id="all_chunks_checkbox"
|
||||||
onCheckedChange={handleSelectAllCheck}
|
onCheckedChange={handleSelectAllCheck}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
className=" data-[state=checked]:bg-[#1668dc] data-[state=checked]:border-[#1668dc] data-[state=checked]:text-white"
|
className=" data-[state=checked]:bg-white data-[state=checked]:border-white data-[state=checked]:text-black border-muted-foreground text-muted-foreground hover:text-black hover:border-white "
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="all_chunks_checkbox">All Chunks</Label>
|
<Label htmlFor="all_chunks_checkbox">{t('chunk.selectAll')}</Label>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="flex items-center cursor-pointer"
|
className="flex items-center cursor-pointer text-muted-foreground hover:text-white"
|
||||||
onClick={handleEnabledClick}
|
onClick={handleEnabledClick}
|
||||||
>
|
>
|
||||||
<CircleCheck size={16} />
|
<CircleCheck size={16} />
|
||||||
<span className="block ml-1">Enable</span>
|
<span className="block ml-1">{t('chunk.enable')}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="flex items-center cursor-pointer"
|
className="flex items-center cursor-pointer text-muted-foreground hover:text-white"
|
||||||
onClick={handleDisabledClick}
|
onClick={handleDisabledClick}
|
||||||
>
|
>
|
||||||
<Ban size={16} />
|
<Ban size={16} />
|
||||||
<span className="block ml-1">Disable</span>
|
<span className="block ml-1">{t('chunk.disable')}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="flex items-center text-red-500 cursor-pointer"
|
className="flex items-center cursor-pointer text-red-400 hover:text-red-500"
|
||||||
onClick={handleDeleteClick}
|
onClick={handleDeleteClick}
|
||||||
>
|
>
|
||||||
<Trash2 size={16} />
|
<Trash2 size={16} />
|
||||||
<span className="block ml-1">Delete</span>
|
<span className="block ml-1">{t('chunk.delete')}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -183,9 +183,9 @@ const Chunk = () => {
|
|||||||
<Spin spinning={loading} className={styles.spin} size="large">
|
<Spin spinning={loading} className={styles.spin} size="large">
|
||||||
<div className="h-[100px] flex flex-col justify-end pb-[5px]">
|
<div className="h-[100px] flex flex-col justify-end pb-[5px]">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-[24px]">Chunk Result</h2>
|
<h2 className="text-[24px]">{t('chunk.chunkResult')}</h2>
|
||||||
<div className="text-[14px] text-[#979AAB]">
|
<div className="text-[14px] text-[#979AAB]">
|
||||||
View the chunked segments used for embedding and retrieval.
|
{t('chunk.chunkResultTip')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -12,9 +12,7 @@ import {
|
|||||||
} from '@/components/ui/dropdown-menu';
|
} from '@/components/ui/dropdown-menu';
|
||||||
import { useRowSelection } from '@/hooks/logic-hooks/use-row-selection';
|
import { useRowSelection } from '@/hooks/logic-hooks/use-row-selection';
|
||||||
import { useFetchDocumentList } from '@/hooks/use-document-request';
|
import { useFetchDocumentList } from '@/hooks/use-document-request';
|
||||||
import { IDocumentInfo } from '@/interfaces/database/document';
|
|
||||||
import { Upload } from 'lucide-react';
|
import { Upload } from 'lucide-react';
|
||||||
import { useMemo, useState } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { DatasetTable } from './dataset-table';
|
import { DatasetTable } from './dataset-table';
|
||||||
import { useBulkOperateDataset } from './use-bulk-operate-dataset';
|
import { useBulkOperateDataset } from './use-bulk-operate-dataset';
|
||||||
@ -42,16 +40,7 @@ export default function Dataset() {
|
|||||||
handleFilterSubmit,
|
handleFilterSubmit,
|
||||||
loading,
|
loading,
|
||||||
} = useFetchDocumentList();
|
} = useFetchDocumentList();
|
||||||
const { filters, documents: filteredDocuments } = useSelectDatasetFilters();
|
const { filters, onOpenChange } = useSelectDatasetFilters();
|
||||||
const [datasetInfo, setDatasetInfo] = useState<IDocumentInfo[]>(documents);
|
|
||||||
|
|
||||||
useMemo(() => {
|
|
||||||
setDatasetInfo(documents);
|
|
||||||
}, [documents]);
|
|
||||||
|
|
||||||
useMemo(() => {
|
|
||||||
setDatasetInfo(filteredDocuments);
|
|
||||||
}, [filteredDocuments]);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
createLoading,
|
createLoading,
|
||||||
@ -69,7 +58,6 @@ export default function Dataset() {
|
|||||||
rowSelection,
|
rowSelection,
|
||||||
setRowSelection,
|
setRowSelection,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="p-5">
|
<section className="p-5">
|
||||||
<ListFilterBar
|
<ListFilterBar
|
||||||
@ -78,13 +66,13 @@ export default function Dataset() {
|
|||||||
searchString={searchString}
|
searchString={searchString}
|
||||||
value={filterValue}
|
value={filterValue}
|
||||||
onChange={handleFilterSubmit}
|
onChange={handleFilterSubmit}
|
||||||
|
onOpenChange={onOpenChange}
|
||||||
filters={filters}
|
filters={filters}
|
||||||
leftPanel={
|
leftPanel={
|
||||||
<div className="items-start">
|
<div className="items-start">
|
||||||
<div className="pb-1">Dataset</div>
|
<div className="pb-1">{t('knowledgeDetails.dataset')}</div>
|
||||||
<div className="text-text-sub-title-invert text-sm">
|
<div className="text-text-sub-title-invert text-sm">
|
||||||
Please wait for your files to finish parsing before starting an
|
{t('knowledgeDetails.datasetDescription')}
|
||||||
AI-powered chat.
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@ -111,7 +99,7 @@ export default function Dataset() {
|
|||||||
<BulkOperateBar list={list} count={selectedCount}></BulkOperateBar>
|
<BulkOperateBar list={list} count={selectedCount}></BulkOperateBar>
|
||||||
)}
|
)}
|
||||||
<DatasetTable
|
<DatasetTable
|
||||||
documents={datasetInfo}
|
documents={documents}
|
||||||
pagination={pagination}
|
pagination={pagination}
|
||||||
setPagination={setPagination}
|
setPagination={setPagination}
|
||||||
rowSelection={rowSelection}
|
rowSelection={rowSelection}
|
||||||
|
|||||||
@ -1,30 +1,36 @@
|
|||||||
import { useFetchAllDocumentList } from '@/hooks/use-document-request';
|
import { FilterCollection } from '@/components/list-filter-bar/interface';
|
||||||
import { groupListByType } from '@/utils/dataset-util';
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
|
import { useGetDocumentFilter } from '@/hooks/use-document-request';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
export function useSelectDatasetFilters() {
|
export function useSelectDatasetFilters() {
|
||||||
const {
|
const { t } = useTranslate('knowledgeDetails');
|
||||||
data: { docs: documents },
|
const { filter, onOpenChange } = useGetDocumentFilter();
|
||||||
} = useFetchAllDocumentList();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const fileTypes = useMemo(() => {
|
const fileTypes = useMemo(() => {
|
||||||
return groupListByType(documents, 'type', 'type');
|
if (filter.suffix) {
|
||||||
}, [documents]);
|
return Object.keys(filter.suffix).map((x) => ({
|
||||||
|
id: x,
|
||||||
const fileStatus = useMemo(() => {
|
label: x.toUpperCase(),
|
||||||
return groupListByType(documents, 'run', 'run').map((x) => ({
|
count: filter.suffix[x],
|
||||||
...x,
|
|
||||||
label: t(`knowledgeDetails.runningStatus${x.label}`),
|
|
||||||
}));
|
}));
|
||||||
}, [documents, t]);
|
}
|
||||||
const filters = useMemo(() => {
|
}, [filter.suffix]);
|
||||||
|
const fileStatus = useMemo(() => {
|
||||||
|
if (filter.run_status) {
|
||||||
|
return Object.keys(filter.run_status).map((x) => ({
|
||||||
|
id: x,
|
||||||
|
label: t(`runningStatus${x}`),
|
||||||
|
count: filter.run_status[x as unknown as number],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}, [filter.run_status, t]);
|
||||||
|
const filters: FilterCollection[] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{ field: 'type', label: 'File Type', list: fileTypes },
|
{ field: 'type', label: 'File Type', list: fileTypes },
|
||||||
{ field: 'run', label: 'Status', list: fileStatus },
|
{ field: 'run', label: 'Status', list: fileStatus },
|
||||||
];
|
] as FilterCollection[];
|
||||||
}, [fileStatus, fileTypes]);
|
}, [fileStatus, fileTypes]);
|
||||||
|
|
||||||
return { fileTypes, fileStatus, filters, documents };
|
return { filters, onOpenChange };
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,9 +35,8 @@ export default function RetrievalTesting() {
|
|||||||
<div className="p-5">
|
<div className="p-5">
|
||||||
<section className="flex justify-between items-center">
|
<section className="flex justify-between items-center">
|
||||||
<TopTitle
|
<TopTitle
|
||||||
title={'Configuration'}
|
title={'Retrieval testing'}
|
||||||
description={` Update your knowledge base configuration here, particularly the chunk
|
description={`Conduct a retrieval test to check if RAGFlow can recover the intended content for the LLM.`}
|
||||||
method.`}
|
|
||||||
></TopTitle>
|
></TopTitle>
|
||||||
{/* <Button>Save as Preset</Button> */}
|
{/* <Button>Save as Preset</Button> */}
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -155,6 +155,10 @@ const methods = {
|
|||||||
url: listTagByKnowledgeIds,
|
url: listTagByKnowledgeIds,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
},
|
},
|
||||||
|
documentFilter: {
|
||||||
|
url: api.get_dataset_filter,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const kbService = registerServer<keyof typeof methods>(methods, request);
|
const kbService = registerServer<keyof typeof methods>(methods, request);
|
||||||
@ -188,4 +192,7 @@ export const listDocument = (
|
|||||||
body?: IFetchDocumentListRequestBody,
|
body?: IFetchDocumentListRequestBody,
|
||||||
) => request.post(api.get_document_list, { data: body || {}, params });
|
) => request.post(api.get_document_list, { data: body || {}, params });
|
||||||
|
|
||||||
|
export const documentFilter = (kb_id: string) =>
|
||||||
|
request.post(api.get_dataset_filter, { kb_id });
|
||||||
|
|
||||||
export default kbService;
|
export default kbService;
|
||||||
|
|||||||
@ -78,6 +78,7 @@ export default {
|
|||||||
upload_and_parse: `${api_host}/document/upload_and_parse`,
|
upload_and_parse: `${api_host}/document/upload_and_parse`,
|
||||||
parse: `${api_host}/document/parse`,
|
parse: `${api_host}/document/parse`,
|
||||||
setMeta: `${api_host}/document/set_meta`,
|
setMeta: `${api_host}/document/set_meta`,
|
||||||
|
get_dataset_filter: `${api_host}/document/filter`,
|
||||||
|
|
||||||
// chat
|
// chat
|
||||||
setDialog: `${api_host}/dialog/set`,
|
setDialog: `${api_host}/dialog/set`,
|
||||||
|
|||||||
Reference in New Issue
Block a user