import type { FC } from 'react' import type { FileEntity } from '@/app/components/datasets/common/image-uploader/types' import type { SegmentDetailModel } from '@/models/datasets' import { RiCloseLine, RiCollapseDiagonalLine, RiExpandDiagonalLine, } from '@remixicon/react' import * as React from 'react' import { useCallback, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { v4 as uuid4 } from 'uuid' import Divider from '@/app/components/base/divider' import ImageUploaderInChunk from '@/app/components/datasets/common/image-uploader/image-uploader-in-chunk' import { IndexingType } from '@/app/components/datasets/create/step-two' import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail' import { useEventEmitterContextContext } from '@/context/event-emitter' import { ChunkingMode } from '@/models/datasets' import { cn } from '@/utils/classnames' import { formatNumber } from '@/utils/format' import { useDocumentContext } from '../context' import ActionButtons from './common/action-buttons' import ChunkContent from './common/chunk-content' import Dot from './common/dot' import Keywords from './common/keywords' import RegenerationModal from './common/regeneration-modal' import { SegmentIndexTag } from './common/segment-index-tag' import SummaryText from './common/summary-text' import { useSegmentListContext } from './index' type ISegmentDetailProps = { segInfo?: Partial & { id: string } onUpdate: ( segmentId: string, q: string, a: string, k: string[], attachments: FileEntity[], summary?: string, needRegenerate?: boolean, ) => void onCancel: () => void isEditMode?: boolean docForm: ChunkingMode onModalStateChange?: (isOpen: boolean) => void } /** * Show all the contents of the segment */ const SegmentDetail: FC = ({ segInfo, onUpdate, onCancel, isEditMode, docForm, onModalStateChange, }) => { const { t } = useTranslation() const [question, setQuestion] = useState(isEditMode ? segInfo?.content || '' : segInfo?.sign_content || '') const [answer, setAnswer] = useState(segInfo?.answer || '') const [summary, setSummary] = useState(segInfo?.summary || '') const [attachments, setAttachments] = useState(() => { return segInfo?.attachments?.map(item => ({ id: uuid4(), name: item.name, size: item.size, mimeType: item.mime_type, extension: item.extension, sourceUrl: item.source_url, uploadedId: item.id, progress: 100, })) || [] }) const [keywords, setKeywords] = useState(segInfo?.keywords || []) const { eventEmitter } = useEventEmitterContextContext() const [loading, setLoading] = useState(false) const [showRegenerationModal, setShowRegenerationModal] = useState(false) const fullScreen = useSegmentListContext(s => s.fullScreen) const toggleFullScreen = useSegmentListContext(s => s.toggleFullScreen) const parentMode = useDocumentContext(s => s.parentMode) const indexingTechnique = useDatasetDetailContextWithSelector(s => s.dataset?.indexing_technique) const runtimeMode = useDatasetDetailContextWithSelector(s => s.dataset?.runtime_mode) eventEmitter?.useSubscription((v) => { if (v === 'update-segment') setLoading(true) if (v === 'update-segment-done') setLoading(false) }) const handleCancel = useCallback(() => { onCancel() }, [onCancel]) const handleSave = useCallback(() => { onUpdate(segInfo?.id || '', question, answer, keywords, attachments, summary, false) }, [onUpdate, segInfo?.id, question, answer, keywords, attachments, summary]) const handleRegeneration = useCallback(() => { setShowRegenerationModal(true) onModalStateChange?.(true) }, [onModalStateChange]) const onCancelRegeneration = useCallback(() => { setShowRegenerationModal(false) onModalStateChange?.(false) }, [onModalStateChange]) const onCloseAfterRegeneration = useCallback(() => { setShowRegenerationModal(false) onModalStateChange?.(false) onCancel() // Close the edit drawer }, [onCancel, onModalStateChange]) const onConfirmRegeneration = useCallback(() => { onUpdate(segInfo?.id || '', question, answer, keywords, attachments, summary, true) }, [onUpdate, segInfo?.id, question, answer, keywords, attachments, summary]) const onAttachmentsChange = useCallback((attachments: FileEntity[]) => { setAttachments(attachments) }, []) const wordCountText = useMemo(() => { const contentLength = docForm === ChunkingMode.qa ? (question.length + answer.length) : question.length const total = formatNumber(isEditMode ? contentLength : segInfo!.word_count as number) const count = isEditMode ? contentLength : segInfo!.word_count as number return `${total} ${t('segment.characters', { ns: 'datasetDocuments', count })}` }, [isEditMode, question.length, answer.length, docForm, segInfo, t]) const isFullDocMode = docForm === ChunkingMode.parentChild && parentMode === 'full-doc' const titleText = isEditMode ? t('segment.editChunk', { ns: 'datasetDocuments' }) : t('segment.chunkDetail', { ns: 'datasetDocuments' }) const labelPrefix = docForm === ChunkingMode.parentChild ? t('segment.parentChunk', { ns: 'datasetDocuments' }) : t('segment.chunk', { ns: 'datasetDocuments' }) const isECOIndexing = indexingTechnique === IndexingType.ECONOMICAL return (
{titleText}
{wordCountText}
{isEditMode && fullScreen && ( <> )}
{ fullScreen ? : }
setQuestion(question)} onAnswerChange={answer => setAnswer(answer)} isEditMode={isEditMode} />
setSummary(summary)} disabled={!isEditMode} /> {isECOIndexing && ( setKeywords(keywords)} /> )}
{isEditMode && !fullScreen && (
)} { showRegenerationModal && ( ) }
) } export default React.memo(SegmentDetail)