'use client' import { useCallback, useMemo, useRef, useState } from 'react' import DataSourceOptions from './data-source-options' import type { CrawlResultItem, DocumentItem, CustomFile as File, FileIndexingEstimateResponse } from '@/models/datasets' import LocalFile from '@/app/components/datasets/documents/create-from-pipeline/data-source/local-file' import { useProviderContextSelector } from '@/context/provider-context' import type { NotionPage } from '@/models/common' import OnlineDocuments from '@/app/components/datasets/documents/create-from-pipeline/data-source/online-documents' import VectorSpaceFull from '@/app/components/billing/vector-space-full' import WebsiteCrawl from '@/app/components/datasets/documents/create-from-pipeline/data-source/website-crawl' import OnlineDrive from '@/app/components/datasets/documents/create-from-pipeline/data-source/online-drive' import Actions from './actions' import { useTranslation } from 'react-i18next' import type { Datasource } from '@/app/components/rag-pipeline/components/panel/test-run/types' import LeftHeader from './left-header' import { usePublishedPipelineInfo, useRunPublishedPipeline } from '@/service/use-pipeline' import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail' import Loading from '@/app/components/base/loading' import type { Node } from '@/app/components/workflow/types' import type { DataSourceNodeType } from '@/app/components/workflow/nodes/data-source/types' import FilePreview from './preview/file-preview' import OnlineDocumentPreview from './preview/online-document-preview' import WebsitePreview from './preview/web-preview' import ProcessDocuments from './process-documents' import ChunkPreview from './preview/chunk-preview' import Processing from './processing' import type { InitialDocumentDetail, OnlineDriveFile, PublishedPipelineRunPreviewResponse, PublishedPipelineRunResponse } from '@/models/pipeline' import { DatasourceType } from '@/models/pipeline' import { TransferMethod } from '@/types/app' import { useAddDocumentsSteps, useLocalFile, useOnlineDocuments, useOnlineDrive, useWebsiteCrawl } from './hooks' import DataSourceProvider from './data-source/store/provider' import { useDataSourceStore } from './data-source/store' import { useFileUploadConfig } from '@/service/use-common' const CreateFormPipeline = () => { const { t } = useTranslation() const plan = useProviderContextSelector(state => state.plan) const enableBilling = useProviderContextSelector(state => state.enableBilling) const pipelineId = useDatasetDetailContextWithSelector(s => s.dataset?.pipeline_id) const [datasource, setDatasource] = useState() const [estimateData, setEstimateData] = useState(undefined) const [batchId, setBatchId] = useState('') const [documents, setDocuments] = useState([]) const dataSourceStore = useDataSourceStore() const isPreview = useRef(false) const formRef = useRef(null) const { data: pipelineInfo, isFetching: isFetchingPipelineInfo } = usePublishedPipelineInfo(pipelineId || '') const { data: fileUploadConfigResponse } = useFileUploadConfig() const { steps, currentStep, handleNextStep, handleBackStep, } = useAddDocumentsSteps() const { fileList, allFileLoaded, currentLocalFile, hidePreviewLocalFile, } = useLocalFile() const { currentWorkspace, onlineDocuments, currentDocument, PagesMapAndSelectedPagesId, hidePreviewOnlineDocument, } = useOnlineDocuments() const { websitePages, currentWebsite, hideWebsitePreview, } = useWebsiteCrawl() const { fileList: onlineDriveFileList, selectedFileKeys, selectedOnlineDriveFileList, } = useOnlineDrive() const datasourceType = datasource?.nodeData.provider_type const isVectorSpaceFull = plan.usage.vectorSpace >= plan.total.vectorSpace const isShowVectorSpaceFull = useMemo(() => { if (!datasource) return false if (datasourceType === DatasourceType.localFile) return allFileLoaded && isVectorSpaceFull && enableBilling if (datasourceType === DatasourceType.onlineDocument) return onlineDocuments.length > 0 && isVectorSpaceFull && enableBilling if (datasourceType === DatasourceType.websiteCrawl) return websitePages.length > 0 && isVectorSpaceFull && enableBilling if (datasourceType === DatasourceType.onlineDrive) return onlineDriveFileList.length > 0 && isVectorSpaceFull && enableBilling return false }, [allFileLoaded, datasource, datasourceType, enableBilling, isVectorSpaceFull, onlineDocuments.length, onlineDriveFileList.length, websitePages.length]) const notSupportBatchUpload = enableBilling && plan.type === 'sandbox' const nextBtnDisabled = useMemo(() => { if (!datasource) return true if (datasourceType === DatasourceType.localFile) return isShowVectorSpaceFull || !fileList.length || !allFileLoaded if (datasourceType === DatasourceType.onlineDocument) return isShowVectorSpaceFull || !onlineDocuments.length if (datasourceType === DatasourceType.websiteCrawl) return isShowVectorSpaceFull || !websitePages.length if (datasourceType === DatasourceType.onlineDrive) return isShowVectorSpaceFull || !selectedFileKeys.length return false }, [datasource, datasourceType, isShowVectorSpaceFull, fileList.length, allFileLoaded, onlineDocuments.length, websitePages.length, selectedFileKeys.length]) const fileUploadConfig = useMemo(() => fileUploadConfigResponse ?? { file_size_limit: 15, batch_count_limit: 5, }, [fileUploadConfigResponse]) const showSelect = useMemo(() => { if (datasourceType === DatasourceType.onlineDocument) { const pagesCount = currentWorkspace?.pages.length ?? 0 return pagesCount > 0 } if (datasourceType === DatasourceType.onlineDrive) { const isBucketList = onlineDriveFileList.some(file => file.type === 'bucket') return !isBucketList && onlineDriveFileList.filter((item) => { return item.type !== 'bucket' }).length > 0 } }, [currentWorkspace?.pages.length, datasourceType, onlineDriveFileList]) const totalOptions = useMemo(() => { if (datasourceType === DatasourceType.onlineDocument) return currentWorkspace?.pages.length if (datasourceType === DatasourceType.onlineDrive) { return onlineDriveFileList.filter((item) => { return item.type !== 'bucket' }).length } }, [currentWorkspace?.pages.length, datasourceType, onlineDriveFileList]) const selectedOptions = useMemo(() => { if (datasourceType === DatasourceType.onlineDocument) return onlineDocuments.length if (datasourceType === DatasourceType.onlineDrive) return selectedFileKeys.length }, [datasourceType, onlineDocuments.length, selectedFileKeys.length]) const tip = useMemo(() => { if (datasourceType === DatasourceType.onlineDocument) return t('datasetPipeline.addDocuments.selectOnlineDocumentTip', { count: 50 }) if (datasourceType === DatasourceType.onlineDrive) { return t('datasetPipeline.addDocuments.selectOnlineDriveTip', { count: fileUploadConfig.batch_count_limit, fileSize: fileUploadConfig.file_size_limit, }) } return '' }, [datasourceType, fileUploadConfig.batch_count_limit, fileUploadConfig.file_size_limit, t]) const { mutateAsync: runPublishedPipeline, isIdle, isPending } = useRunPublishedPipeline() const handlePreviewChunks = useCallback(async (data: Record) => { if (!datasource) return const { previewLocalFileRef, previewOnlineDocumentRef, previewWebsitePageRef, previewOnlineDriveFileRef, } = dataSourceStore.getState() const datasourceInfoList: Record[] = [] if (datasourceType === DatasourceType.localFile) { const { id, name, type, size, extension, mime_type } = previewLocalFileRef.current as File const documentInfo = { related_id: id, name, type, size, extension, mime_type, url: '', transfer_method: TransferMethod.local_file, } datasourceInfoList.push(documentInfo) } if (datasourceType === DatasourceType.onlineDocument) { const { workspace_id, ...rest } = previewOnlineDocumentRef.current! const documentInfo = { workspace_id, page: rest, } datasourceInfoList.push(documentInfo) } if (datasourceType === DatasourceType.websiteCrawl) datasourceInfoList.push(previewWebsitePageRef.current!) if (datasourceType === DatasourceType.onlineDrive) { const { bucket } = dataSourceStore.getState() const { key } = previewOnlineDriveFileRef.current! datasourceInfoList.push({ bucket, key, }) } await runPublishedPipeline({ pipeline_id: pipelineId!, inputs: data, start_node_id: datasource.nodeId, datasource_type: datasourceType as DatasourceType, datasource_info_list: datasourceInfoList, is_preview: true, }, { onSuccess: (res) => { setEstimateData((res as PublishedPipelineRunPreviewResponse).data.outputs) }, }) }, [datasource, datasourceType, runPublishedPipeline, pipelineId, dataSourceStore]) const handleProcess = useCallback(async (data: Record) => { if (!datasource) return const datasourceInfoList: Record[] = [] if (datasourceType === DatasourceType.localFile) { fileList.forEach((file) => { const { id, name, type, size, extension, mime_type } = file.file const documentInfo = { related_id: id, name, type, size, extension, mime_type, url: '', transfer_method: TransferMethod.local_file, } datasourceInfoList.push(documentInfo) }) } if (datasourceType === DatasourceType.onlineDocument) { onlineDocuments.forEach((page) => { const { workspace_id, ...rest } = page const documentInfo = { workspace_id, page: rest, } datasourceInfoList.push(documentInfo) }) } if (datasourceType === DatasourceType.websiteCrawl) { websitePages.forEach((websitePage) => { datasourceInfoList.push(websitePage) }) } if (datasourceType === DatasourceType.onlineDrive) { if (datasourceType === DatasourceType.onlineDrive) { const { bucket } = dataSourceStore.getState() selectedFileKeys.forEach((key) => { datasourceInfoList.push({ bucket, key, }) }) } } await runPublishedPipeline({ pipeline_id: pipelineId!, inputs: data, start_node_id: datasource.nodeId, datasource_type: datasourceType as DatasourceType, datasource_info_list: datasourceInfoList, is_preview: false, }, { onSuccess: (res) => { setBatchId((res as PublishedPipelineRunResponse).batch || '') setDocuments((res as PublishedPipelineRunResponse).documents || []) handleNextStep() }, }) }, [dataSourceStore, datasource, datasourceType, fileList, handleNextStep, onlineDocuments, pipelineId, runPublishedPipeline, selectedFileKeys, websitePages]) const onClickProcess = useCallback(() => { isPreview.current = false formRef.current?.submit() }, []) const onClickPreview = useCallback(() => { isPreview.current = true formRef.current?.submit() }, []) const handleSubmit = useCallback((data: Record) => { isPreview.current ? handlePreviewChunks(data) : handleProcess(data) }, [handlePreviewChunks, handleProcess]) const handlePreviewFileChange = useCallback((file: DocumentItem) => { const { previewLocalFileRef } = dataSourceStore.getState() previewLocalFileRef.current = file onClickPreview() }, [dataSourceStore, onClickPreview]) const handlePreviewOnlineDocumentChange = useCallback((page: NotionPage) => { const { previewOnlineDocumentRef } = dataSourceStore.getState() previewOnlineDocumentRef.current = page onClickPreview() }, [dataSourceStore, onClickPreview]) const handlePreviewWebsiteChange = useCallback((website: CrawlResultItem) => { const { previewWebsitePageRef } = dataSourceStore.getState() previewWebsitePageRef.current = website onClickPreview() }, [dataSourceStore, onClickPreview]) const handlePreviewOnlineDriveFileChange = useCallback((file: OnlineDriveFile) => { const { previewOnlineDriveFileRef } = dataSourceStore.getState() previewOnlineDriveFileRef.current = file onClickPreview() }, [dataSourceStore, onClickPreview]) const handleSelectAll = useCallback(() => { const { onlineDocuments, fileList: onlineDriveFileList, selectedFileKeys, setOnlineDocuments, setSelectedFileKeys, setSelectedPagesId, } = dataSourceStore.getState() if (datasourceType === DatasourceType.onlineDocument) { const allIds = currentWorkspace?.pages.map(page => page.page_id) || [] if (onlineDocuments.length < allIds.length) { const selectedPages = Array.from(allIds).map(pageId => PagesMapAndSelectedPagesId[pageId]) setOnlineDocuments(selectedPages) setSelectedPagesId(new Set(allIds)) } else { setOnlineDocuments([]) setSelectedPagesId(new Set()) } } if (datasourceType === DatasourceType.onlineDrive) { const allKeys = onlineDriveFileList.filter((item) => { return item.type !== 'bucket' }).map(file => file.key) if (selectedFileKeys.length < allKeys.length) setSelectedFileKeys(allKeys) else setSelectedFileKeys([]) } }, [PagesMapAndSelectedPagesId, currentWorkspace?.pages, dataSourceStore, datasourceType]) if (isFetchingPipelineInfo) { return ( ) } return (
{ currentStep === 1 && (
[]} /> {datasourceType === DatasourceType.localFile && ( )} {datasourceType === DatasourceType.onlineDocument && ( )} {datasourceType === DatasourceType.websiteCrawl && ( )} {datasourceType === DatasourceType.onlineDrive && ( )} {isShowVectorSpaceFull && ( )}
) } { currentStep === 2 && ( ) } { currentStep === 3 && ( ) }
{/* Preview */} { currentStep === 1 && (
{currentLocalFile && ( )} {currentDocument && ( )} {currentWebsite && ( )}
) } { currentStep === 2 && (
file.file)} onlineDocuments={onlineDocuments} websitePages={websitePages} onlineDriveFiles={selectedOnlineDriveFileList} isIdle={isIdle} isPending={isPending && isPreview.current} estimateData={estimateData} onPreview={onClickPreview} handlePreviewFileChange={handlePreviewFileChange} handlePreviewOnlineDocumentChange={handlePreviewOnlineDocumentChange} handlePreviewWebsitePageChange={handlePreviewWebsiteChange} handlePreviewOnlineDriveFileChange={handlePreviewOnlineDriveFileChange} />
) }
) } const CreateFormPipelineWrapper = () => { return ( ) } export default CreateFormPipelineWrapper