Initial GeoIntel V1 foundation
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
import type {
|
||||
DatasetCreateResponse,
|
||||
DetectionModelCapability,
|
||||
DetectionQaResult,
|
||||
DetectionRead,
|
||||
DetectionRunRead,
|
||||
DetectionRunResponse,
|
||||
} from '../../types'
|
||||
|
||||
interface DetectionLabProps {
|
||||
detectionModels: DetectionModelCapability[]
|
||||
loadingDetectionModels: boolean
|
||||
detectionModelError: string | null
|
||||
selectedDetectionDatasetId: string
|
||||
selectedDetectionModelId: string
|
||||
detectionTileManifestPath: string
|
||||
detectionConfidenceThreshold: number
|
||||
runningDetection: boolean
|
||||
detectionRunResult: DetectionRunResponse | null
|
||||
detectionRunError: string | null
|
||||
detectionRuns: DetectionRunRead[]
|
||||
selectedDetectionRunId: string
|
||||
detectionItems: DetectionRead[]
|
||||
detectionClassFilter: string
|
||||
detectionMinConfidenceFilter: number
|
||||
loadingDetectionResults: boolean
|
||||
detectionReferenceDatasetId: string
|
||||
detectionQaResult: DetectionQaResult | null
|
||||
detectionQaError: string | null
|
||||
runningDetectionQa: boolean
|
||||
selectedProjectId: string | null
|
||||
rasterDatasets: DatasetCreateResponse[]
|
||||
referenceDatasets: DatasetCreateResponse[]
|
||||
onLoadModels: () => void
|
||||
onSelectDataset: (datasetId: string) => void
|
||||
onSelectModel: (modelId: string) => void
|
||||
onSetConfidenceThreshold: (value: number) => void
|
||||
onSetTileManifestPath: (value: string) => void
|
||||
onRunDetection: () => void
|
||||
onLoadRuns: () => void
|
||||
onSelectRun: (runId: string) => void
|
||||
onSetClassFilter: (value: string) => void
|
||||
onSetMinConfidenceFilter: (value: number) => void
|
||||
onLoadResults: () => void
|
||||
onSelectReferenceDataset: (datasetId: string) => void
|
||||
onRunQa: () => void
|
||||
}
|
||||
|
||||
export function DetectionLab({
|
||||
detectionModels,
|
||||
loadingDetectionModels,
|
||||
detectionModelError,
|
||||
selectedDetectionDatasetId,
|
||||
selectedDetectionModelId,
|
||||
detectionTileManifestPath,
|
||||
detectionConfidenceThreshold,
|
||||
runningDetection,
|
||||
detectionRunResult,
|
||||
detectionRunError,
|
||||
detectionRuns,
|
||||
selectedDetectionRunId,
|
||||
detectionItems,
|
||||
detectionClassFilter,
|
||||
detectionMinConfidenceFilter,
|
||||
loadingDetectionResults,
|
||||
detectionReferenceDatasetId,
|
||||
detectionQaResult,
|
||||
detectionQaError,
|
||||
runningDetectionQa,
|
||||
selectedProjectId,
|
||||
rasterDatasets,
|
||||
referenceDatasets,
|
||||
onLoadModels,
|
||||
onSelectDataset,
|
||||
onSelectModel,
|
||||
onSetConfidenceThreshold,
|
||||
onSetTileManifestPath,
|
||||
onRunDetection,
|
||||
onLoadRuns,
|
||||
onSelectRun,
|
||||
onSetClassFilter,
|
||||
onSetMinConfidenceFilter,
|
||||
onLoadResults,
|
||||
onSelectReferenceDataset,
|
||||
onRunQa,
|
||||
}: DetectionLabProps): JSX.Element {
|
||||
return (
|
||||
<section>
|
||||
<h2>Detection Lab</h2>
|
||||
<button type="button" onClick={onLoadModels} disabled={loadingDetectionModels}>
|
||||
Refresh detection models
|
||||
</button>
|
||||
{loadingDetectionModels ? <p>Loading detection models...</p> : null}
|
||||
{detectionModelError ? <p className="error">{detectionModelError}</p> : null}
|
||||
{detectionModels.length === 0 && !loadingDetectionModels ? <p>No detection models reported by backend</p> : null}
|
||||
<ul>
|
||||
{detectionModels.map((model) => (
|
||||
<li key={model.model_id}>
|
||||
<strong>{model.display_name}</strong>
|
||||
<div>model: {model.model_id}</div>
|
||||
<div>framework: {model.framework}</div>
|
||||
<div>task: {model.task_type}</div>
|
||||
<div>status: {model.status}</div>
|
||||
<div>configured: {model.configured ? 'yes' : 'no'}</div>
|
||||
<div>classes: {model.supported_classes.join(', ')}</div>
|
||||
<div>limitation: {model.limitation_message}</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div>
|
||||
<select value={selectedDetectionDatasetId} onChange={(event) => onSelectDataset(event.target.value)}>
|
||||
<option value="">Select raster dataset</option>
|
||||
{rasterDatasets.map((dataset) => (
|
||||
<option key={dataset.id} value={dataset.id}>
|
||||
{dataset.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<select value={selectedDetectionModelId} onChange={(event) => onSelectModel(event.target.value)}>
|
||||
{detectionModels.map((model) => (
|
||||
<option key={model.model_id} value={model.model_id}>
|
||||
{model.display_name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.05"
|
||||
value={detectionConfidenceThreshold}
|
||||
onChange={(event) => onSetConfidenceThreshold(Number(event.target.value))}
|
||||
/>
|
||||
{selectedDetectionModelId === 'yolo-configured' ? (
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Raster tile manifest path"
|
||||
value={detectionTileManifestPath}
|
||||
onChange={(event) => onSetTileManifestPath(event.target.value)}
|
||||
/>
|
||||
) : null}
|
||||
<button type="button" onClick={onRunDetection} disabled={runningDetection || !selectedProjectId || rasterDatasets.length === 0}>
|
||||
Run detection
|
||||
</button>
|
||||
</div>
|
||||
{detectionRunError ? <p className="error">{detectionRunError}</p> : null}
|
||||
{detectionRunResult ? (
|
||||
<div>
|
||||
<p>Status: {detectionRunResult.status}</p>
|
||||
<p>Message: {detectionRunResult.message}</p>
|
||||
<p>Analysis run: {detectionRunResult.analysis_run_id}</p>
|
||||
<p>Job: {detectionRunResult.job_id}</p>
|
||||
<p>Detections: {detectionRunResult.detection_count}</p>
|
||||
{detectionRunResult.error_code ? <p className="error">Code: {detectionRunResult.error_code}</p> : null}
|
||||
</div>
|
||||
) : null}
|
||||
<div>
|
||||
<h3>Detection results</h3>
|
||||
<button type="button" onClick={onLoadRuns} disabled={!selectedProjectId}>
|
||||
Refresh detection runs
|
||||
</button>
|
||||
<select value={selectedDetectionRunId} onChange={(event) => onSelectRun(event.target.value)}>
|
||||
<option value="">Select detection run</option>
|
||||
{detectionRuns.map((run) => (
|
||||
<option key={run.id} value={run.id}>
|
||||
{run.model_name || 'detection'} - {run.status} - {run.id}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Class filter"
|
||||
value={detectionClassFilter}
|
||||
onChange={(event) => onSetClassFilter(event.target.value)}
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.05"
|
||||
value={detectionMinConfidenceFilter}
|
||||
onChange={(event) => onSetMinConfidenceFilter(Number(event.target.value))}
|
||||
/>
|
||||
<button type="button" onClick={onLoadResults} disabled={!selectedDetectionRunId || loadingDetectionResults}>
|
||||
Load detections
|
||||
</button>
|
||||
{loadingDetectionResults ? <p>Loading detection results...</p> : null}
|
||||
<p>Detections loaded: {detectionItems.length}</p>
|
||||
{detectionItems.length > 0 ? (
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Class</th>
|
||||
<th>Confidence</th>
|
||||
<th>Model</th>
|
||||
<th>Source tile</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{detectionItems.map((detection) => (
|
||||
<tr key={detection.id}>
|
||||
<td>{detection.class_name}</td>
|
||||
<td>{detection.confidence.toFixed(2)}</td>
|
||||
<td>{detection.model_name}</td>
|
||||
<td>{detection.source_tile_path || 'n/a'}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
) : null}
|
||||
</div>
|
||||
<div>
|
||||
<h3>Detection QA</h3>
|
||||
<select value={detectionReferenceDatasetId} onChange={(event) => onSelectReferenceDataset(event.target.value)}>
|
||||
<option value="">Select reference dataset</option>
|
||||
{referenceDatasets.map((dataset) => (
|
||||
<option key={dataset.id} value={dataset.id}>
|
||||
{dataset.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button type="button" onClick={onRunQa} disabled={runningDetectionQa || !selectedDetectionRunId || !detectionReferenceDatasetId}>
|
||||
Compare detections to reference
|
||||
</button>
|
||||
{detectionQaError ? <p className="error">{detectionQaError}</p> : null}
|
||||
{detectionQaResult ? (
|
||||
<div>
|
||||
<p>Status: {detectionQaResult.status}</p>
|
||||
<p>Quality check: {detectionQaResult.quality_check_id}</p>
|
||||
<p>Precision: {detectionQaResult.precision?.toFixed(3) ?? 'n/a'}</p>
|
||||
<p>Recall: {detectionQaResult.recall?.toFixed(3) ?? 'n/a'}</p>
|
||||
<p>F1: {detectionQaResult.f1_score?.toFixed(3) ?? 'n/a'}</p>
|
||||
<p>Mean IoU: {detectionQaResult.mean_iou?.toFixed(3) ?? 'n/a'}</p>
|
||||
<p>False positives: {detectionQaResult.false_positives}</p>
|
||||
<p>False negatives: {detectionQaResult.false_negatives}</p>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user