'use client' import type { FC } from 'react' import React, { useState } from 'react' import useSWR from 'swr' import { ArrowLeftIcon } from '@heroicons/react/24/solid' import { createContext, useContext } from 'use-context-selector' import { useTranslation } from 'react-i18next' import { useRouter } from 'next/navigation' import { omit } from 'lodash-es' import { OperationAction, StatusItem } from '../list' import s from '../style.module.css' import Completed from './completed' import Embedding from './embedding' import Metadata from './metadata' import SegmentAdd, { ProcessStatus } from './segment-add' import BatchModal from './batch-modal' import style from './style.module.css' import cn from '@/utils/classnames' import Divider from '@/app/components/base/divider' import Loading from '@/app/components/base/loading' import type { MetadataType } from '@/service/datasets' import { checkSegmentBatchImportProgress, fetchDocumentDetail, segmentBatchImport } from '@/service/datasets' import { ToastContext } from '@/app/components/base/toast' import type { DocForm } from '@/models/datasets' import { useDatasetDetailContext } from '@/context/dataset-detail' import FloatRightContainer from '@/app/components/base/float-right-container' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' export const DocumentContext = createContext<{ datasetId?: string; documentId?: string; docForm: string }>({ docForm: '' }) type DocumentTitleProps = { extension?: string name?: string iconCls?: string textCls?: string wrapperCls?: string } export const DocumentTitle: FC = ({ extension, name, iconCls, textCls, wrapperCls }) => { const localExtension = extension?.toLowerCase() || name?.split('.')?.pop()?.toLowerCase() return
{name || '--'}
} type Props = { datasetId: string documentId: string } const DocumentDetail: FC = ({ datasetId, documentId }) => { const router = useRouter() const { t } = useTranslation() const media = useBreakpoints() const isMobile = media === MediaType.mobile const { notify } = useContext(ToastContext) const { dataset } = useDatasetDetailContext() const embeddingAvailable = !!dataset?.embedding_available const [showMetadata, setShowMetadata] = useState(!isMobile) const [newSegmentModalVisible, setNewSegmentModalVisible] = useState(false) const [batchModalVisible, setBatchModalVisible] = useState(false) const [importStatus, setImportStatus] = useState() const showNewSegmentModal = () => setNewSegmentModalVisible(true) const showBatchModal = () => setBatchModalVisible(true) const hideBatchModal = () => setBatchModalVisible(false) const resetProcessStatus = () => setImportStatus('') const checkProcess = async (jobID: string) => { try { const res = await checkSegmentBatchImportProgress({ jobID }) setImportStatus(res.job_status) if (res.job_status === ProcessStatus.WAITING || res.job_status === ProcessStatus.PROCESSING) setTimeout(() => checkProcess(res.job_id), 2500) if (res.job_status === ProcessStatus.ERROR) notify({ type: 'error', message: `${t('datasetDocuments.list.batchModal.runError')}` }) } catch (e: any) { notify({ type: 'error', message: `${t('datasetDocuments.list.batchModal.runError')}${'message' in e ? `: ${e.message}` : ''}` }) } } const runBatch = async (csv: File) => { const formData = new FormData() formData.append('file', csv) try { const res = await segmentBatchImport({ url: `/datasets/${datasetId}/documents/${documentId}/segments/batch_import`, body: formData, }) setImportStatus(res.job_status) checkProcess(res.job_id) } catch (e: any) { notify({ type: 'error', message: `${t('datasetDocuments.list.batchModal.runError')}${'message' in e ? `: ${e.message}` : ''}` }) } } const { data: documentDetail, error, mutate: detailMutate } = useSWR({ action: 'fetchDocumentDetail', datasetId, documentId, params: { metadata: 'without' as MetadataType }, }, apiParams => fetchDocumentDetail(omit(apiParams, 'action'))) const { data: documentMetadata, error: metadataErr, mutate: metadataMutate } = useSWR({ action: 'fetchDocumentDetail', datasetId, documentId, params: { metadata: 'only' as MetadataType }, }, apiParams => fetchDocumentDetail(omit(apiParams, 'action')), ) const backToPrev = () => { router.push(`/datasets/${datasetId}/documents`) } const isDetailLoading = !documentDetail && !error const isMetadataLoading = !documentMetadata && !metadataErr const embedding = ['queuing', 'indexing', 'paused'].includes((documentDetail?.display_status || '').toLowerCase()) const handleOperate = (operateName?: string) => { if (operateName === 'delete') backToPrev() else detailMutate() } return (
{embeddingAvailable && documentDetail && !documentDetail.archived && ( )}
{isDetailLoading ? :
{embedding ? : }
} setShowMetadata(false)} isMobile={isMobile} panelClassname='!justify-start' footer={null}>
) } export default DocumentDetail