611 lines
23 KiB
TypeScript
611 lines
23 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import { datasetsApi, detectionApi } from '../services/api'
|
|
import type {
|
|
DatasetCreateResponse,
|
|
DetectionModelCapability,
|
|
DetectionQaResult,
|
|
DetectionRead,
|
|
DetectionRunRead,
|
|
DetectionRunResponse,
|
|
JobRead,
|
|
ModelAssetRead,
|
|
QualityCheckRead,
|
|
YoloPreflightResponse,
|
|
} from '../types'
|
|
import { formatError } from '../lib/formatError'
|
|
|
|
interface DetectionWorkflowOptions {
|
|
selectedProjectId: string | null
|
|
rasterDatasets: DatasetCreateResponse[]
|
|
qaIouThreshold: number
|
|
loadProjectData: (projectId: string) => Promise<unknown>
|
|
loadQualityChecks: (projectId?: string | null) => Promise<QualityCheckRead[] | void>
|
|
}
|
|
|
|
interface DetectionOperatorProfileSelection {
|
|
modelAssetId: string
|
|
confidenceThreshold: number
|
|
}
|
|
|
|
export type DetectionWorkflowStage =
|
|
| 'idle'
|
|
| 'uploading'
|
|
| 'ready'
|
|
| 'tiling'
|
|
| 'validating'
|
|
| 'detecting'
|
|
| 'loading'
|
|
| 'complete'
|
|
| 'failed'
|
|
|
|
export interface DetectionCalibrationRunRow {
|
|
threshold: number
|
|
status: 'queued' | 'running' | 'success' | 'failed'
|
|
analysis_run_id?: string | null
|
|
job_id?: string | null
|
|
quality_check_id?: string | null
|
|
detection_count?: number | null
|
|
precision?: number | null
|
|
recall?: number | null
|
|
f1_score?: number | null
|
|
false_positives?: number | null
|
|
false_negatives?: number | null
|
|
message?: string | null
|
|
}
|
|
|
|
function parseCalibrationThresholds(value: string): number[] {
|
|
const tokens = value
|
|
.split(/[\s,;]+/)
|
|
.map((token) => token.trim())
|
|
.filter(Boolean)
|
|
const thresholds: number[] = []
|
|
for (const token of tokens) {
|
|
const threshold = Number(token)
|
|
if (!Number.isFinite(threshold) || threshold < 0 || threshold > 1) {
|
|
return []
|
|
}
|
|
if (!thresholds.includes(threshold)) {
|
|
thresholds.push(threshold)
|
|
}
|
|
}
|
|
return thresholds
|
|
}
|
|
|
|
function tileManifestPathFromJob(job: JobRead): string | null {
|
|
const manifestPath = job.result_json?.manifest_path
|
|
return typeof manifestPath === 'string' && manifestPath.trim().length > 0 ? manifestPath.trim() : null
|
|
}
|
|
|
|
function rasterTileCount(metadata: Record<string, unknown>, tileSize: number, overlap: number): number | null {
|
|
const width = metadata.width
|
|
const height = metadata.height
|
|
if (typeof width !== 'number' || typeof height !== 'number' || width <= 0 || height <= 0) {
|
|
return null
|
|
}
|
|
const step = tileSize - overlap
|
|
return Math.ceil(width / step) * Math.ceil(height / step)
|
|
}
|
|
|
|
export function useDetectionWorkflow({
|
|
selectedProjectId,
|
|
rasterDatasets,
|
|
qaIouThreshold,
|
|
loadProjectData,
|
|
loadQualityChecks,
|
|
}: DetectionWorkflowOptions) {
|
|
const [detectionModels, setDetectionModels] = useState<DetectionModelCapability[]>([])
|
|
const [modelAssets, setModelAssets] = useState<ModelAssetRead[]>([])
|
|
const [loadingDetectionModels, setLoadingDetectionModels] = useState(false)
|
|
const [detectionModelError, setDetectionModelError] = useState<string | null>(null)
|
|
const [modelAssetError, setModelAssetError] = useState<string | null>(null)
|
|
const [selectedDetectionDatasetId, setSelectedDetectionDatasetId] = useState('')
|
|
const [selectedDetectionModelId, setSelectedDetectionModelId] = useState('yolo-configured')
|
|
const [selectedModelAssetId, setSelectedModelAssetId] = useState('')
|
|
const [detectionTileManifestPath, setDetectionTileManifestPath] = useState('')
|
|
const [detectionConfidenceThreshold, setDetectionConfidenceThreshold] = useState(0.15)
|
|
const [runningDetection, setRunningDetection] = useState(false)
|
|
const [detectionRunResult, setDetectionRunResult] = useState<DetectionRunResponse | null>(null)
|
|
const [detectionRunError, setDetectionRunError] = useState<string | null>(null)
|
|
const [detectionRuns, setDetectionRuns] = useState<DetectionRunRead[]>([])
|
|
const [selectedDetectionRunId, setSelectedDetectionRunId] = useState('')
|
|
const [detectionItems, setDetectionItems] = useState<DetectionRead[]>([])
|
|
const [detectionGeoJson, setDetectionGeoJson] = useState<GeoJSON.FeatureCollection | null>(null)
|
|
const [detectionClassFilter, setDetectionClassFilter] = useState('')
|
|
const [detectionMinConfidenceFilter, setDetectionMinConfidenceFilter] = useState(0)
|
|
const [loadingDetectionResults, setLoadingDetectionResults] = useState(false)
|
|
const [detectionReferenceDatasetId, setDetectionReferenceDatasetId] = useState('')
|
|
const [detectionQaResult, setDetectionQaResult] = useState<DetectionQaResult | null>(null)
|
|
const [detectionQaError, setDetectionQaError] = useState<string | null>(null)
|
|
const [runningDetectionQa, setRunningDetectionQa] = useState(false)
|
|
const [yoloPreflight, setYoloPreflight] = useState<YoloPreflightResponse | null>(null)
|
|
const [loadingYoloPreflight, setLoadingYoloPreflight] = useState(false)
|
|
const [yoloPreflightError, setYoloPreflightError] = useState<string | null>(null)
|
|
const [calibrationThresholdText, setCalibrationThresholdText] = useState('0.50 0.25 0.15')
|
|
const [runningDetectionCalibration, setRunningDetectionCalibration] = useState(false)
|
|
const [detectionCalibrationRows, setDetectionCalibrationRows] = useState<DetectionCalibrationRunRow[]>([])
|
|
const [detectionCalibrationError, setDetectionCalibrationError] = useState<string | null>(null)
|
|
const [detectionWorkflowStage, setDetectionWorkflowStage] = useState<DetectionWorkflowStage>('idle')
|
|
|
|
useEffect(() => {
|
|
if (!selectedDetectionDatasetId && rasterDatasets.length > 0) {
|
|
setSelectedDetectionDatasetId(rasterDatasets[0].id)
|
|
}
|
|
}, [rasterDatasets, selectedDetectionDatasetId])
|
|
|
|
const loadDetectionModels = async () => {
|
|
setLoadingDetectionModels(true)
|
|
setDetectionModelError(null)
|
|
setModelAssetError(null)
|
|
try {
|
|
const response = await detectionApi.listModels()
|
|
setDetectionModels(response.models)
|
|
const selectedModelStillAvailable = response.models.some((model) => model.model_id === selectedDetectionModelId)
|
|
if (!selectedModelStillAvailable && response.models.length > 0) {
|
|
const configuredModel = response.models.find(
|
|
(model) => model.configured && model.model_id !== 'manual-fixture-detector',
|
|
)
|
|
setSelectedDetectionModelId(configuredModel?.model_id ?? response.models[0].model_id)
|
|
}
|
|
} catch (error) {
|
|
setDetectionModelError(formatError(error, 'Failed to load detection models'))
|
|
}
|
|
try {
|
|
const assetResponse = await detectionApi.listModelAssets()
|
|
setModelAssets(assetResponse.items)
|
|
const activeAsset = assetResponse.items.find((asset) => asset.active) ?? null
|
|
const selectedAssetStillAvailable = assetResponse.items.some((asset) => asset.model_asset_id === selectedModelAssetId)
|
|
const nextAssetId = selectedAssetStillAvailable ? selectedModelAssetId : activeAsset?.model_asset_id ?? ''
|
|
setSelectedModelAssetId(nextAssetId)
|
|
try {
|
|
const preflight = await detectionApi.getYoloPreflight({ model_asset_id: nextAssetId || null })
|
|
setYoloPreflight(preflight)
|
|
setYoloPreflightError(null)
|
|
} catch (error) {
|
|
setYoloPreflightError(formatError(error, 'Failed to load YOLO preflight status'))
|
|
}
|
|
} catch (error) {
|
|
setModelAssets([])
|
|
setModelAssetError(formatError(error, 'Failed to load local model assets'))
|
|
} finally {
|
|
setLoadingDetectionModels(false)
|
|
}
|
|
}
|
|
|
|
const loadYoloPreflight = async (tileManifestPath = detectionTileManifestPath) => {
|
|
setLoadingYoloPreflight(true)
|
|
setYoloPreflightError(null)
|
|
try {
|
|
const response = await detectionApi.getYoloPreflight({
|
|
tile_manifest_path: tileManifestPath.trim() || null,
|
|
model_asset_id: selectedModelAssetId || null,
|
|
})
|
|
setYoloPreflight(response)
|
|
} catch (error) {
|
|
setYoloPreflightError(formatError(error, 'Failed to load YOLO preflight status'))
|
|
} finally {
|
|
setLoadingYoloPreflight(false)
|
|
}
|
|
}
|
|
|
|
const loadDetectionRuns = async (projectId = selectedProjectId) => {
|
|
if (!projectId) {
|
|
setDetectionRuns([])
|
|
return
|
|
}
|
|
try {
|
|
const response = await detectionApi.listRuns({ project_id: projectId })
|
|
setDetectionRuns(response.items)
|
|
if (!selectedDetectionRunId && response.items.length > 0) {
|
|
setSelectedDetectionRunId(response.items[0].id)
|
|
}
|
|
} catch (error) {
|
|
setDetectionRunError(formatError(error, 'Failed to load detection runs'))
|
|
}
|
|
}
|
|
|
|
const loadDetectionResults = async (analysisRunId = selectedDetectionRunId) => {
|
|
if (!analysisRunId) {
|
|
setDetectionItems([])
|
|
setDetectionGeoJson(null)
|
|
return
|
|
}
|
|
setLoadingDetectionResults(true)
|
|
setDetectionRunError(null)
|
|
try {
|
|
const params = {
|
|
class_name: detectionClassFilter || null,
|
|
min_confidence: detectionMinConfidenceFilter > 0 ? detectionMinConfidenceFilter : null,
|
|
}
|
|
const [detectionsResponse, geoJsonResponse] = await Promise.all([
|
|
detectionApi.listDetections(analysisRunId, params),
|
|
detectionApi.getRunGeoJson(analysisRunId, params),
|
|
])
|
|
setDetectionItems(detectionsResponse.items)
|
|
setDetectionGeoJson(geoJsonResponse)
|
|
} catch (error) {
|
|
setDetectionRunError(formatError(error, 'Failed to load detection results'))
|
|
} finally {
|
|
setLoadingDetectionResults(false)
|
|
}
|
|
}
|
|
|
|
const executeDetection = async (
|
|
projectId: string,
|
|
datasetId: string,
|
|
manifestPath: string | null,
|
|
modelId = selectedDetectionModelId,
|
|
modelAssetId = selectedModelAssetId,
|
|
) => {
|
|
const result = await detectionApi.run({
|
|
project_id: projectId,
|
|
dataset_id: datasetId,
|
|
model_id: modelId,
|
|
model_asset_id: modelAssetId || null,
|
|
confidence_threshold: detectionConfidenceThreshold,
|
|
tile_manifest_path: manifestPath,
|
|
parameters_json: {},
|
|
})
|
|
setDetectionRunResult(result)
|
|
setSelectedDetectionRunId(result.analysis_run_id)
|
|
setDetectionWorkflowStage('loading')
|
|
await loadDetectionRuns(projectId)
|
|
await loadDetectionResults(result.analysis_run_id)
|
|
await loadProjectData(projectId)
|
|
return result
|
|
}
|
|
|
|
const runDetection = async () => {
|
|
if (!selectedProjectId) {
|
|
setDetectionRunError('Select a project first')
|
|
return
|
|
}
|
|
const datasetId = selectedDetectionDatasetId || rasterDatasets[0]?.id
|
|
if (!datasetId) {
|
|
setDetectionRunError('Select a raster dataset')
|
|
return
|
|
}
|
|
setDetectionRunError(null)
|
|
setDetectionRunResult(null)
|
|
setRunningDetection(true)
|
|
setDetectionWorkflowStage('detecting')
|
|
try {
|
|
await executeDetection(selectedProjectId, datasetId, detectionTileManifestPath.trim() || null)
|
|
setDetectionWorkflowStage('complete')
|
|
} catch (error) {
|
|
setDetectionRunError(formatError(error, 'Detection run failed'))
|
|
setDetectionWorkflowStage('failed')
|
|
} finally {
|
|
setRunningDetection(false)
|
|
}
|
|
}
|
|
|
|
const uploadDetectionRaster = async (file: File): Promise<boolean> => {
|
|
if (!selectedProjectId) {
|
|
setDetectionRunError('De regionale werkruimte is nog niet geladen')
|
|
return false
|
|
}
|
|
setDetectionRunError(null)
|
|
setDetectionWorkflowStage('uploading')
|
|
try {
|
|
const dataset = await datasetsApi.upload(selectedProjectId, {
|
|
file,
|
|
datasetType: 'raster',
|
|
source: 'user_upload',
|
|
datasetRole: 'source',
|
|
sourceName: 'manual',
|
|
sourceMetadataJson: JSON.stringify({ purpose: 'building_detection' }),
|
|
provenanceMetadataJson: JSON.stringify({ original_filename: file.name, acquisition: 'explicit_user_upload' }),
|
|
})
|
|
setSelectedDetectionDatasetId(dataset.id)
|
|
setDetectionTileManifestPath('')
|
|
setDetectionRunResult(null)
|
|
setDetectionWorkflowStage('ready')
|
|
await loadProjectData(selectedProjectId)
|
|
return true
|
|
} catch (error) {
|
|
setDetectionRunError(formatError(error, 'Het luchtbeeld kon niet worden toegevoegd'))
|
|
setDetectionWorkflowStage('failed')
|
|
return false
|
|
}
|
|
}
|
|
|
|
const prepareAndRunDetection = async (
|
|
datasetIdOverride?: string,
|
|
modelIdOverride?: string,
|
|
): Promise<DetectionRunResponse | null> => {
|
|
if (!selectedProjectId) {
|
|
setDetectionRunError('De regionale werkruimte is nog niet geladen')
|
|
return null
|
|
}
|
|
const datasetId = datasetIdOverride || selectedDetectionDatasetId || rasterDatasets[0]?.id
|
|
if (!datasetId) {
|
|
setDetectionRunError('Kies of voeg eerst een gegeorefereerd luchtbeeld toe')
|
|
return null
|
|
}
|
|
const effectiveModelId = modelIdOverride || selectedDetectionModelId
|
|
const effectiveModelAssetId = effectiveModelId === 'yolo-configured'
|
|
? modelAssets.find((asset) => asset.active)?.model_asset_id ?? selectedModelAssetId
|
|
: selectedModelAssetId
|
|
const selectedModel = detectionModels.find((model) => model.model_id === effectiveModelId)
|
|
if (!selectedModel?.configured || effectiveModelId === 'manual-fixture-detector') {
|
|
setDetectionRunError(selectedModel?.limitation_message ?? 'Het gekozen analysemodel is niet beschikbaar')
|
|
return null
|
|
}
|
|
if (effectiveModelId === 'yolo-configured' && modelAssets.length > 0 && !effectiveModelAssetId) {
|
|
setDetectionRunError('Kies eerst een lokaal modelbestand')
|
|
return null
|
|
}
|
|
|
|
setDetectionRunError(null)
|
|
setDetectionRunResult(null)
|
|
setRunningDetection(true)
|
|
try {
|
|
let manifestPath = detectionTileManifestPath.trim()
|
|
if (!manifestPath) {
|
|
setDetectionWorkflowStage('tiling')
|
|
const inspection = await datasetsApi.rasterInspect(selectedProjectId, datasetId)
|
|
const expectedTileCount = rasterTileCount(inspection.metadata, 512, 64)
|
|
const maxTiles = yoloPreflight?.max_tiles ?? 256
|
|
if (expectedTileCount === null) {
|
|
throw new Error('De afmetingen van het luchtbeeld konden niet veilig worden bepaald')
|
|
}
|
|
if (expectedTileCount > maxTiles) {
|
|
throw new Error(
|
|
`Dit luchtbeeld zou ${expectedTileCount} beeldtegels maken; het veilige maximum is ${maxTiles}. Knip het beeld eerst tot het gewenste werkgebied.`,
|
|
)
|
|
}
|
|
const tileJob = await datasetsApi.rasterTile(selectedProjectId, datasetId, {
|
|
tile_size: 512,
|
|
overlap: 64,
|
|
})
|
|
manifestPath = tileManifestPathFromJob(tileJob) ?? ''
|
|
if (!manifestPath) {
|
|
throw new Error(tileJob.error_message || 'De tegelvoorbereiding leverde geen geldig manifest op')
|
|
}
|
|
setDetectionTileManifestPath(manifestPath)
|
|
}
|
|
|
|
setDetectionWorkflowStage('validating')
|
|
const preflight = await detectionApi.getYoloPreflight({
|
|
tile_manifest_path: manifestPath,
|
|
model_asset_id: effectiveModelAssetId || null,
|
|
})
|
|
setYoloPreflight(preflight)
|
|
setYoloPreflightError(null)
|
|
if (
|
|
!preflight.checks.manifest_valid ||
|
|
!preflight.checks.tile_paths_exist ||
|
|
!preflight.checks.tile_limit_ok ||
|
|
!preflight.checks.dependencies_available ||
|
|
!preflight.checks.model_file_exists
|
|
) {
|
|
throw new Error(preflight.message || 'De beeldtegels of modelruntime zijn niet startklaar')
|
|
}
|
|
|
|
setDetectionWorkflowStage('detecting')
|
|
const result = await executeDetection(
|
|
selectedProjectId,
|
|
datasetId,
|
|
manifestPath,
|
|
effectiveModelId,
|
|
effectiveModelAssetId,
|
|
)
|
|
setDetectionWorkflowStage('complete')
|
|
return result
|
|
} catch (error) {
|
|
setDetectionRunError(formatError(error, 'De beeldanalyse is mislukt'))
|
|
setDetectionWorkflowStage('failed')
|
|
return null
|
|
} finally {
|
|
setRunningDetection(false)
|
|
}
|
|
}
|
|
|
|
const compareDetectionRunWithReference = async (
|
|
analysisRunId: string,
|
|
referenceDatasetId: string,
|
|
useCurrentFilters = true,
|
|
iouThresholdOverride?: number,
|
|
): Promise<DetectionQaResult | null> => {
|
|
if (!analysisRunId) {
|
|
setDetectionQaError('Select a detection run')
|
|
return null
|
|
}
|
|
if (!referenceDatasetId) {
|
|
setDetectionQaError('Select a reference dataset')
|
|
return null
|
|
}
|
|
setSelectedDetectionRunId(analysisRunId)
|
|
setDetectionReferenceDatasetId(referenceDatasetId)
|
|
setDetectionQaError(null)
|
|
setDetectionQaResult(null)
|
|
setRunningDetectionQa(true)
|
|
try {
|
|
const result = await detectionApi.compareWithReference(analysisRunId, {
|
|
reference_dataset_id: referenceDatasetId,
|
|
iou_threshold: iouThresholdOverride ?? qaIouThreshold,
|
|
class_name: useCurrentFilters ? detectionClassFilter || null : null,
|
|
min_confidence: useCurrentFilters && detectionMinConfidenceFilter > 0 ? detectionMinConfidenceFilter : null,
|
|
})
|
|
setDetectionQaResult(result)
|
|
await loadQualityChecks(selectedProjectId)
|
|
return result
|
|
} catch (error) {
|
|
setDetectionQaError(formatError(error, 'Detection QA failed'))
|
|
return null
|
|
} finally {
|
|
setRunningDetectionQa(false)
|
|
}
|
|
}
|
|
|
|
const runDetectionQa = async (): Promise<DetectionQaResult | null> =>
|
|
compareDetectionRunWithReference(selectedDetectionRunId, detectionReferenceDatasetId)
|
|
|
|
const runDetectionCalibration = async () => {
|
|
if (!selectedProjectId) {
|
|
setDetectionCalibrationError('Select a project before calibration')
|
|
return
|
|
}
|
|
const datasetId = selectedDetectionDatasetId || rasterDatasets[0]?.id
|
|
if (!datasetId) {
|
|
setDetectionCalibrationError('Select a raster dataset before calibration')
|
|
return
|
|
}
|
|
if (!detectionReferenceDatasetId) {
|
|
setDetectionCalibrationError('Select a reference dataset before calibration')
|
|
return
|
|
}
|
|
const selectedModel = detectionModels.find((model) => model.model_id === selectedDetectionModelId)
|
|
if (!selectedModel?.configured || selectedDetectionModelId === 'manual-fixture-detector') {
|
|
setDetectionCalibrationError('Select a configured non-fixture detection model before calibration')
|
|
return
|
|
}
|
|
if (selectedDetectionModelId === 'yolo-configured' && !detectionTileManifestPath.trim()) {
|
|
setDetectionCalibrationError('Configured YOLO calibration requires a tile manifest')
|
|
return
|
|
}
|
|
if (selectedDetectionModelId === 'yolo-configured' && modelAssets.length > 0 && !selectedModelAssetId) {
|
|
setDetectionCalibrationError('Select a local model asset before calibration')
|
|
return
|
|
}
|
|
const thresholds = parseCalibrationThresholds(calibrationThresholdText)
|
|
if (thresholds.length === 0) {
|
|
setDetectionCalibrationError('Provide at least one valid threshold between 0 and 1')
|
|
return
|
|
}
|
|
setDetectionCalibrationError(null)
|
|
setDetectionCalibrationRows(thresholds.map((threshold) => ({ threshold, status: 'queued' })))
|
|
setRunningDetectionCalibration(true)
|
|
try {
|
|
for (const threshold of thresholds) {
|
|
setDetectionCalibrationRows((rows) =>
|
|
rows.map((row) => row.threshold === threshold ? { ...row, status: 'running', message: 'Running detection' } : row),
|
|
)
|
|
try {
|
|
const result = await detectionApi.run({
|
|
project_id: selectedProjectId,
|
|
dataset_id: datasetId,
|
|
model_id: selectedDetectionModelId,
|
|
model_asset_id: selectedModelAssetId || null,
|
|
confidence_threshold: threshold,
|
|
tile_manifest_path: detectionTileManifestPath.trim() || null,
|
|
parameters_json: { calibration: true, calibration_thresholds: thresholds },
|
|
})
|
|
setSelectedDetectionRunId(result.analysis_run_id)
|
|
const qa = await detectionApi.compareWithReference(result.analysis_run_id, {
|
|
reference_dataset_id: detectionReferenceDatasetId,
|
|
iou_threshold: qaIouThreshold,
|
|
class_name: detectionClassFilter || null,
|
|
min_confidence: null,
|
|
})
|
|
setDetectionCalibrationRows((rows) =>
|
|
rows.map((row) => row.threshold === threshold
|
|
? {
|
|
...row,
|
|
status: 'success',
|
|
analysis_run_id: result.analysis_run_id,
|
|
job_id: result.job_id,
|
|
quality_check_id: qa.quality_check_id,
|
|
detection_count: result.detection_count,
|
|
precision: qa.precision ?? null,
|
|
recall: qa.recall ?? null,
|
|
f1_score: qa.f1_score ?? null,
|
|
false_positives: qa.false_positives,
|
|
false_negatives: qa.false_negatives,
|
|
message: result.message,
|
|
}
|
|
: row),
|
|
)
|
|
} catch (error) {
|
|
const message = formatError(error, `Calibration threshold ${threshold} failed`)
|
|
setDetectionCalibrationRows((rows) =>
|
|
rows.map((row) => row.threshold === threshold ? { ...row, status: 'failed', message } : row),
|
|
)
|
|
setDetectionCalibrationError(message)
|
|
break
|
|
}
|
|
}
|
|
await loadDetectionRuns(selectedProjectId)
|
|
await loadQualityChecks(selectedProjectId)
|
|
await loadProjectData(selectedProjectId)
|
|
} finally {
|
|
setRunningDetectionCalibration(false)
|
|
}
|
|
}
|
|
|
|
const applyDetectionOperatorProfile = (profile: DetectionOperatorProfileSelection) => {
|
|
setSelectedDetectionModelId('yolo-configured')
|
|
setSelectedModelAssetId(profile.modelAssetId)
|
|
setDetectionConfidenceThreshold(profile.confidenceThreshold)
|
|
}
|
|
|
|
const resetDetectionForProject = () => {
|
|
setSelectedDetectionDatasetId('')
|
|
setDetectionRuns([])
|
|
setSelectedDetectionRunId('')
|
|
setDetectionItems([])
|
|
setDetectionGeoJson(null)
|
|
setDetectionRunResult(null)
|
|
setDetectionCalibrationRows([])
|
|
setDetectionCalibrationError(null)
|
|
setDetectionWorkflowStage('idle')
|
|
}
|
|
|
|
return {
|
|
detectionModels,
|
|
modelAssets,
|
|
loadingDetectionModels,
|
|
detectionModelError,
|
|
modelAssetError,
|
|
selectedDetectionDatasetId,
|
|
selectedDetectionModelId,
|
|
selectedModelAssetId,
|
|
detectionTileManifestPath,
|
|
detectionConfidenceThreshold,
|
|
runningDetection,
|
|
detectionRunResult,
|
|
detectionRunError,
|
|
detectionRuns,
|
|
selectedDetectionRunId,
|
|
detectionItems,
|
|
detectionGeoJson,
|
|
detectionClassFilter,
|
|
detectionMinConfidenceFilter,
|
|
loadingDetectionResults,
|
|
detectionReferenceDatasetId,
|
|
detectionQaResult,
|
|
detectionQaError,
|
|
runningDetectionQa,
|
|
yoloPreflight,
|
|
loadingYoloPreflight,
|
|
yoloPreflightError,
|
|
calibrationThresholdText,
|
|
runningDetectionCalibration,
|
|
detectionCalibrationRows,
|
|
detectionCalibrationError,
|
|
detectionWorkflowStage,
|
|
loadDetectionModels,
|
|
loadYoloPreflight,
|
|
loadDetectionRuns,
|
|
loadDetectionResults,
|
|
runDetection,
|
|
uploadDetectionRaster,
|
|
prepareAndRunDetection,
|
|
compareDetectionRunWithReference,
|
|
runDetectionQa,
|
|
runDetectionCalibration,
|
|
applyDetectionOperatorProfile,
|
|
resetDetectionForProject,
|
|
setSelectedDetectionDatasetId,
|
|
setSelectedDetectionModelId,
|
|
setSelectedModelAssetId,
|
|
setDetectionTileManifestPath,
|
|
setDetectionConfidenceThreshold,
|
|
setSelectedDetectionRunId,
|
|
setDetectionClassFilter,
|
|
setDetectionMinConfidenceFilter,
|
|
setDetectionReferenceDatasetId,
|
|
setCalibrationThresholdText,
|
|
}
|
|
}
|