|
|
import { useState, useCallback, useRef } from 'react' |
|
|
import { apiClient } from '../api/client' |
|
|
import type { SegmentationResult } from '../types' |
|
|
|
|
|
export function useSegmentation() { |
|
|
const [result, setResult] = useState<SegmentationResult | null>(null) |
|
|
const [isLoading, setIsLoading] = useState(false) |
|
|
const [error, setError] = useState<string | null>(null) |
|
|
|
|
|
|
|
|
|
|
|
const currentRequestRef = useRef<number>(0) |
|
|
const abortControllerRef = useRef<AbortController | null>(null) |
|
|
|
|
|
const runSegmentation = useCallback(async (caseId: string, fastMode = true) => { |
|
|
|
|
|
abortControllerRef.current?.abort() |
|
|
const abortController = new AbortController() |
|
|
abortControllerRef.current = abortController |
|
|
|
|
|
|
|
|
const requestToken = ++currentRequestRef.current |
|
|
|
|
|
setIsLoading(true) |
|
|
setError(null) |
|
|
|
|
|
try { |
|
|
const data = await apiClient.runSegmentation(caseId, fastMode, abortController.signal) |
|
|
|
|
|
|
|
|
|
|
|
if (requestToken !== currentRequestRef.current) return |
|
|
|
|
|
setResult({ |
|
|
dwiUrl: data.dwiUrl, |
|
|
predictionUrl: data.predictionUrl, |
|
|
metrics: { |
|
|
caseId: data.caseId, |
|
|
diceScore: data.diceScore, |
|
|
volumeMl: data.volumeMl, |
|
|
elapsedSeconds: data.elapsedSeconds, |
|
|
}, |
|
|
}) |
|
|
} catch (err) { |
|
|
|
|
|
if (err instanceof Error && err.name === 'AbortError') return |
|
|
|
|
|
|
|
|
if (requestToken !== currentRequestRef.current) return |
|
|
|
|
|
const message = err instanceof Error ? err.message : 'Unknown error' |
|
|
setError(message) |
|
|
setResult(null) |
|
|
} finally { |
|
|
|
|
|
if (requestToken === currentRequestRef.current) { |
|
|
setIsLoading(false) |
|
|
} |
|
|
} |
|
|
}, []) |
|
|
|
|
|
return { result, isLoading, error, runSegmentation } |
|
|
} |
|
|
|