Upgrade async GPU analysis and workbench UX
This commit is contained in:
@@ -6,6 +6,7 @@ import type {
|
||||
DetectionRead,
|
||||
DetectionRunRead,
|
||||
DetectionRunResponse,
|
||||
JobRead,
|
||||
ModelAssetRead,
|
||||
QualityCheckRead,
|
||||
YoloPreflightResponse,
|
||||
@@ -15,7 +16,7 @@ import { DETECTION_OPERATOR_PROFILES, type DetectionOperatorProfile } from './de
|
||||
import { DetectionModelManagement, detectionModelLabel } from './DetectionModelManagement'
|
||||
import { AiPipelineIllustration } from './AiPipelineIllustration'
|
||||
import { ModelSelector } from '../models/ModelSelector'
|
||||
import { toAnalysisModelOption } from '../models/modelOptions'
|
||||
import { analysisModelAvailabilityMessage, toAnalysisModelOption } from '../models/modelOptions'
|
||||
|
||||
const DETECTION_PAGE_SIZE_OPTIONS = [25, 50, 100] as const
|
||||
const DEFAULT_DETECTION_PAGE_SIZE = 50
|
||||
@@ -87,6 +88,7 @@ interface DetectionLabProps {
|
||||
detectionTileManifestPath: string
|
||||
detectionConfidenceThreshold: number
|
||||
runningDetection: boolean
|
||||
detectionJob: JobRead | null
|
||||
detectionRunResult: DetectionRunResponse | null
|
||||
detectionRunError: string | null
|
||||
detectionRuns: DetectionRunRead[]
|
||||
@@ -151,6 +153,7 @@ export function DetectionLab({
|
||||
detectionTileManifestPath,
|
||||
detectionConfidenceThreshold,
|
||||
runningDetection,
|
||||
detectionJob,
|
||||
detectionRunResult,
|
||||
detectionRunError,
|
||||
detectionRuns,
|
||||
@@ -208,12 +211,17 @@ export function DetectionLab({
|
||||
const yoloRuntimeReady = Boolean(
|
||||
yoloPreflight?.checks?.enabled &&
|
||||
yoloPreflight.checks?.dependencies_available &&
|
||||
yoloPreflight.checks?.accelerator_ready === true &&
|
||||
yoloPreflight.checks?.model_file_exists,
|
||||
)
|
||||
const detectionRequiresTileManifest = selectedDetectionModelId === 'yolo-configured'
|
||||
const detectionJobActive = detectionJob?.status === 'queued' || detectionJob?.status === 'running'
|
||||
const detectionHasDataset = selectedDetectionDatasetId.length > 0
|
||||
const detectionHasModel = selectedDetectionModel !== null
|
||||
const detectionModelReady = Boolean(selectedDetectionModel?.configured)
|
||||
const selectedDetectionModelAvailability = selectedDetectionModel
|
||||
? analysisModelAvailabilityMessage(selectedDetectionModel)
|
||||
: 'Het gekozen model is niet geconfigureerd'
|
||||
const detectionModelUiRunnable = detectionModelReady && selectedDetectionModelId !== 'manual-fixture-detector'
|
||||
const detectionHasExplicitModelAsset =
|
||||
selectedDetectionModelId !== 'yolo-configured' || modelAssets.length === 0 || selectedModelAssetId.length > 0
|
||||
@@ -259,7 +267,7 @@ export function DetectionLab({
|
||||
: selectedDetectionModelId === 'manual-fixture-detector'
|
||||
? 'Het fixturemodel is alleen bedoeld voor expliciete tests en demo\'s'
|
||||
: !detectionModelReady
|
||||
? selectedDetectionModel?.limitation_message ?? 'Het gekozen model is niet geconfigureerd'
|
||||
? selectedDetectionModelAvailability
|
||||
: !detectionHasExplicitModelAsset
|
||||
? 'Kies een lokaal modelbestand onder beheer'
|
||||
: !detectionHasTileManifest
|
||||
@@ -275,7 +283,7 @@ export function DetectionLab({
|
||||
: selectedDetectionModelId === 'manual-fixture-detector'
|
||||
? 'Het fixturemodel is alleen bedoeld voor expliciete tests en demo\'s'
|
||||
: !detectionModelReady
|
||||
? selectedDetectionModel?.limitation_message ?? 'Het gekozen model is niet geconfigureerd'
|
||||
? selectedDetectionModelAvailability
|
||||
: !detectionHasExplicitModelAsset
|
||||
? 'Kies een lokaal modelbestand onder beheer'
|
||||
: null
|
||||
@@ -499,8 +507,8 @@ export function DetectionLab({
|
||||
<DetectionWorkflowStep label="3. Modelcontrole" complete={detectionWorkflowStage === 'detecting' || detectionWorkflowStage === 'loading' || detectionWorkflowStage === 'complete'} active={detectionWorkflowStage === 'validating'} />
|
||||
<DetectionWorkflowStep label="4. Resultaat" complete={detectionWorkflowStage === 'complete'} active={detectionWorkflowStage === 'detecting' || detectionWorkflowStage === 'loading'} />
|
||||
</div>
|
||||
<button className="primary-action guided-detection-action" type="button" onClick={onPrepareAndRunDetection} disabled={runningDetection || !guidedDetectionReady}>
|
||||
{detectionWorkflowActionLabel(detectionWorkflowStage)}
|
||||
<button className="primary-action guided-detection-action" type="button" onClick={onPrepareAndRunDetection} disabled={runningDetection || runningDetectionCalibration || detectionJobActive || !guidedDetectionReady}>
|
||||
{detectionWorkflowActionLabel(detectionWorkflowStage, detectionJob?.status)}
|
||||
</button>
|
||||
|
||||
{!managementLocked ? <details className="ai-lab-model-surface technical-manifest-surface" aria-label="Technische tegelinstellingen">
|
||||
@@ -528,7 +536,7 @@ export function DetectionLab({
|
||||
<span>De technische controle wordt vernieuwd wanneer het model of tegelbestand wijzigt.</span>
|
||||
</div>
|
||||
) : null}
|
||||
<button className="secondary-action" type="button" onClick={onRunDetection} disabled={runningDetection || !detectionRunReady}>
|
||||
<button className="secondary-action" type="button" onClick={onRunDetection} disabled={runningDetection || runningDetectionCalibration || detectionJobActive || !detectionRunReady}>
|
||||
Bestaande beeldtegels analyseren
|
||||
</button>
|
||||
</div>
|
||||
@@ -537,15 +545,26 @@ export function DetectionLab({
|
||||
</div>
|
||||
|
||||
<div className="ai-lab-state-stack">
|
||||
{detectionJob && (detectionJob.status === 'queued' || detectionJob.status === 'running') ? (
|
||||
<div className="result-state" role="status" aria-live="polite">
|
||||
<strong>{detectionJob.status === 'queued' ? 'GPU-taak staat in de wachtrij.' : 'GPU-analyse wordt uitgevoerd.'}</strong>
|
||||
<p>
|
||||
{detectionJob.status === 'queued'
|
||||
? 'De server heeft de aanvraag veilig bewaard en start ze zodra de NVIDIA-worker beschikbaar is.'
|
||||
: 'Het model verwerkt de beeldtegels op de server. Dit scherm volgt de bewaarde taak automatisch.'}
|
||||
</p>
|
||||
<span className="muted">Taak-ID: {detectionJob.id}</span>
|
||||
</div>
|
||||
) : null}
|
||||
{detectionRunError ? (
|
||||
<div className="result-state result-state-error">
|
||||
<strong>De beeldanalyse is mislukt.</strong>
|
||||
<div className="result-state result-state-error" role="alert">
|
||||
<strong>{detectionJobActive ? 'Het volgen van de servertaak is onderbroken.' : 'De beeldanalyse is mislukt.'}</strong>
|
||||
<p>{detectionRunError}</p>
|
||||
</div>
|
||||
) : null}
|
||||
{detectionRunResult ? (
|
||||
<div className="result-summary-card">
|
||||
<p>Status: {detectionRunResult.status === 'completed' ? 'afgerond' : detectionRunResult.status}</p>
|
||||
<div className={detectionRunResult.detection_count === 0 ? 'result-state result-state-warning' : 'result-summary-card'} role="status">
|
||||
<p>Status: {detectionStatusLabel(detectionRunResult.status)}</p>
|
||||
<p>{detectionRunResult.message}</p>
|
||||
<p>Gevonden objecten: {detectionRunResult.detection_count}</p>
|
||||
{detectionRunResult.error_code ? <p className="error">Code: {detectionRunResult.error_code}</p> : null}
|
||||
@@ -602,7 +621,7 @@ export function DetectionLab({
|
||||
className="primary-action"
|
||||
type="button"
|
||||
onClick={onRunCalibration}
|
||||
disabled={runningDetectionCalibration || !calibrationRunReady}
|
||||
disabled={runningDetectionCalibration || runningDetection || detectionJobActive || !calibrationRunReady}
|
||||
>
|
||||
Drempels vergelijken
|
||||
</button>
|
||||
@@ -927,7 +946,7 @@ export function DetectionLab({
|
||||
) : null}
|
||||
{detectionQaResult ? (
|
||||
<div className="result-summary-card">
|
||||
<p>Status: {detectionQaResult.status === 'completed' ? 'afgerond' : detectionQaResult.status}</p>
|
||||
<p>Status: {detectionStatusLabel(detectionQaResult.status)}</p>
|
||||
<p>Precisie: {detectionQaResult.precision?.toFixed(3) ?? 'n.v.t.'}</p>
|
||||
<p>Herkenningsgraad: {detectionQaResult.recall?.toFixed(3) ?? 'n.v.t.'}</p>
|
||||
<p>F1: {detectionQaResult.f1_score?.toFixed(3) ?? 'n.v.t.'}</p>
|
||||
@@ -1042,10 +1061,11 @@ function DetectionWorkflowStep({
|
||||
)
|
||||
}
|
||||
|
||||
function detectionWorkflowActionLabel(stage: DetectionWorkflowStage): string {
|
||||
function detectionWorkflowActionLabel(stage: DetectionWorkflowStage, jobStatus?: string): string {
|
||||
if (stage === 'tiling') return 'Beeldtegels voorbereiden...'
|
||||
if (stage === 'validating') return 'Model en beeld controleren...'
|
||||
if (stage === 'detecting') return 'Gebouwen zoeken...'
|
||||
if (stage === 'detecting' && jobStatus === 'queued') return 'Wachten op NVIDIA GPU...'
|
||||
if (stage === 'detecting') return 'Gebouwen zoeken op NVIDIA GPU...'
|
||||
if (stage === 'loading') return 'Resultaat op kaart laden...'
|
||||
if (stage === 'complete') return 'Analyse opnieuw uitvoeren'
|
||||
return 'Gebouwen zoeken en op kaart tonen'
|
||||
|
||||
Reference in New Issue
Block a user