| import { forwardRef, useEffect, useRef } from 'react' | import { forwardRef, useEffect, useRef } from 'react' | ||||
| import cn from 'classnames' | import cn from 'classnames' | ||||
| import { sleep } from '@/utils' | |||||
| type IProps = { | type IProps = { | ||||
| placeholder?: string | placeholder?: string | ||||
| return false | return false | ||||
| } | } | ||||
| const focus = () => { | |||||
| const focus = async () => { | |||||
| if (!doFocus()) { | if (!doFocus()) { | ||||
| let hasFocus = false | let hasFocus = false | ||||
| const runId = setInterval(() => { | |||||
| hasFocus = doFocus() | |||||
| if (hasFocus) | |||||
| clearInterval(runId) | |||||
| }, 100) | |||||
| await sleep(100) | |||||
| hasFocus = doFocus() | |||||
| if (!hasFocus) | |||||
| focus() | |||||
| } | } | ||||
| } | } | ||||
| import { useProviderContext } from '@/context/provider-context' | import { useProviderContext } from '@/context/provider-context' | ||||
| import TooltipPlus from '@/app/components/base/tooltip-plus' | import TooltipPlus from '@/app/components/base/tooltip-plus' | ||||
| import { AlertCircle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback' | import { AlertCircle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback' | ||||
| import { sleep } from '@/utils' | |||||
| type Props = { | type Props = { | ||||
| datasetId: string | datasetId: string | ||||
| return status.data | return status.data | ||||
| } | } | ||||
| // const [_, setRunId, getRunId] = useGetState<ReturnType<typeof setInterval>>() | |||||
| const [runId, setRunId] = useState<ReturnType<typeof setInterval>>() | |||||
| const runIdRef = useRef(runId) | |||||
| const getRunId = () => runIdRef.current | |||||
| const [isStopQuery, setIsStopQuery] = useState(false) | |||||
| const isStopQueryRef = useRef(isStopQuery) | |||||
| useEffect(() => { | useEffect(() => { | ||||
| runIdRef.current = runId | |||||
| }, [runId]) | |||||
| isStopQueryRef.current = isStopQuery | |||||
| }, [isStopQuery]) | |||||
| const stopQueryStatus = () => { | const stopQueryStatus = () => { | ||||
| clearInterval(getRunId()) | |||||
| setRunId(undefined) | |||||
| setIsStopQuery(true) | |||||
| } | } | ||||
| const startQueryStatus = () => { | |||||
| const runId = setInterval(async () => { | |||||
| // It's so strange that the interval can't be cleared after the clearInterval called. And the runId is current. | |||||
| if (!getRunId()) | |||||
| return | |||||
| const startQueryStatus = async () => { | |||||
| if (isStopQueryRef.current) | |||||
| return | |||||
| try { | |||||
| const indexingStatusBatchDetail = await fetchIndexingStatus() | const indexingStatusBatchDetail = await fetchIndexingStatus() | ||||
| const isCompleted = indexingStatusBatchDetail.every(indexingStatusDetail => ['completed', 'error'].includes(indexingStatusDetail.indexing_status)) | |||||
| if (isCompleted) | |||||
| const isCompleted = indexingStatusBatchDetail.every(indexingStatusDetail => ['completed', 'error', 'paused'].includes(indexingStatusDetail.indexing_status)) | |||||
| if (isCompleted) { | |||||
| stopQueryStatus() | stopQueryStatus() | ||||
| }, 2500) | |||||
| setRunId(runId) | |||||
| return | |||||
| } | |||||
| await sleep(2500) | |||||
| await startQueryStatus() | |||||
| } | |||||
| catch (e) { | |||||
| await sleep(2500) | |||||
| await startQueryStatus() | |||||
| } | |||||
| } | } | ||||
| useEffect(() => { | useEffect(() => { | ||||
| fetchIndexingStatus() | |||||
| startQueryStatus() | startQueryStatus() | ||||
| return () => { | return () => { | ||||
| stopQueryStatus() | stopQueryStatus() | ||||
| } | } | ||||
| // eslint-disable-next-line react-hooks/exhaustive-deps | |||||
| }, []) | }, []) | ||||
| // get rule | // get rule | ||||
| return indexingStatusBatchDetail.some(indexingStatusDetail => ['indexing', 'splitting', 'parsing', 'cleaning'].includes(indexingStatusDetail?.indexing_status || '')) | return indexingStatusBatchDetail.some(indexingStatusDetail => ['indexing', 'splitting', 'parsing', 'cleaning'].includes(indexingStatusDetail?.indexing_status || '')) | ||||
| }, [indexingStatusBatchDetail]) | }, [indexingStatusBatchDetail]) | ||||
| const isEmbeddingCompleted = useMemo(() => { | const isEmbeddingCompleted = useMemo(() => { | ||||
| return indexingStatusBatchDetail.every(indexingStatusDetail => ['completed', 'error'].includes(indexingStatusDetail?.indexing_status || '')) | |||||
| return indexingStatusBatchDetail.every(indexingStatusDetail => ['completed', 'error', 'paused'].includes(indexingStatusDetail?.indexing_status || '')) | |||||
| }, [indexingStatusBatchDetail]) | }, [indexingStatusBatchDetail]) | ||||
| const getSourceName = (id: string) => { | const getSourceName = (id: string) => { |
| import type { FC, SVGProps } from 'react' | import type { FC, SVGProps } from 'react' | ||||
| import React, { useCallback, useEffect, useMemo, useState } from 'react' | |||||
| import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' | |||||
| import useSWR from 'swr' | import useSWR from 'swr' | ||||
| import { useRouter } from 'next/navigation' | import { useRouter } from 'next/navigation' | ||||
| import { useContext } from 'use-context-selector' | import { useContext } from 'use-context-selector' | ||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import { omit } from 'lodash-es' | import { omit } from 'lodash-es' | ||||
| import { ArrowRightIcon } from '@heroicons/react/24/solid' | import { ArrowRightIcon } from '@heroicons/react/24/solid' | ||||
| import { useGetState } from 'ahooks' | |||||
| import cn from 'classnames' | import cn from 'classnames' | ||||
| import SegmentCard from '../completed/SegmentCard' | import SegmentCard from '../completed/SegmentCard' | ||||
| import { FieldInfo } from '../metadata' | import { FieldInfo } from '../metadata' | ||||
| import { ToastContext } from '@/app/components/base/toast' | import { ToastContext } from '@/app/components/base/toast' | ||||
| import type { FullDocumentDetail, ProcessRuleResponse } from '@/models/datasets' | import type { FullDocumentDetail, ProcessRuleResponse } from '@/models/datasets' | ||||
| import type { CommonResponse } from '@/models/common' | import type { CommonResponse } from '@/models/common' | ||||
| import { asyncRunSafe } from '@/utils' | |||||
| import { asyncRunSafe, sleep } from '@/utils' | |||||
| import { formatNumber } from '@/utils/format' | import { formatNumber } from '@/utils/format' | ||||
| import { fetchIndexingStatus as doFetchIndexingStatus, fetchIndexingEstimate, fetchProcessRule, pauseDocIndexing, resumeDocIndexing } from '@/service/datasets' | import { fetchIndexingStatus as doFetchIndexingStatus, fetchIndexingEstimate, fetchProcessRule, pauseDocIndexing, resumeDocIndexing } from '@/service/datasets' | ||||
| import DatasetDetailContext from '@/context/dataset-detail' | import DatasetDetailContext from '@/context/dataset-detail' | ||||
| const localDocumentId = docId ?? documentId | const localDocumentId = docId ?? documentId | ||||
| const localIndexingTechnique = indexingType ?? indexingTechnique | const localIndexingTechnique = indexingType ?? indexingTechnique | ||||
| const [indexingStatusDetail, setIndexingStatusDetail, getIndexingStatusDetail] = useGetState<any>(null) | |||||
| const [indexingStatusDetail, setIndexingStatusDetail] = useState<any>(null) | |||||
| const fetchIndexingStatus = async () => { | const fetchIndexingStatus = async () => { | ||||
| try { | |||||
| const status = await doFetchIndexingStatus({ datasetId: localDatasetId, documentId: localDocumentId }) | |||||
| setIndexingStatusDetail(status) | |||||
| // eslint-disable-next-line @typescript-eslint/no-use-before-define | |||||
| startQueryStatus() | |||||
| } | |||||
| catch (err) { | |||||
| // eslint-disable-next-line @typescript-eslint/no-use-before-define | |||||
| stopQueryStatus() | |||||
| notify({ type: 'error', message: `error: ${err}` }) | |||||
| } | |||||
| const status = await doFetchIndexingStatus({ datasetId: localDatasetId, documentId: localDocumentId }) | |||||
| setIndexingStatusDetail(status) | |||||
| return status | |||||
| } | } | ||||
| const [runId, setRunId, getRunId] = useGetState<any>(null) | |||||
| const [isStopQuery, setIsStopQuery] = useState(false) | |||||
| const isStopQueryRef = useRef(isStopQuery) | |||||
| useEffect(() => { | |||||
| isStopQueryRef.current = isStopQuery | |||||
| }, [isStopQuery]) | |||||
| const stopQueryStatus = () => { | const stopQueryStatus = () => { | ||||
| clearInterval(getRunId()) | |||||
| setIsStopQuery(true) | |||||
| } | } | ||||
| const startQueryStatus = () => { | |||||
| const runId = setInterval(() => { | |||||
| const indexingStatusDetail = getIndexingStatusDetail() | |||||
| if (indexingStatusDetail?.indexing_status === 'completed') { | |||||
| const startQueryStatus = async () => { | |||||
| if (isStopQueryRef.current) | |||||
| return | |||||
| try { | |||||
| const indexingStatusDetail = await fetchIndexingStatus() | |||||
| if (['completed', 'error', 'paused'].includes(indexingStatusDetail?.indexing_status)) { | |||||
| stopQueryStatus() | stopQueryStatus() | ||||
| detailUpdate() | detailUpdate() | ||||
| return | return | ||||
| } | } | ||||
| fetchIndexingStatus() | |||||
| }, 2500) | |||||
| setRunId(runId) | |||||
| await sleep(2500) | |||||
| await startQueryStatus() | |||||
| } | |||||
| catch (e) { | |||||
| await sleep(2500) | |||||
| await startQueryStatus() | |||||
| } | |||||
| } | } | ||||
| useEffect(() => { | useEffect(() => { | ||||
| fetchIndexingStatus() | |||||
| setIsStopQuery(false) | |||||
| startQueryStatus() | |||||
| return () => { | return () => { | ||||
| stopQueryStatus() | stopQueryStatus() | ||||
| } | } | ||||
| // eslint-disable-next-line react-hooks/exhaustive-deps | |||||
| }, []) | }, []) | ||||
| const { data: indexingEstimateDetail, error: indexingEstimateErr } = useSWR({ | const { data: indexingEstimateDetail, error: indexingEstimateErr } = useSWR({ | ||||
| ) | ) | ||||
| } | } | ||||
| export default EmbeddingDetail | |||||
| export default React.memo(EmbeddingDetail) |
| import { TransferMethod, type VisionFile, type VisionSettings } from '@/types/app' | import { TransferMethod, type VisionFile, type VisionSettings } from '@/types/app' | ||||
| import { NodeRunningStatus, WorkflowRunningStatus } from '@/app/components/workflow/types' | import { NodeRunningStatus, WorkflowRunningStatus } from '@/app/components/workflow/types' | ||||
| import type { WorkflowProcess } from '@/app/components/base/chat/types' | import type { WorkflowProcess } from '@/app/components/base/chat/types' | ||||
| import { sleep } from '@/utils' | |||||
| export type IResultProps = { | export type IResultProps = { | ||||
| isWorkflow: boolean | isWorkflow: boolean | ||||
| onShowRes() | onShowRes() | ||||
| setRespondingTrue() | setRespondingTrue() | ||||
| const startTime = Date.now() | |||||
| let isTimeout = false | |||||
| const runId = setInterval(() => { | |||||
| if (Date.now() - startTime > 1000 * 60) { // 1min timeout | |||||
| clearInterval(runId) | |||||
| let isEnd = false | |||||
| let isTimeout = false; | |||||
| (async () => { | |||||
| await sleep(1000 * 60) // 1min timeout | |||||
| if (!isEnd) { | |||||
| setRespondingFalse() | setRespondingFalse() | ||||
| onCompleted(getCompletionRes(), taskId, false) | onCompleted(getCompletionRes(), taskId, false) | ||||
| isTimeout = true | isTimeout = true | ||||
| } | } | ||||
| }, 1000) | |||||
| })() | |||||
| if (isWorkflow) { | if (isWorkflow) { | ||||
| sendWorkflowMessage( | sendWorkflowMessage( | ||||
| notify({ type: 'error', message: data.error }) | notify({ type: 'error', message: data.error }) | ||||
| setRespondingFalse() | setRespondingFalse() | ||||
| onCompleted(getCompletionRes(), taskId, false) | onCompleted(getCompletionRes(), taskId, false) | ||||
| clearInterval(runId) | |||||
| isEnd = true | |||||
| return | return | ||||
| } | } | ||||
| setWorkflowProccessData(produce(getWorkflowProccessData()!, (draft) => { | setWorkflowProccessData(produce(getWorkflowProccessData()!, (draft) => { | ||||
| setRespondingFalse() | setRespondingFalse() | ||||
| setMessageId(tempMessageId) | setMessageId(tempMessageId) | ||||
| onCompleted(getCompletionRes(), taskId, true) | onCompleted(getCompletionRes(), taskId, true) | ||||
| clearInterval(runId) | |||||
| isEnd = true | |||||
| }, | }, | ||||
| }, | }, | ||||
| isInstalledApp, | isInstalledApp, | ||||
| setRespondingFalse() | setRespondingFalse() | ||||
| setMessageId(tempMessageId) | setMessageId(tempMessageId) | ||||
| onCompleted(getCompletionRes(), taskId, true) | onCompleted(getCompletionRes(), taskId, true) | ||||
| clearInterval(runId) | |||||
| isEnd = true | |||||
| }, | }, | ||||
| onMessageReplace: (messageReplace) => { | onMessageReplace: (messageReplace) => { | ||||
| res = [messageReplace.answer] | res = [messageReplace.answer] | ||||
| return | return | ||||
| setRespondingFalse() | setRespondingFalse() | ||||
| onCompleted(getCompletionRes(), taskId, false) | onCompleted(getCompletionRes(), taskId, false) | ||||
| clearInterval(runId) | |||||
| isEnd = true | |||||
| }, | }, | ||||
| }, isInstalledApp, installedAppInfo?.id) | }, isInstalledApp, installedAppInfo?.id) | ||||
| } | } |