Fix: Dataset parse logic (#12330)

### What problem does this PR solve?

Fix: Dataset  logic of parser

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
chanx
2025-12-30 19:53:00 +08:00
committed by GitHub
parent 2fccf3924d
commit a7e466142d
9 changed files with 126 additions and 76 deletions

View File

@ -109,6 +109,19 @@ export const SelectWithSearch = forwardRef<
}
}, [options, value]);
const showSearch = useMemo(() => {
if (Array.isArray(options) && options.length > 5) {
return true;
}
if (Array.isArray(options)) {
const optionsNum = options.reduce((acc, option) => {
return acc + (option?.options?.length || 0);
}, 0);
return optionsNum > 5;
}
return false;
}, [options]);
const handleSelect = useCallback(
(val: string) => {
setValue(val);
@ -179,7 +192,7 @@ export const SelectWithSearch = forwardRef<
align="start"
>
<Command className="p-5">
{options && options.length > 5 && (
{showSearch && (
<CommandInput
placeholder={t('common.search') + '...'}
className=" placeholder:text-text-disabled"

View File

@ -147,6 +147,8 @@ Procedural Memory: Learned skills, habits, and automated procedures.`,
action: 'Action',
},
config: {
memorySizeTooltip: `Accounts for each message's content + its embedding vector (≈ Content + Dimensions × 8 Bytes).
Example: A 1 KB message with 1024-dim embedding uses ~9 KB. The 5 MB default limit holds ~500 such messages.`,
avatar: 'Avatar',
description: 'Description',
memorySize: 'Memory size',

View File

@ -124,7 +124,6 @@ export default {
forgetMessageTip: '确定遗忘吗?',
messageDescription: '记忆提取使用高级设置中的提示词和温度值进行配置。',
copied: '已复制!',
contentEmbed: '内容嵌入',
content: '内容',
delMessageWarn: `遗忘后,代理将无法检索此消息。`,
forgetMessage: '遗忘消息',
@ -138,6 +137,8 @@ export default {
action: '操作',
},
config: {
memorySizeTooltip: `记录每条消息的内容 + 其嵌入向量(≈ 内容 + 维度 × 8 字节)。
例如:一条带有 1024 维嵌入的 1 KB 消息大约使用 9 KB。5 MB 的默认限制大约可容纳 500 条此类消息。`,
avatar: '头像',
description: '描述',
memorySize: '记忆大小',

View File

@ -79,6 +79,7 @@ export default function Dataset() {
useRowSelection();
const {
chunkNum,
list,
visible: reparseDialogVisible,
hideModal: hideReparseDialogModal,
@ -218,7 +219,7 @@ export default function Dataset() {
// hidden={isZeroChunk || isRunning}
hidden={true}
handleOperationIconClick={handleOperationIconClick}
chunk_num={0}
chunk_num={chunkNum}
visible={reparseDialogVisible}
hideModal={hideReparseDialogModal}
></ReparseDialog>

View File

@ -183,7 +183,7 @@ export function ParsingStatusCell({
)}
{reparseDialogVisible && (
<ReparseDialog
hidden={isZeroChunk || isRunning}
hidden={isRunning}
// hidden={false}
handleOperationIconClick={handleOperationIconClick}
chunk_num={chunk_num}

View File

@ -2,12 +2,14 @@ import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
import {
DynamicForm,
DynamicFormRef,
FormFieldConfig,
FormFieldType,
} from '@/components/dynamic-form';
import { Checkbox } from '@/components/ui/checkbox';
import { DialogProps } from '@radix-ui/react-dialog';
import { t } from 'i18next';
import { memo, useCallback, useEffect, useRef } from 'react';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { ControllerRenderProps } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
export const ReparseDialog = memo(
({
@ -26,18 +28,77 @@ export const ReparseDialog = memo(
hideModal: () => void;
hidden?: boolean;
}) => {
// const [formInstance, setFormInstance] = useState<DynamicFormRef | null>(
// null,
// );
const [defaultValues, setDefaultValues] = useState<any>(null);
const [fields, setFields] = useState<FormFieldConfig[]>([]);
const { t } = useTranslation();
const handleOperationIconClickRef = useRef(handleOperationIconClick);
const hiddenRef = useRef(hidden);
// const formCallbackRef = useCallback((node: DynamicFormRef | null) => {
// if (node) {
// setFormInstance(node);
// console.log('Form instance assigned:', node);
// } else {
// console.log('Form instance removed');
// }
// }, []);
useEffect(() => {
handleOperationIconClickRef.current = handleOperationIconClick;
hiddenRef.current = hidden;
});
useEffect(() => {
if (hiddenRef.current) {
handleOperationIconClickRef.current();
}
}, []);
useEffect(() => {
setDefaultValues({
delete: chunk_num > 0,
apply_kb: false,
});
const deleteField = {
name: 'delete',
label: '',
type: FormFieldType.Checkbox,
render: (fieldProps: ControllerRenderProps) => (
<div className="flex items-center text-text-secondary p-5 border border-border-button rounded-lg">
<Checkbox
{...fieldProps}
checked={fieldProps.value}
onCheckedChange={(checked: boolean) => {
fieldProps.onChange(checked);
}}
/>
<span className="ml-2">
{chunk_num > 0
? t(`knowledgeDetails.redo`, {
chunkNum: chunk_num,
})
: t('knowledgeDetails.redoAll')}
</span>
</div>
),
};
const applyKBField = {
name: 'apply_kb',
label: '',
type: FormFieldType.Checkbox,
defaultValue: false,
render: (fieldProps: ControllerRenderProps) => (
<div className="flex items-center text-text-secondary p-5 border border-border-button rounded-lg">
<Checkbox
{...fieldProps}
checked={fieldProps.value}
onCheckedChange={(checked: boolean) => {
fieldProps.onChange(checked);
}}
/>
<span className="ml-2">
{t('knowledgeDetails.applyAutoMetadataSettings')}
</span>
</div>
),
};
if (chunk_num > 0) {
setFields([deleteField, applyKBField]);
}
if (chunk_num <= 0) {
setFields([applyKBField]);
}
}, [chunk_num, t]);
const formCallbackRef = useRef<DynamicFormRef>(null);
@ -68,12 +129,6 @@ export const ReparseDialog = memo(
}
}, [formCallbackRef, handleOperationIconClick]);
useEffect(() => {
if (hidden) {
handleOperationIconClick();
}
}, []);
return (
<ConfirmDeleteDialog
title={t(`knowledgeDetails.parseFile`)}
@ -91,48 +146,8 @@ export const ReparseDialog = memo(
console.log('submit', data);
}}
ref={formCallbackRef}
fields={[
{
name: 'delete',
label: '',
type: FormFieldType.Checkbox,
render: (fieldProps) => (
<div className="flex items-center text-text-secondary p-5 border border-border-button rounded-lg">
<Checkbox
{...fieldProps}
onCheckedChange={(checked: boolean) => {
fieldProps.onChange(checked);
}}
/>
<span className="ml-2">
{chunk_num > 0
? t(`knowledgeDetails.redo`, {
chunkNum: chunk_num,
})
: t('knowledgeDetails.redoAll')}
</span>
</div>
),
},
{
name: 'apply_kb',
label: '',
type: FormFieldType.Checkbox,
render: (fieldProps) => (
<div className="flex items-center text-text-secondary p-5 border border-border-button rounded-lg">
<Checkbox
{...fieldProps}
onCheckedChange={(checked: boolean) => {
fieldProps.onChange(checked);
}}
/>
<span className="ml-2">
{t('knowledgeDetails.applyAutoMetadataSettings')}
</span>
</div>
),
},
]}
fields={fields}
defaultValues={defaultValues}
>
{/* <DynamicForm.CancelButton
handleCancel={() => handleOperationIconClick(false)}

View File

@ -10,7 +10,7 @@ import {
} from '@/hooks/use-document-request';
import { IDocumentInfo } from '@/interfaces/database/document';
import { Ban, CircleCheck, CircleX, Play, Trash2 } from 'lucide-react';
import { useCallback } from 'react';
import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { toast } from 'sonner';
import { DocumentType, RunningStatus } from './constant';
@ -32,6 +32,16 @@ export function useBulkOperateDataset({
const { setDocumentStatus } = useSetDocumentStatus();
const { removeDocument } = useRemoveDocument();
const { visible, showModal, hideModal } = useSetModalState();
const chunkNum = useMemo(() => {
if (!documents.length) {
return 0;
}
return documents.reduce((acc, cur) => {
return acc + cur.chunk_num;
}, 0);
}, [documents]);
const runDocument = useCallback(
async (run: number, option?: { delete: boolean; apply_kb: boolean }) => {
const nonVirtualKeys = selectedRowKeys.filter(
@ -132,5 +142,5 @@ export function useBulkOperateDataset({
},
];
return { list, visible, hideModal, showModal, handleRunClick };
return { chunkNum, list, visible, hideModal, showModal, handleRunClick };
}

View File

@ -38,21 +38,27 @@ interface ProcessLogModalProps {
}
const InfoItem: React.FC<{
overflowTip?: boolean;
label: string;
value: string | React.ReactNode;
className?: string;
}> = ({ label, value, className = '' }) => {
}> = ({ label, value, className = '', overflowTip = false }) => {
return (
<div className={`flex flex-col mb-4 ${className}`}>
<span className="text-text-secondary text-sm">{label}</span>
<Tooltip>
<TooltipTrigger asChild>
<span className="text-text-primary mt-1 truncate w-full">
{value}
</span>
</TooltipTrigger>
<TooltipContent>{value}</TooltipContent>
</Tooltip>
{overflowTip && (
<Tooltip>
<TooltipTrigger asChild>
<span className="text-text-primary mt-1 truncate w-full">
{value}
</span>
</TooltipTrigger>
<TooltipContent>{value}</TooltipContent>
</Tooltip>
)}
{!overflowTip && (
<span className="text-text-primary mt-1 truncate w-full">{value}</span>
)}
</div>
);
};
@ -139,6 +145,7 @@ const ProcessLogModal: React.FC<ProcessLogModalProps> = ({
return (
<div className="w-1/2" key={key}>
<InfoItem
overflowTip={true}
label={t(key)}
value={logInfo[key as keyof typeof logInfo]}
/>

View File

@ -92,6 +92,7 @@ export const MemoryModelForm = () => {
label: t('memory.config.memorySize') + ' (Bytes)',
type: FormFieldType.Number,
horizontal: true,
tooltip: t('memory.config.memorySizeTooltip'),
// placeholder: t('memory.config.memorySizePlaceholder'),
required: false,
}}