import { useId, useRef, useState, type KeyboardEvent } from 'react' import { BadgeCheck, Boxes, Cpu, Image, ScanSearch } from 'lucide-react' interface AiPipelineIllustrationProps { hasImagery: boolean hasTiles: boolean gpuReady: boolean hasDetections: boolean hasQualityEvidence: boolean running: boolean } const pipelineStages = [ { key: 'imagery', label: 'Orthofoto', title: 'Gegeorefereerd bronbeeld', detail: 'CRS, resolutie en ruimtelijke dekking blijven bij de dataset bewaard.', icon: Image }, { key: 'tiles', label: 'Beeldtegels', title: 'Beeld opgedeeld in controleerbare tegels', detail: 'Elke tegel houdt zijn overlap en herkomst bij, zodat elke detectie terug te voeren is op de bronpixel.', icon: Boxes }, { key: 'gpu', label: 'Berekening', title: 'De herkenning draait lokaal', detail: 'De analyse gebruikt de GPU van de server. Is die niet beschikbaar, dan stopt de analyse in plaats van een resultaat te maken waarop u niet kunt bouwen.', icon: Cpu }, { key: 'detections', label: 'Detecties', title: 'Gegeorefereerde gebouwobjecten', detail: 'Confidence, modelversie, brontegel en geometrie worden als reproduceerbaar resultaat bewaard.', icon: ScanSearch }, { key: 'quality', label: 'QA-bewijs', title: 'Controle vóór vrijgave', detail: 'Precision, recall, IoU en foutbewijs bepalen of een resultaat alleen verkennend of operationeel bruikbaar is.', icon: BadgeCheck }, ] as const export function AiPipelineIllustration({ hasImagery, hasTiles, gpuReady, hasDetections, hasQualityEvidence, running, }: AiPipelineIllustrationProps): JSX.Element { const readiness = [hasImagery, hasTiles, gpuReady, hasDetections, hasQualityEvidence] const firstIncomplete = readiness.findIndex((ready) => !ready) const [selectedIndex, setSelectedIndex] = useState(firstIncomplete === -1 ? 4 : firstIncomplete) const tabRefs = useRef>([]) const componentId = useId() const titleId = `${componentId}-title` const panelId = `${componentId}-panel` const selected = pipelineStages[selectedIndex] const selectAndFocus = (index: number) => { setSelectedIndex(index) tabRefs.current[index]?.focus() } const handleTabKeyDown = (event: KeyboardEvent, index: number) => { let nextIndex: number | null = null switch (event.key) { case 'ArrowRight': nextIndex = (index + 1) % pipelineStages.length break case 'ArrowLeft': nextIndex = (index - 1 + pipelineStages.length) % pipelineStages.length break case 'Home': nextIndex = 0 break case 'End': nextIndex = pipelineStages.length - 1 break default: return } event.preventDefault() selectAndFocus(nextIndex) } return (

Van pixel naar bewijs

Van luchtbeeld naar controleerbare detectie

Open een schakel om te zien welke technische context GeoIntel door de volledige analyse bewaart.

{gpuReady ? 'GPU gereed' : 'GPU controleren'}
{String(selectedIndex + 1).padStart(2, '0')}
{selected.title}

{selected.detail}

) }