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]); }, [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( const handleSelect = useCallback(
(val: string) => { (val: string) => {
setValue(val); setValue(val);
@ -179,7 +192,7 @@ export const SelectWithSearch = forwardRef<
align="start" align="start"
> >
<Command className="p-5"> <Command className="p-5">
{options && options.length > 5 && ( {showSearch && (
<CommandInput <CommandInput
placeholder={t('common.search') + '...'} placeholder={t('common.search') + '...'}
className=" placeholder:text-text-disabled" className=" placeholder:text-text-disabled"

View File

@ -147,6 +147,8 @@ Procedural Memory: Learned skills, habits, and automated procedures.`,
action: 'Action', action: 'Action',
}, },
config: { 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', avatar: 'Avatar',
description: 'Description', description: 'Description',
memorySize: 'Memory size', memorySize: 'Memory size',

View File

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

View File

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

View File

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

View File

@ -2,12 +2,14 @@ import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
import { import {
DynamicForm, DynamicForm,
DynamicFormRef, DynamicFormRef,
FormFieldConfig,
FormFieldType, FormFieldType,
} from '@/components/dynamic-form'; } from '@/components/dynamic-form';
import { Checkbox } from '@/components/ui/checkbox'; import { Checkbox } from '@/components/ui/checkbox';
import { DialogProps } from '@radix-ui/react-dialog'; import { DialogProps } from '@radix-ui/react-dialog';
import { t } from 'i18next'; import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { memo, useCallback, useEffect, useRef } from 'react'; import { ControllerRenderProps } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
export const ReparseDialog = memo( export const ReparseDialog = memo(
({ ({
@ -26,18 +28,77 @@ export const ReparseDialog = memo(
hideModal: () => void; hideModal: () => void;
hidden?: boolean; hidden?: boolean;
}) => { }) => {
// const [formInstance, setFormInstance] = useState<DynamicFormRef | null>( const [defaultValues, setDefaultValues] = useState<any>(null);
// null, const [fields, setFields] = useState<FormFieldConfig[]>([]);
// ); const { t } = useTranslation();
const handleOperationIconClickRef = useRef(handleOperationIconClick);
const hiddenRef = useRef(hidden);
// const formCallbackRef = useCallback((node: DynamicFormRef | null) => { useEffect(() => {
// if (node) { handleOperationIconClickRef.current = handleOperationIconClick;
// setFormInstance(node); hiddenRef.current = hidden;
// console.log('Form instance assigned:', node); });
// } else {
// console.log('Form instance removed'); 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); const formCallbackRef = useRef<DynamicFormRef>(null);
@ -68,12 +129,6 @@ export const ReparseDialog = memo(
} }
}, [formCallbackRef, handleOperationIconClick]); }, [formCallbackRef, handleOperationIconClick]);
useEffect(() => {
if (hidden) {
handleOperationIconClick();
}
}, []);
return ( return (
<ConfirmDeleteDialog <ConfirmDeleteDialog
title={t(`knowledgeDetails.parseFile`)} title={t(`knowledgeDetails.parseFile`)}
@ -91,48 +146,8 @@ export const ReparseDialog = memo(
console.log('submit', data); console.log('submit', data);
}} }}
ref={formCallbackRef} ref={formCallbackRef}
fields={[ fields={fields}
{ defaultValues={defaultValues}
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>
),
},
]}
> >
{/* <DynamicForm.CancelButton {/* <DynamicForm.CancelButton
handleCancel={() => handleOperationIconClick(false)} handleCancel={() => handleOperationIconClick(false)}

View File

@ -10,7 +10,7 @@ import {
} from '@/hooks/use-document-request'; } from '@/hooks/use-document-request';
import { IDocumentInfo } from '@/interfaces/database/document'; import { IDocumentInfo } from '@/interfaces/database/document';
import { Ban, CircleCheck, CircleX, Play, Trash2 } from 'lucide-react'; import { Ban, CircleCheck, CircleX, Play, Trash2 } from 'lucide-react';
import { useCallback } from 'react'; import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { DocumentType, RunningStatus } from './constant'; import { DocumentType, RunningStatus } from './constant';
@ -32,6 +32,16 @@ export function useBulkOperateDataset({
const { setDocumentStatus } = useSetDocumentStatus(); const { setDocumentStatus } = useSetDocumentStatus();
const { removeDocument } = useRemoveDocument(); const { removeDocument } = useRemoveDocument();
const { visible, showModal, hideModal } = useSetModalState(); 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( const runDocument = useCallback(
async (run: number, option?: { delete: boolean; apply_kb: boolean }) => { async (run: number, option?: { delete: boolean; apply_kb: boolean }) => {
const nonVirtualKeys = selectedRowKeys.filter( 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<{ const InfoItem: React.FC<{
overflowTip?: boolean;
label: string; label: string;
value: string | React.ReactNode; value: string | React.ReactNode;
className?: string; className?: string;
}> = ({ label, value, className = '' }) => { }> = ({ label, value, className = '', overflowTip = false }) => {
return ( return (
<div className={`flex flex-col mb-4 ${className}`}> <div className={`flex flex-col mb-4 ${className}`}>
<span className="text-text-secondary text-sm">{label}</span> <span className="text-text-secondary text-sm">{label}</span>
<Tooltip> {overflowTip && (
<TooltipTrigger asChild> <Tooltip>
<span className="text-text-primary mt-1 truncate w-full"> <TooltipTrigger asChild>
{value} <span className="text-text-primary mt-1 truncate w-full">
</span> {value}
</TooltipTrigger> </span>
<TooltipContent>{value}</TooltipContent> </TooltipTrigger>
</Tooltip> <TooltipContent>{value}</TooltipContent>
</Tooltip>
)}
{!overflowTip && (
<span className="text-text-primary mt-1 truncate w-full">{value}</span>
)}
</div> </div>
); );
}; };
@ -139,6 +145,7 @@ const ProcessLogModal: React.FC<ProcessLogModalProps> = ({
return ( return (
<div className="w-1/2" key={key}> <div className="w-1/2" key={key}>
<InfoItem <InfoItem
overflowTip={true}
label={t(key)} label={t(key)}
value={logInfo[key as keyof typeof logInfo]} value={logInfo[key as keyof typeof logInfo]}
/> />

View File

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