diff --git a/web/src/hooks/use-document-request.ts b/web/src/hooks/use-document-request.ts index aa88628e1..22a4a86ef 100644 --- a/web/src/hooks/use-document-request.ts +++ b/web/src/hooks/use-document-request.ts @@ -266,20 +266,19 @@ export const useRunDocument = () => { mutationFn: async ({ documentIds, run, - shouldDelete, + option, }: { documentIds: string[]; run: number; - shouldDelete: boolean; + option?: { delete: boolean; apply_kb: boolean }; }) => { queryClient.invalidateQueries({ queryKey: [DocumentApiAction.FetchDocumentList], }); - const ret = await kbService.document_run({ doc_ids: documentIds, run, - delete: shouldDelete, + ...option, }); const code = get(ret, 'data.code'); if (code === 0) { diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 1779129ee..335e17ad6 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -125,8 +125,9 @@ Procedural Memory: Learned skills, habits, and automated procedures.`, }, memory: { messages: { + forgetMessageTip: 'Are you sure you want to forget?', messageDescription: - 'Memory retrieval is configured with Similarity threshold, Keyword similarity weight, and Top N from Advanced Settings.', + 'Memory extract is configured with Prompts and Temperature from Advanced Settings.', copied: 'Copied!', contentEmbed: 'Content embed', content: 'Content', @@ -216,6 +217,10 @@ Procedural Memory: Learned skills, habits, and automated procedures.`, deleteSettingFieldWarn: `This field will be deleted; existing metadata won't be affected.`, deleteSettingValueWarn: `This value will be deleted; existing metadata won't be affected.`, }, + redoAll: 'Clear existing chunks', + applyAutoMetadataSettings: 'Apply global auto-metadata settings', + parseFileTip: 'Are you sure to parse?', + parseFile: 'Parse file', emptyMetadata: 'No metadata', metadataField: 'Metadata field', systemAttribute: 'System attribute', @@ -455,7 +460,7 @@ Procedural Memory: Learned skills, habits, and automated procedures.`, manualSetup: 'Choose pipeline', builtIn: 'Built-in', titleDescription: - 'Update your knowledge base configuration here, particularly the chunking method.', + 'Update your memory configuration here, particularly the LLM and prompts.', name: 'Knowledge base name', photo: 'Knowledge base photo', photoTip: 'You can upload a file with 4 MB', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index 4570233ca..da3874bc0 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -117,8 +117,8 @@ export default { }, memory: { messages: { - messageDescription: - '记忆检索已在高级设置中配置相似度阈值、关键词相似度权重和前N个结果。', + forgetMessageTip: '确定遗忘吗?', + messageDescription: '记忆提取使用高级设置中的提示词和温度值进行配置。', copied: '已复制!', contentEmbed: '内容嵌入', content: '内容', @@ -201,6 +201,10 @@ export default { deleteSettingFieldWarn: `此字段将被删除;现有元数据不会受到影响。`, deleteSettingValueWarn: `此值将被删除;现有元数据不会受到影响。`, }, + redoAll: '清除现有分块', + applyAutoMetadataSettings: '应用全局自动元数据设置', + parseFileTip: '您确定要解析吗?', + parseFile: '解析文件', emptyMetadata: '无元数据', localUpload: '本地上传', fileSize: '文件大小', @@ -418,7 +422,7 @@ export default { parseType: '解析方法', manualSetup: '选择pipeline', builtIn: '内置', - titleDescription: '在这里更新您的知识库详细信息,尤其是切片方法。', + titleDescription: '在这里更新您的记忆配置,特别是大语言模型和提示词。', name: '知识库名称', photo: '知识库图片', photoTip: '你可以上传4MB的文件', diff --git a/web/src/pages/dataset/dataset/index.tsx b/web/src/pages/dataset/dataset/index.tsx index 1d2908d5d..f2c4b9667 100644 --- a/web/src/pages/dataset/dataset/index.tsx +++ b/web/src/pages/dataset/dataset/index.tsx @@ -23,6 +23,7 @@ import { import { ManageMetadataModal } from '../components/metedata/manage-modal'; import { DatasetTable } from './dataset-table'; import Generate from './generate-button/generate'; +import { ReparseDialog } from './reparse-dialog'; import { useBulkOperateDataset } from './use-bulk-operate-dataset'; import { useCreateEmptyDocument } from './use-create-empty-document'; import { useSelectDatasetFilters } from './use-select-filters'; @@ -77,7 +78,12 @@ export default function Dataset() { const { rowSelection, rowSelectionIsEmpty, setRowSelection, selectedCount } = useRowSelection(); - const { list } = useBulkOperateDataset({ + const { + list, + visible: reparseDialogVisible, + hideModal: hideReparseDialogModal, + handleRunClick: handleOperationIconClick, + } = useBulkOperateDataset({ documents, rowSelection, setRowSelection, @@ -207,6 +213,16 @@ export default function Dataset() { otherData={metadataConfig.record} /> )} + {reparseDialogVisible && ( + + )} ); diff --git a/web/src/pages/dataset/dataset/parsing-status-cell.tsx b/web/src/pages/dataset/dataset/parsing-status-cell.tsx index 102b6db54..ea6019b98 100644 --- a/web/src/pages/dataset/dataset/parsing-status-cell.tsx +++ b/web/src/pages/dataset/dataset/parsing-status-cell.tsx @@ -1,4 +1,3 @@ -import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog'; import { IconFontFill } from '@/components/icon-font'; import { DropdownMenu, @@ -19,6 +18,7 @@ import { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { DocumentType, RunningStatus } from './constant'; import { ParsingCard } from './parsing-card'; +import { ReparseDialog } from './reparse-dialog'; import { UseChangeDocumentParserShowType } from './use-change-document-parser'; import { useHandleRunDocumentByIds } from './use-run-document'; import { UseSaveMetaShowType } from './use-save-meta'; @@ -63,15 +63,21 @@ export function ParsingStatusCell({ } = record; const operationIcon = IconMap[run]; const p = Number((progress * 100).toFixed(2)); - const { handleRunDocumentByIds } = useHandleRunDocumentByIds(id); + const { + handleRunDocumentByIds, + visible: reparseDialogVisible, + showModal: showReparseDialogModal, + hideModal: hideReparseDialogModal, + } = useHandleRunDocumentByIds(id); const isRunning = isParserRunning(run); const isZeroChunk = chunk_num === 0; - const handleOperationIconClick = - (shouldDelete: boolean = false) => - () => { - handleRunDocumentByIds(record.id, isRunning, shouldDelete); - }; + const handleOperationIconClick = (option: { + delete: boolean; + apply_kb: boolean; + }) => { + handleRunDocumentByIds(record.id, isRunning, option); + }; const handleShowChangeParserModal = useCallback(() => { showChangeParserModal(record); @@ -129,23 +135,20 @@ export function ParsingStatusCell({
{!isParserRunning(run) && ( -
{} - } + onClick={() => { + showReparseDialogModal(); + }} + // onClick={ + // isZeroChunk || isRunning + // ? handleOperationIconClick(false) + // : () => {} + // } > {operationIcon}
@@ -175,6 +181,16 @@ export function ParsingStatusCell({ )} )} + {reparseDialogVisible && ( + + )} ); } diff --git a/web/src/pages/dataset/dataset/reparse-dialog.tsx b/web/src/pages/dataset/dataset/reparse-dialog.tsx new file mode 100644 index 000000000..31a217a21 --- /dev/null +++ b/web/src/pages/dataset/dataset/reparse-dialog.tsx @@ -0,0 +1,154 @@ +import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog'; +import { + DynamicForm, + DynamicFormRef, + FormFieldType, +} from '@/components/dynamic-form'; +import { Checkbox } from '@/components/ui/checkbox'; +import { DialogProps } from '@radix-ui/react-dialog'; +import { t } from 'i18next'; +import { useCallback, useState } from 'react'; + +export const ReparseDialog = ({ + handleOperationIconClick, + chunk_num, + hidden = false, + visible = true, + hideModal, + children, +}: DialogProps & { + chunk_num: number; + handleOperationIconClick: (options: { + delete: boolean; + apply_kb: boolean; + }) => void; + visible: boolean; + hideModal: () => void; + hidden?: boolean; +}) => { + const [formInstance, setFormInstance] = useState(null); + + const formCallbackRef = useCallback((node: DynamicFormRef | null) => { + if (node) { + setFormInstance(node); + console.log('Form instance assigned:', node); + } else { + console.log('Form instance removed'); + } + }, []); + + const handleCancel = useCallback(() => { + // handleOperationIconClick(false); + hideModal?.(); + formInstance?.reset(); + }, [formInstance]); + + const handleSave = useCallback(async () => { + const instance = formInstance; + if (!instance) { + console.error('Form instance is null'); + return; + } + + const check = await instance.trigger(); + if (check) { + instance.submit(); + const formValues = instance.getValues(); + console.log(formValues); + handleOperationIconClick({ + delete: formValues.delete, + apply_kb: formValues.apply_kb, + }); + } + }, [formInstance, handleOperationIconClick]); + + // useEffect(() => { + // if (!hidden) { + // const timer = setTimeout(() => { + // if (!formInstance) { + // console.warn( + // 'Form ref is still null after component should be mounted', + // ); + // } else { + // console.log('Form ref is properly set'); + // } + // }, 1000); + + // return () => clearTimeout(timer); + // } + // }, [hidden, formInstance]); + + return ( + handleSave()} + onCancel={() => handleCancel()} + hidden={hidden} + open={visible} + content={{ + title: t(`knowledgeDetails.parseFileTip`), + node: ( +
+ { + console.log('submit', data); + }} + ref={formCallbackRef} + fields={[ + { + name: 'delete', + label: '', + type: FormFieldType.Checkbox, + render: (fieldProps) => ( +
+ { + fieldProps.onChange(checked); + }} + /> + + {chunk_num > 0 + ? t(`knowledgeDetails.redo`, { chunkNum: chunk_num }) + : t('knowledgeDetails.redoAll')} + +
+ ), + }, + { + name: 'apply_kb', + label: '', + type: FormFieldType.Checkbox, + render: (fieldProps) => ( +
+ { + fieldProps.onChange(checked); + }} + /> + + {t('knowledgeDetails.applyAutoMetadataSettings')} + +
+ ), + }, + ]} + > + {/* handleOperationIconClick(false)} + cancelText={t('common.cancel')} + /> + */} +
+
+ ), + }} + > + {/* {children} */} +
+ ); +}; diff --git a/web/src/pages/dataset/dataset/use-bulk-operate-dataset.tsx b/web/src/pages/dataset/dataset/use-bulk-operate-dataset.tsx index ea8eeaebc..b0527c264 100644 --- a/web/src/pages/dataset/dataset/use-bulk-operate-dataset.tsx +++ b/web/src/pages/dataset/dataset/use-bulk-operate-dataset.tsx @@ -1,3 +1,4 @@ +import { useSetModalState } from '@/hooks/common-hooks'; import { UseRowSelectionType, useSelectedIds, @@ -30,9 +31,9 @@ export function useBulkOperateDataset({ const { runDocumentByIds } = useRunDocument(); const { setDocumentStatus } = useSetDocumentStatus(); const { removeDocument } = useRemoveDocument(); - + const { visible, showModal, hideModal } = useSetModalState(); const runDocument = useCallback( - (run: number) => { + async (run: number, option?: { delete: boolean; apply_kb: boolean }) => { const nonVirtualKeys = selectedRowKeys.filter( (x) => !documents.some((y) => x === y.id && y.type === DocumentType.Virtual), @@ -42,18 +43,22 @@ export function useBulkOperateDataset({ toast.error(t('Please select a non-empty file list')); return; } - runDocumentByIds({ + await runDocumentByIds({ documentIds: nonVirtualKeys, run, - shouldDelete: false, + option, }); + hideModal(); }, - [documents, runDocumentByIds, selectedRowKeys, t], + [documents, runDocumentByIds, selectedRowKeys, hideModal, t], ); - const handleRunClick = useCallback(() => { - runDocument(1); - }, [runDocument]); + const handleRunClick = useCallback( + (option: { delete: boolean; apply_kb: boolean }) => { + runDocument(1, option); + }, + [runDocument], + ); const handleCancelClick = useCallback(() => { runDocument(2); @@ -106,7 +111,7 @@ export function useBulkOperateDataset({ id: 'run', label: t('knowledgeDetails.run'), icon: , - onClick: handleRunClick, + onClick: () => showModal(), }, { id: 'cancel', @@ -127,5 +132,5 @@ export function useBulkOperateDataset({ }, ]; - return { list }; + return { list, visible, hideModal, showModal, handleRunClick }; } diff --git a/web/src/pages/dataset/dataset/use-run-document.ts b/web/src/pages/dataset/dataset/use-run-document.ts index c17235f9b..b7a92401c 100644 --- a/web/src/pages/dataset/dataset/use-run-document.ts +++ b/web/src/pages/dataset/dataset/use-run-document.ts @@ -1,3 +1,4 @@ +import { useSetModalState } from '@/hooks/common-hooks'; import { useRunDocument } from '@/hooks/use-document-request'; import { useState } from 'react'; @@ -5,11 +6,11 @@ export const useHandleRunDocumentByIds = (id: string) => { const { runDocumentByIds, loading } = useRunDocument(); const [currentId, setCurrentId] = useState(''); const isLoading = loading && currentId !== '' && currentId === id; - + const { visible, showModal, hideModal } = useSetModalState(); const handleRunDocumentByIds = async ( documentId: string, isRunning: boolean, - shouldDelete: boolean = false, + option: { delete: boolean; apply_kb: boolean }, ) => { if (isLoading) { return; @@ -19,16 +20,20 @@ export const useHandleRunDocumentByIds = (id: string) => { await runDocumentByIds({ documentIds: [documentId], run: isRunning ? 2 : 1, - shouldDelete, + option, }); setCurrentId(''); } catch (error) { setCurrentId(''); } + hideModal(); }; return { handleRunDocumentByIds, loading: isLoading, + visible, + showModal, + hideModal, }; }; diff --git a/web/src/pages/memory/memory-message/index.tsx b/web/src/pages/memory/memory-message/index.tsx index 9e65612fd..943fad706 100644 --- a/web/src/pages/memory/memory-message/index.tsx +++ b/web/src/pages/memory/memory-message/index.tsx @@ -39,7 +39,7 @@ export default function MemoryMessage() { messages={data?.messages?.message_list ?? []} pagination={pagination} setPagination={setPagination} - total={data?.messages?.total ?? 0} + total={data?.messages?.total_count ?? 0} // rowSelection={rowSelection} // setRowSelection={setRowSelection} // loading={loading} diff --git a/web/src/pages/memory/memory-message/interface.ts b/web/src/pages/memory/memory-message/interface.ts index 347f3db0c..09bd51e75 100644 --- a/web/src/pages/memory/memory-message/interface.ts +++ b/web/src/pages/memory/memory-message/interface.ts @@ -14,7 +14,7 @@ export interface IMessageInfo { } export interface IMessageTableProps { - messages: { message_list: Array; total: number }; + messages: { message_list: Array; total_count: number }; storage_type: string; } diff --git a/web/src/pages/memory/memory-message/message-table.tsx b/web/src/pages/memory/memory-message/message-table.tsx index 68f735899..1d9c486fb 100644 --- a/web/src/pages/memory/memory-message/message-table.tsx +++ b/web/src/pages/memory/memory-message/message-table.tsx @@ -252,6 +252,7 @@ export function MemoryTable({ open={showDeleteDialog} onOpenChange={setShowDeleteDialog} content={{ + title: t('memory.messages.forgetMessageTip'), node: ( { horizontal: true, placeholder: t('memory.config.storageTypePlaceholder'), options: [ - { label: 'table', value: 'table' }, - // { label: 'graph', value: 'graph' }, + { label: 'Table', value: 'table' }, + // { label: 'Graph', value: 'graph' }, ], required: false, }} @@ -95,7 +95,7 @@ export const AdvancedSettingsForm = () => { // placeholder: t('memory.config.storageTypePlaceholder'), options: [ // { label: 'LRU', value: 'LRU' }, - { label: 'FIFO', value: 'FIFO' }, + { label: 'FIFO', value: 'fifo' }, ], required: false, }} diff --git a/web/src/pages/memory/memory-setting/memory-model-form.tsx b/web/src/pages/memory/memory-setting/memory-model-form.tsx index c700de577..97c64208b 100644 --- a/web/src/pages/memory/memory-setting/memory-model-form.tsx +++ b/web/src/pages/memory/memory-setting/memory-model-form.tsx @@ -4,6 +4,7 @@ import { EmbeddingSelect } from '@/pages/dataset/dataset-setting/configuration/c import { MemoryType } from '@/pages/memories/constants'; import { useTranslation } from 'react-i18next'; import { z } from 'zod'; +import { useFetchMemoryMessageList } from '../memory-message/hook'; export const memoryModelFormSchema = { embd_id: z.string(), @@ -20,6 +21,7 @@ export const defaultMemoryModelForm = { export const MemoryModelForm = () => { const { modelOptions } = useModelOptions(); const { t } = useTranslation(); + const { data } = useFetchMemoryMessageList(); return ( <> { type: FormFieldType.Custom, disabled: true, render: (field) => ( - + 0} + /> ), tooltip: t('memories.embeddingModelTooltip'), @@ -47,6 +53,7 @@ export const MemoryModelForm = () => { required: true, horizontal: true, type: FormFieldType.Select, + disabled: data?.messages?.total_count > 0, options: modelOptions as { value: string; label: string }[], tooltip: t('memories.llmTooltip'), }} diff --git a/web/src/utils/api.ts b/web/src/utils/api.ts index 251158000..b43ca9e89 100644 --- a/web/src/utils/api.ts +++ b/web/src/utils/api.ts @@ -239,7 +239,7 @@ export default { createMemory: `${api_host}/memories`, getMemoryList: `${api_host}/memories`, getMemoryConfig: (id: string) => `${api_host}/memories/${id}/config`, - deleteMemory: (id: string) => `${api_host}/memory/rm/${id}`, + deleteMemory: (id: string) => `${api_host}/memories/${id}`, getMemoryDetail: (id: string) => `${api_host}/memories/${id}`, updateMemorySetting: (id: string) => `${api_host}/memories/${id}`, deleteMemoryMessage: (data: { memory_id: string; message_id: string }) =>