'use client' import type { FC } from 'react' import React, { memo, useState, useEffect, useMemo } from 'react' import { HashtagIcon } from '@heroicons/react/24/solid' import { useTranslation } from 'react-i18next' import { useContext } from 'use-context-selector' import { omitBy, isNil, debounce } from 'lodash-es' import { formatNumber } from '@/utils/format' import { StatusItem } from '../../list' import { DocumentContext } from '../index' import s from './style.module.css' import Modal from '@/app/components/base/modal' import Switch from '@/app/components/base/switch' import Divider from '@/app/components/base/divider' import Input from '@/app/components/base/input' import Loading from '@/app/components/base/loading' import { ToastContext } from '@/app/components/base/toast' import { SimpleSelect, Item } from '@/app/components/base/select' import { disableSegment, enableSegment, fetchSegments } from '@/service/datasets' import type { SegmentDetailModel, SegmentsResponse, SegmentsQuery } from '@/models/datasets' import { asyncRunSafe } from '@/utils' import type { CommonResponse } from '@/models/common' import InfiniteVirtualList from "./InfiniteVirtualList"; import cn from 'classnames' export const SegmentIndexTag: FC<{ positionId: string | number; className?: string }> = ({ positionId, className }) => { const localPositionId = useMemo(() => { const positionIdStr = String(positionId) if (positionIdStr.length >= 3) return positionId return positionIdStr.padStart(3, '0') }, [positionId]) return (
{localPositionId}
) } type ISegmentDetailProps = { segInfo?: Partial & { id: string } onChangeSwitch?: (segId: string, enabled: boolean) => Promise } /** * Show all the contents of the segment */ export const SegmentDetail: FC = memo(({ segInfo, onChangeSwitch }) => { const { t } = useTranslation() return (
{segInfo?.content}
{t('datasetDocuments.segment.keywords')}
{!segInfo?.keywords?.length ? '-' : segInfo?.keywords?.map((word: any) => { return
{word}
})}
{formatNumber(segInfo?.word_count as any)} {t('datasetDocuments.segment.characters')}
{formatNumber(segInfo?.hit_count as any)} {t('datasetDocuments.segment.hitCount')}
{t('datasetDocuments.segment.vectorHash')}{segInfo?.index_node_hash}
{ await onChangeSwitch?.(segInfo?.id || '', val) }} />
) }) export const splitArray = (arr: any[], size = 3) => { if (!arr || !arr.length) return [] const result = [] for (let i = 0; i < arr.length; i += size) result.push(arr.slice(i, i + size)) return result } type ICompletedProps = { // data: Array<{}> // all/part segments } /** * Embedding done, show list of all segments * Support search and filter */ const Completed: FC = () => { const { t } = useTranslation() const { notify } = useContext(ToastContext) const { datasetId = '', documentId = '' } = useContext(DocumentContext) // the current segment id and whether to show the modal const [currSegment, setCurrSegment] = useState<{ segInfo?: SegmentDetailModel; showModal: boolean }>({ showModal: false }) const [searchValue, setSearchValue] = useState() // the search value const [selectedStatus, setSelectedStatus] = useState('all') // the selected status, enabled/disabled/undefined const [lastSegmentsRes, setLastSegmentsRes] = useState(undefined) const [allSegments, setAllSegments] = useState>([]) // all segments data const [loading, setLoading] = useState(false) const [total, setTotal] = useState() useEffect(() => { if (lastSegmentsRes !== undefined) { getSegments(false) } }, [selectedStatus, searchValue]) const onChangeStatus = ({ value }: Item) => { setSelectedStatus(value === 'all' ? 'all' : !!value) } const getSegments = async (needLastId?: boolean) => { const finalLastId = lastSegmentsRes?.data?.[lastSegmentsRes.data.length - 1]?.id || ''; setLoading(true) const [e, res] = await asyncRunSafe(fetchSegments({ datasetId, documentId, params: omitBy({ last_id: !needLastId ? undefined : finalLastId, limit: 9, keyword: searchValue, enabled: selectedStatus === 'all' ? 'all' : !!selectedStatus, }, isNil) as SegmentsQuery }) as Promise) if (!e) { setAllSegments([...(!needLastId ? [] : allSegments), ...splitArray(res.data || [])]) setLastSegmentsRes(res) if (!lastSegmentsRes) { setTotal(res?.total || 0) } } setLoading(false) } const onClickCard = (detail: SegmentDetailModel) => { setCurrSegment({ segInfo: detail, showModal: true }) } const onCloseModal = () => { setCurrSegment({ ...currSegment, showModal: false }) } const onChangeSwitch = async (segId: string, enabled: boolean) => { const opApi = enabled ? enableSegment : disableSegment const [e] = await asyncRunSafe(opApi({ datasetId, segmentId: segId }) as Promise) if (!e) { notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') }) for (const item of allSegments) { for (const seg of item) { if (seg.id === segId) { seg.enabled = enabled } } } setAllSegments([...allSegments]) } else { notify({ type: 'error', message: t('common.actionMsg.modificationFailed') }) } } return ( <>
{total ? formatNumber(total) : '--'} {t('datasetDocuments.segment.paragraphs')}
) } export default Completed