import React, { useEffect, useMemo, useState } from 'react' import { useRouter } from 'next/navigation' import { useTranslation } from 'react-i18next' import { RiAedFill, RiArrowRightLine, RiCheckboxCircleFill, RiErrorWarningFill, RiLoader2Fill, RiTerminalBoxLine, } from '@remixicon/react' import cn from '@/utils/classnames' import Button from '@/app/components/base/button' import type { IndexingStatusResponse } from '@/models/datasets' import NotionIcon from '@/app/components/base/notion-icon' import PriorityLabel from '@/app/components/billing/priority-label' import { Plan } from '@/app/components/billing/type' import UpgradeBtn from '@/app/components/billing/upgrade-btn' import { useProviderContext } from '@/context/provider-context' import Tooltip from '@/app/components/base/tooltip' import { useInvalidDocumentList } from '@/service/knowledge/use-document' import DocumentFileIcon from '@/app/components/datasets/common/document-file-icon' import RuleDetail from './rule-detail' import type { IndexingType } from '@/app/components/datasets/create/step-two' import type { RETRIEVE_METHOD } from '@/types/app' import { DatasourceType, type InitialDocumentDetail } from '@/models/pipeline' import { useIndexingStatusBatch, useProcessRule } from '@/service/knowledge/use-dataset' import Divider from '@/app/components/base/divider' type EmbeddingProcessProps = { datasetId: string batchId: string documents?: InitialDocumentDetail[] indexingType?: IndexingType retrievalMethod?: RETRIEVE_METHOD } const EmbeddingProcess = ({ datasetId, batchId, documents = [], indexingType, retrievalMethod, }: EmbeddingProcessProps) => { const { t } = useTranslation() const router = useRouter() const { enableBilling, plan } = useProviderContext() const [indexingStatusBatchDetail, setIndexingStatusDetail] = useState([]) const [shouldPoll, setShouldPoll] = useState(true) const { mutateAsync: fetchIndexingStatus } = useIndexingStatusBatch({ datasetId, batchId }) useEffect(() => { let timeoutId: ReturnType const fetchData = async () => { await fetchIndexingStatus(undefined, { onSuccess: (res) => { const indexingStatusDetailList = res.data setIndexingStatusDetail(indexingStatusDetailList) const isCompleted = indexingStatusDetailList.every(indexingStatusDetail => ['completed', 'error', 'paused'].includes(indexingStatusDetail.indexing_status)) if (isCompleted) setShouldPoll(false) }, onSettled: () => { if (shouldPoll) timeoutId = setTimeout(fetchData, 2500) }, }) } fetchData() return () => { clearTimeout(timeoutId) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [shouldPoll]) // get rule const firstDocument = documents[0] const { data: ruleDetail } = useProcessRule(firstDocument.id) const invalidDocumentList = useInvalidDocumentList() const navToDocumentList = () => { invalidDocumentList() router.push(`/datasets/${datasetId}/documents`) } const navToApiDocs = () => { router.push('/datasets?category=api') } const isEmbedding = useMemo(() => { return indexingStatusBatchDetail.some(indexingStatusDetail => ['indexing', 'splitting', 'parsing', 'cleaning'].includes(indexingStatusDetail?.indexing_status || '')) }, [indexingStatusBatchDetail]) const isEmbeddingCompleted = useMemo(() => { return indexingStatusBatchDetail.every(indexingStatusDetail => ['completed', 'error', 'paused'].includes(indexingStatusDetail?.indexing_status || '')) }, [indexingStatusBatchDetail]) const getSourceName = (id: string) => { const doc = documents.find(document => document.id === id) return doc?.name } const getFileType = (name?: string) => name?.split('.').pop() || 'txt' const getSourcePercent = (detail: IndexingStatusResponse) => { const completedCount = detail.completed_segments || 0 const totalCount = detail.total_segments || 0 if (totalCount === 0) return 0 const percent = Math.round(completedCount * 100 / totalCount) return percent > 100 ? 100 : percent } const getSourceType = (id: string) => { const doc = documents.find(document => document.id === id) return doc?.data_source_type } const getIcon = (id: string) => { const doc = documents.find(document => document.id === id) return doc?.data_source_info.notion_page_icon } const isSourceEmbedding = (detail: IndexingStatusResponse) => ['indexing', 'splitting', 'parsing', 'cleaning', 'waiting'].includes(detail.indexing_status || '') return ( <>
{isEmbedding && ( <> {t('datasetDocuments.embedding.processing')} )} {isEmbeddingCompleted && t('datasetDocuments.embedding.completed')}
{ enableBilling && plan.type !== Plan.team && (
{t('billing.plansCommon.documentProcessingPriorityUpgrade')}
) }
{indexingStatusBatchDetail.map(indexingStatusDetail => (
{isSourceEmbedding(indexingStatusDetail) && (
)}
{getSourceType(indexingStatusDetail.id) === DatasourceType.localFile && ( )} {getSourceType(indexingStatusDetail.id) === DatasourceType.onlineDocument && ( )}
{getSourceName(indexingStatusDetail.id)}
{ enableBilling && ( ) }
{isSourceEmbedding(indexingStatusDetail) && (
{`${getSourcePercent(indexingStatusDetail)}%`}
)} {indexingStatusDetail.indexing_status === 'error' && ( )} {indexingStatusDetail.indexing_status === 'completed' && ( )}
))}
) } export default EmbeddingProcess