| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  | 'use client' | 
					
						
							|  |  |  | import type { FC } from 'react' | 
					
						
							|  |  |  | import React, { useState } from 'react' | 
					
						
							|  |  |  | import useSWR from 'swr' | 
					
						
							|  |  |  | import { ArrowLeftIcon } from '@heroicons/react/24/solid' | 
					
						
							| 
									
										
										
										
											2023-08-18 17:37:31 +08:00
										 |  |  | import { createContext, useContext } from 'use-context-selector' | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  | import { useTranslation } from 'react-i18next' | 
					
						
							|  |  |  | import { useRouter } from 'next/navigation' | 
					
						
							|  |  |  | import { omit } from 'lodash-es' | 
					
						
							|  |  |  | import cn from 'classnames' | 
					
						
							|  |  |  | import { OperationAction, StatusItem } from '../list' | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | import s from '../style.module.css' | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  | import Completed from './completed' | 
					
						
							|  |  |  | import Embedding from './embedding' | 
					
						
							|  |  |  | import Metadata from './metadata' | 
					
						
							| 
									
										
										
										
											2023-08-18 17:37:31 +08:00
										 |  |  | import SegmentAdd, { ProcessStatus } from './segment-add' | 
					
						
							|  |  |  | import BatchModal from './batch-modal' | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  | import style from './style.module.css' | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  | import Divider from '@/app/components/base/divider' | 
					
						
							|  |  |  | import Loading from '@/app/components/base/loading' | 
					
						
							|  |  |  | import type { MetadataType } from '@/service/datasets' | 
					
						
							| 
									
										
										
										
											2023-08-18 17:37:31 +08:00
										 |  |  | import { checkSegmentBatchImportProgress, fetchDocumentDetail, segmentBatchImport } from '@/service/datasets' | 
					
						
							|  |  |  | import { ToastContext } from '@/app/components/base/toast' | 
					
						
							|  |  |  | import type { DocForm } from '@/models/datasets' | 
					
						
							| 
									
										
										
										
											2023-08-30 17:27:19 +08:00
										 |  |  | import { useDatasetDetailContext } from '@/context/dataset-detail' | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-28 20:47:15 +08:00
										 |  |  | export const DocumentContext = createContext<{ datasetId?: string; documentId?: string; docForm: string }>({ docForm: '' }) | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | type DocumentTitleProps = { | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |   extension?: string | 
					
						
							|  |  |  |   name?: string | 
					
						
							|  |  |  |   iconCls?: string | 
					
						
							|  |  |  |   textCls?: string | 
					
						
							|  |  |  |   wrapperCls?: string | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export const DocumentTitle: FC<DocumentTitleProps> = ({ extension, name, iconCls, textCls, wrapperCls }) => { | 
					
						
							|  |  |  |   const localExtension = extension?.toLowerCase() || name?.split('.')?.pop()?.toLowerCase() | 
					
						
							|  |  |  |   return <div className={cn('flex items-center justify-start flex-1', wrapperCls)}> | 
					
						
							|  |  |  |     <div className={cn(s[`${localExtension || 'txt'}Icon`], style.titleIcon, iconCls)}></div> | 
					
						
							|  |  |  |     <span className={cn('font-semibold text-lg text-gray-900 ml-1', textCls)}> {name || '--'}</span> | 
					
						
							|  |  |  |   </div> | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type Props = { | 
					
						
							|  |  |  |   datasetId: string | 
					
						
							|  |  |  |   documentId: string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const DocumentDetail: FC<Props> = ({ datasetId, documentId }) => { | 
					
						
							|  |  |  |   const router = useRouter() | 
					
						
							| 
									
										
										
										
											2023-08-18 17:37:31 +08:00
										 |  |  |   const { t } = useTranslation() | 
					
						
							|  |  |  |   const { notify } = useContext(ToastContext) | 
					
						
							| 
									
										
										
										
											2023-08-30 17:27:19 +08:00
										 |  |  |   const { dataset } = useDatasetDetailContext() | 
					
						
							|  |  |  |   const embeddingAvailable = !!dataset?.embedding_available | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  |   const [showMetadata, setShowMetadata] = useState(true) | 
					
						
							| 
									
										
										
										
											2023-08-18 17:37:31 +08:00
										 |  |  |   const [newSegmentModalVisible, setNewSegmentModalVisible] = useState(false) | 
					
						
							|  |  |  |   const [batchModalVisible, setBatchModalVisible] = useState(false) | 
					
						
							|  |  |  |   const [importStatus, setImportStatus] = useState<ProcessStatus | string>() | 
					
						
							|  |  |  |   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}` : ''}` }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const { data: documentDetail, error, mutate: detailMutate } = useSWR({ | 
					
						
							|  |  |  |     action: 'fetchDocumentDetail', | 
					
						
							|  |  |  |     datasetId, | 
					
						
							|  |  |  |     documentId, | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |     params: { metadata: 'without' as MetadataType }, | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  |   }, apiParams => fetchDocumentDetail(omit(apiParams, 'action'))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { data: documentMetadata, error: metadataErr, mutate: metadataMutate } = useSWR({ | 
					
						
							|  |  |  |     action: 'fetchDocumentDetail', | 
					
						
							|  |  |  |     datasetId, | 
					
						
							|  |  |  |     documentId, | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |     params: { metadata: 'only' as MetadataType }, | 
					
						
							|  |  |  |   }, apiParams => fetchDocumentDetail(omit(apiParams, 'action')), | 
					
						
							|  |  |  |   ) | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |   const handleOperate = (operateName?: string) => { | 
					
						
							|  |  |  |     if (operateName === 'delete') | 
					
						
							|  |  |  |       backToPrev() | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       detailMutate() | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  |   return ( | 
					
						
							| 
									
										
										
										
											2023-07-28 20:47:15 +08:00
										 |  |  |     <DocumentContext.Provider value={{ datasetId, documentId, docForm: documentDetail?.doc_form || '' }}> | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  |       <div className='flex flex-col h-full'> | 
					
						
							|  |  |  |         <div className='flex h-16 border-b-gray-100 border-b items-center p-4'> | 
					
						
							| 
									
										
										
										
											2023-08-18 17:37:31 +08:00
										 |  |  |           <div onClick={backToPrev} className={'rounded-full w-8 h-8 flex justify-center items-center border-gray-100 cursor-pointer border hover:border-gray-300 shadow-[0px_12px_16px_-4px_rgba(16,24,40,0.08),0px_4px_6px_-2px_rgba(16,24,40,0.03)]'}> | 
					
						
							|  |  |  |             <ArrowLeftIcon className='text-primary-600 fill-current stroke-current h-4 w-4' /> | 
					
						
							|  |  |  |           </div> | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  |           <Divider className='!h-4' type='vertical' /> | 
					
						
							|  |  |  |           <DocumentTitle extension={documentDetail?.data_source_info?.upload_file?.extension} name={documentDetail?.name} /> | 
					
						
							| 
									
										
										
										
											2023-08-21 18:07:51 +08:00
										 |  |  |           <StatusItem status={documentDetail?.display_status || 'available'} scene='detail' errorMessage={documentDetail?.error || ''} /> | 
					
						
							| 
									
										
										
										
											2023-08-30 17:27:19 +08:00
										 |  |  |           {embeddingAvailable && documentDetail && !documentDetail.archived && ( | 
					
						
							| 
									
										
										
										
											2023-08-18 17:37:31 +08:00
										 |  |  |             <SegmentAdd | 
					
						
							|  |  |  |               importStatus={importStatus} | 
					
						
							|  |  |  |               clearProcessStatus={resetProcessStatus} | 
					
						
							|  |  |  |               showNewSegmentModal={showNewSegmentModal} | 
					
						
							|  |  |  |               showBatchModal={showBatchModal} | 
					
						
							|  |  |  |             /> | 
					
						
							|  |  |  |           )} | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  |           <OperationAction | 
					
						
							|  |  |  |             scene='detail' | 
					
						
							| 
									
										
										
										
											2023-08-30 17:27:19 +08:00
										 |  |  |             embeddingAvailable={embeddingAvailable} | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  |             detail={{ | 
					
						
							|  |  |  |               enabled: documentDetail?.enabled || false, | 
					
						
							|  |  |  |               archived: documentDetail?.archived || false, | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |               id: documentId, | 
					
						
							| 
									
										
										
										
											2023-08-18 17:37:31 +08:00
										 |  |  |               data_source_type: documentDetail?.data_source_type || '', | 
					
						
							| 
									
										
										
										
											2023-07-28 20:47:15 +08:00
										 |  |  |               doc_form: documentDetail?.doc_form || '', | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  |             }} | 
					
						
							|  |  |  |             datasetId={datasetId} | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |             onUpdate={handleOperate} | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  |             className='!w-[216px]' | 
					
						
							|  |  |  |           /> | 
					
						
							|  |  |  |           <button | 
					
						
							|  |  |  |             className={cn(style.layoutRightIcon, showMetadata ? style.iconShow : style.iconClose)} | 
					
						
							|  |  |  |             onClick={() => setShowMetadata(!showMetadata)} | 
					
						
							|  |  |  |           /> | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |         <div className='flex flex-row flex-1' style={{ height: 'calc(100% - 4rem)' }}> | 
					
						
							| 
									
										
										
										
											2023-06-16 21:47:51 +08:00
										 |  |  |           {isDetailLoading | 
					
						
							|  |  |  |             ? <Loading type='app' /> | 
					
						
							|  |  |  |             : <div className={`box-border h-full w-full overflow-y-scroll ${embedding ? 'py-12 px-16' : 'pb-[30px] pt-3 px-6'}`}> | 
					
						
							| 
									
										
										
										
											2023-07-28 20:47:15 +08:00
										 |  |  |               {embedding | 
					
						
							|  |  |  |                 ? <Embedding detail={documentDetail} detailUpdate={detailMutate} /> | 
					
						
							|  |  |  |                 : <Completed | 
					
						
							| 
									
										
										
										
											2023-08-30 17:27:19 +08:00
										 |  |  |                   embeddingAvailable={embeddingAvailable} | 
					
						
							| 
									
										
										
										
											2023-08-18 17:37:31 +08:00
										 |  |  |                   showNewSegmentModal={newSegmentModalVisible} | 
					
						
							|  |  |  |                   onNewSegmentModalChange={setNewSegmentModalVisible} | 
					
						
							|  |  |  |                   importStatus={importStatus} | 
					
						
							|  |  |  |                   archived={documentDetail?.archived} | 
					
						
							| 
									
										
										
										
											2023-07-28 20:47:15 +08:00
										 |  |  |                 /> | 
					
						
							|  |  |  |               } | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  |             </div> | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           {showMetadata && <Metadata | 
					
						
							| 
									
										
										
										
											2023-08-21 13:57:18 +08:00
										 |  |  |             docDetail={{ ...documentDetail, ...documentMetadata, doc_type: documentDetail?.doc_type === 'others' ? '' : documentDetail?.doc_type } as any} | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  |             loading={isMetadataLoading} | 
					
						
							|  |  |  |             onUpdate={metadataMutate} | 
					
						
							|  |  |  |           />} | 
					
						
							|  |  |  |         </div> | 
					
						
							| 
									
										
										
										
											2023-08-18 17:37:31 +08:00
										 |  |  |         <BatchModal | 
					
						
							|  |  |  |           isShow={batchModalVisible} | 
					
						
							|  |  |  |           onCancel={hideBatchModal} | 
					
						
							|  |  |  |           onConfirm={runBatch} | 
					
						
							|  |  |  |           docForm={documentDetail?.doc_form as DocForm} | 
					
						
							|  |  |  |         /> | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  |       </div> | 
					
						
							|  |  |  |     </DocumentContext.Provider> | 
					
						
							|  |  |  |   ) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default DocumentDetail |