feat: upgrade knowledge metadata (#16063)

Support filter knowledge by metadata.

Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: NFish <douxc512@gmail.com>
This commit is contained in:
zxhlyh
2025-03-18 11:01:06 +08:00
committed by GitHub
parent 475b8d731e
commit 20376ca951
72 changed files with 4775 additions and 101 deletions

View File

@@ -1,5 +1,5 @@
import React, { type FC } from 'react'
import { RiArchive2Line, RiCheckboxCircleLine, RiCloseCircleLine, RiDeleteBinLine } from '@remixicon/react'
import { RiArchive2Line, RiCheckboxCircleLine, RiCloseCircleLine, RiDeleteBinLine, RiDraftLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import { useBoolean } from 'ahooks'
import Divider from '@/app/components/base/divider'
@@ -14,6 +14,7 @@ type IBatchActionProps = {
onBatchDisable: () => void
onBatchDelete: () => Promise<void>
onArchive?: () => void
onEditMetadata?: () => void
onCancel: () => void
}
@@ -24,6 +25,7 @@ const BatchAction: FC<IBatchActionProps> = ({
onBatchDisable,
onArchive,
onBatchDelete,
onEditMetadata,
onCancel,
}) => {
const { t } = useTranslation()
@@ -62,6 +64,15 @@ const BatchAction: FC<IBatchActionProps> = ({
{t(`${i18nPrefix}.disable`)}
</button>
</div>
{onEditMetadata && (
<div className='flex items-center gap-x-0.5 px-3 py-2'>
<RiDraftLine className='w-4 h-4 text-components-button-ghost-text' />
<button type='button' className='px-0.5 text-components-button-ghost-text text-[13px] font-medium leading-[16px]' onClick={onEditMetadata}>
{t('dataset.metadata.metadata')}
</button>
</div>
)}
{onArchive && (
<div className='flex items-center gap-x-0.5 px-3 py-2'>
<RiArchive2Line className='w-4 h-4 text-components-button-ghost-text' />

View File

@@ -9,7 +9,7 @@ import { OperationAction, StatusItem } from '../list'
import DocumentPicker from '../../common/document-picker'
import Completed from './completed'
import Embedding from './embedding'
import Metadata from './metadata'
import Metadata from '@/app/components/datasets/metadata/metadata-document'
import SegmentAdd, { ProcessStatus } from './segment-add'
import BatchModal from './batch-modal'
import style from './style.module.css'
@@ -281,9 +281,10 @@ const DocumentDetail: FC<Props> = ({ datasetId, documentId }) => {
}
<FloatRightContainer showClose isOpen={showMetadata} onClose={() => setShowMetadata(false)} isMobile={isMobile} panelClassname='!justify-start' footer={null}>
<Metadata
className='mr-2 mt-3'
datasetId={datasetId}
documentId={documentId}
docDetail={{ ...documentDetail, ...documentMetadata, doc_type: documentMetadata?.doc_type === 'others' ? '' : documentMetadata?.doc_type } as any}
loading={isMetadataLoading}
onUpdate={metadataMutate}
/>
</FloatRightContainer>
</div>

View File

@@ -6,7 +6,7 @@ import { useRouter } from 'next/navigation'
import { useDebounce, useDebounceFn } from 'ahooks'
import { groupBy } from 'lodash-es'
import { PlusIcon } from '@heroicons/react/24/solid'
import { RiExternalLinkLine } from '@remixicon/react'
import { RiDraftLine, RiExternalLinkLine } from '@remixicon/react'
import AutoDisabledDocument from '../common/document-status-with-action/auto-disabled-document'
import List from './list'
import s from './style.module.css'
@@ -26,6 +26,9 @@ import cn from '@/utils/classnames'
import { useDocumentList, useInvalidDocumentDetailKey, useInvalidDocumentList } from '@/service/knowledge/use-document'
import { useInvalid } from '@/service/use-base'
import { useChildSegmentListKey, useSegmentListKey } from '@/service/knowledge/use-segment'
import useEditDocumentMetadata from '../metadata/hooks/use-edit-dataset-metadata'
import DatasetMetadataDrawer from '../metadata/metadata-dataset/dataset-metadata-drawer'
import StatusWithAction from '../common/document-status-with-action/status-with-action'
const FolderPlusIcon = ({ className }: React.SVGProps<SVGElement>) => {
return <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
@@ -116,7 +119,7 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
if (totalPages < currPage + 1)
setCurrPage(totalPages === 0 ? 0 : totalPages - 1)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [documentsRes])
const invalidDocumentDetail = useInvalidDocumentDetailKey()
@@ -231,6 +234,23 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
handleSearch()
}
const {
isShowEditModal: isShowEditMetadataModal,
showEditModal: showEditMetadataModal,
hideEditModal: hideEditMetadataModal,
datasetMetaData,
handleAddMetaData,
handleRename,
handleDeleteMetaData,
builtInEnabled,
setBuiltInEnabled,
builtInMetaData,
} = useEditDocumentMetadata({
datasetId,
dataset,
onUpdateDocList: invalidDocumentList,
})
return (
<div className='flex flex-col h-full overflow-y-auto'>
<div className='flex flex-col justify-center gap-1 px-6 pt-4'>
@@ -259,6 +279,25 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
<div className='flex gap-2 justify-center items-center !h-8'>
{!isFreePlan && <AutoDisabledDocument datasetId={datasetId} />}
<IndexFailed datasetId={datasetId} />
{!embeddingAvailable && <StatusWithAction type='warning' description={t('dataset.embeddingModelNotAvailable')} />}
{embeddingAvailable && (
<Button variant='secondary' className='shrink-0' onClick={showEditMetadataModal}>
<RiDraftLine className='size-4 mr-1' />
{t('dataset.metadata.metadata')}
</Button>
)}
{isShowEditMetadataModal && (
<DatasetMetadataDrawer
userMetadata={datasetMetaData || []}
onClose={hideEditMetadataModal}
onAdd={handleAddMetaData}
onRename={handleRename}
onRemove={handleDeleteMetaData}
builtInMetadata={builtInMetaData || []}
isBuiltInEnabled={!!builtInEnabled}
onIsBuiltInEnabledChange={setBuiltInEnabled}
/>
)}
{embeddingAvailable && (
<Button variant='primary' onClick={routeToDocCreate} className='shrink-0'>
<PlusIcon className={cn('h-4 w-4 mr-2 stroke-current')} />
@@ -286,6 +325,7 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
current: currPage,
onChange: setCurrPage,
}}
onManageMetadata={showEditMetadataModal}
/>
: <EmptyElement canAdd={embeddingAvailable} onClick={routeToDocCreate} type={isDataSourceNotion ? 'sync' : 'upload'} />
}

View File

@@ -45,6 +45,8 @@ import Pagination from '@/app/components/base/pagination'
import Checkbox from '@/app/components/base/checkbox'
import { useDocumentArchive, useDocumentDelete, useDocumentDisable, useDocumentEnable, useDocumentUnArchive, useSyncDocument, useSyncWebsite } from '@/service/knowledge/use-document'
import { extensionToFileType } from '@/app/components/datasets/hit-testing/utils/extension-to-file-type'
import useBatchEditDocumentMetadata from '../metadata/hooks/use-batch-edit-document-metadata'
import EditMetadataBatchModal from '@/app/components/datasets/metadata/edit-metadata-batch/modal'
export const useIndexStatus = () => {
const { t } = useTranslation()
@@ -107,7 +109,8 @@ export const StatusItem: FC<{
const [e] = await asyncRunSafe<CommonResponse>(opApi({ datasetId, documentId: id }) as Promise<CommonResponse>)
if (!e) {
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
onUpdate?.(operationName)
onUpdate?.()
// onUpdate?.(operationName)
}
else { notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) }
}
@@ -401,6 +404,7 @@ type IDocumentListProps = {
datasetId: string
pagination: PaginationProps
onUpdate: () => void
onManageMetadata: () => void
}
/**
@@ -414,6 +418,7 @@ const DocumentList: FC<IDocumentListProps> = ({
datasetId,
pagination,
onUpdate,
onManageMetadata,
}) => {
const { t } = useTranslation()
const { formatTime } = useTimestamp()
@@ -424,6 +429,17 @@ const DocumentList: FC<IDocumentListProps> = ({
const isQAMode = chunkingMode === ChunkingMode.qa
const [localDocs, setLocalDocs] = useState<LocalDoc[]>(documents)
const [enableSort, setEnableSort] = useState(true)
const {
isShowEditModal,
showEditModal,
hideEditModal,
originalList,
handleSave,
} = useBatchEditDocumentMetadata({
datasetId,
docList: documents.filter(item => selectedIds.includes(item.id)),
onUpdate,
})
useEffect(() => {
setLocalDocs(documents)
@@ -501,18 +517,20 @@ const DocumentList: FC<IDocumentListProps> = ({
return (
<div className='flex flex-col relative w-full h-full'>
<div className='grow overflow-x-auto'>
<div className='relative grow overflow-x-auto'>
<table className={`min-w-[700px] max-w-full w-full border-collapse border-0 text-sm mt-3 ${s.documentTable}`}>
<thead className="h-8 leading-8 border-b border-divider-subtle text-text-tertiary font-medium text-xs uppercase">
<tr>
<td className='w-12'>
<div className='flex items-center' onClick={e => e.stopPropagation()}>
<Checkbox
className='shrink-0 mr-2'
checked={isAllSelected}
mixed={!isAllSelected && isSomeSelected}
onCheck={onSelectedAll}
/>
{embeddingAvailable && (
<Checkbox
className='shrink-0 mr-2'
checked={isAllSelected}
mixed={!isAllSelected && isSomeSelected}
onCheck={onSelectedAll}
/>
)}
#
</div>
</td>
@@ -625,6 +643,7 @@ const DocumentList: FC<IDocumentListProps> = ({
onBatchEnable={handleAction(DocumentActionType.enable)}
onBatchDisable={handleAction(DocumentActionType.disable)}
onBatchDelete={handleAction(DocumentActionType.delete)}
onEditMetadata={showEditModal}
onCancel={() => {
onSelectedIdChange([])
}}
@@ -647,6 +666,20 @@ const DocumentList: FC<IDocumentListProps> = ({
onSaved={handleRenamed}
/>
)}
{isShowEditModal && (
<EditMetadataBatchModal
datasetId={datasetId}
documentNum={selectedIds.length}
list={originalList}
onSave={handleSave}
onHide={hideEditModal}
onShowManage={() => {
hideEditModal()
onManageMetadata()
}}
/>
)}
</div>
)
}