Add raster tile detection handoff
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-06-23 18:18:59 +02:00
parent 8855aa8390
commit aa41dfa586
8 changed files with 112 additions and 4 deletions
+12
View File
@@ -79,6 +79,7 @@ function App(): JSX.Element {
datasetContent,
jobs,
rasterPreview,
latestRasterTileManifestPath,
selectedIntersectTargetId,
selectedClipAreaId,
rasterTileSize,
@@ -254,6 +255,15 @@ function App(): JSX.Element {
loadProjectData,
loadQualityChecks,
})
const useRasterTileManifestForDetection = () => {
const manifestPath = latestRasterTileManifestPath.trim()
if (!manifestPath || !selectedDataset || selectedDataset.dataset_type !== 'raster') {
return
}
setDetectionTileManifestPath(manifestPath)
setSelectedDetectionDatasetId(selectedDataset.id)
setActiveWorkspace('ai')
}
const {
segmentationModels,
loadingSegmentationModels,
@@ -949,6 +959,7 @@ function App(): JSX.Element {
selectedRasterMetadata,
selectedRasterStats,
rasterPreview,
latestRasterTileManifestPath,
rasterUnavailableMessage,
selectedClipAreaId,
selectedIntersectTargetId,
@@ -987,6 +998,7 @@ function App(): JSX.Element {
onRunRasterReproject: runRasterReproject,
onRunRasterClip: runRasterClip,
onRunRasterTile: runRasterTile,
onUseTileManifestForDetection: useRasterTileManifestForDetection,
onRunRasterNdvi: runRasterNdvi,
onRunRasterNdwi: runRasterNdwi,
onRunRasterNdbi: runRasterNdbi,
@@ -19,6 +19,7 @@ export interface DatasetDetailPanelProps {
selectedRasterMetadata: RasterMetadataResponse | null
selectedRasterStats: RasterStatsResponse | null
rasterPreview: RasterPreviewResponse | null
latestRasterTileManifestPath: string
rasterUnavailableMessage: string | null
selectedClipAreaId: string
selectedIntersectTargetId: string
@@ -57,6 +58,7 @@ export interface DatasetDetailPanelProps {
onRunRasterReproject: () => void
onRunRasterClip: () => void
onRunRasterTile: () => void
onUseTileManifestForDetection: () => void
onRunRasterNdvi: () => void
onRunRasterNdwi: () => void
onRunRasterNdbi: () => void
@@ -100,6 +102,7 @@ export function DatasetDetailPanel({
selectedRasterMetadata,
selectedRasterStats,
rasterPreview,
latestRasterTileManifestPath,
rasterUnavailableMessage,
selectedClipAreaId,
selectedIntersectTargetId,
@@ -138,6 +141,7 @@ export function DatasetDetailPanel({
onRunRasterReproject,
onRunRasterClip,
onRunRasterTile,
onUseTileManifestForDetection,
onRunRasterNdvi,
onRunRasterNdwi,
onRunRasterNdbi,
@@ -171,6 +175,7 @@ export function DatasetDetailPanel({
selectedRasterMetadata={selectedRasterMetadata}
selectedRasterStats={selectedRasterStats}
rasterPreview={rasterPreview}
latestRasterTileManifestPath={latestRasterTileManifestPath}
rasterUnavailableMessage={rasterUnavailableMessage}
selectedClipAreaId={selectedClipAreaId}
rasterTileSize={rasterTileSize}
@@ -203,6 +208,7 @@ export function DatasetDetailPanel({
onRunRasterReproject={onRunRasterReproject}
onRunRasterClip={onRunRasterClip}
onRunRasterTile={onRunRasterTile}
onUseTileManifestForDetection={onUseTileManifestForDetection}
onRunRasterNdvi={onRunRasterNdvi}
onRunRasterNdwi={onRunRasterNdwi}
onRunRasterNdbi={onRunRasterNdbi}
@@ -6,6 +6,7 @@ interface RasterControlsProps {
selectedRasterMetadata: RasterMetadataResponse | null
selectedRasterStats: RasterStatsResponse | null
rasterPreview: RasterPreviewResponse | null
latestRasterTileManifestPath: string
rasterUnavailableMessage: string | null
selectedClipAreaId: string
rasterTileSize: number
@@ -38,6 +39,7 @@ interface RasterControlsProps {
onRunRasterReproject: () => void
onRunRasterClip: () => void
onRunRasterTile: () => void
onUseTileManifestForDetection: () => void
onRunRasterNdvi: () => void
onRunRasterNdwi: () => void
onRunRasterNdbi: () => void
@@ -57,6 +59,7 @@ export function RasterControls({
selectedRasterMetadata,
selectedRasterStats,
rasterPreview,
latestRasterTileManifestPath,
rasterUnavailableMessage,
selectedClipAreaId,
rasterTileSize,
@@ -89,6 +92,7 @@ export function RasterControls({
onRunRasterReproject,
onRunRasterClip,
onRunRasterTile,
onUseTileManifestForDetection,
onRunRasterNdvi,
onRunRasterNdwi,
onRunRasterNdbi,
@@ -156,11 +160,14 @@ export function RasterControls({
))}
</div>
<div className="raster-manifest-handoff">
<span>Tile manifest handoff</span>
<span>Latest tile manifest</span>
<p>
Generated tile manifests remain backend artifacts and are referenced by path in detection/segmentation requests; this panel only prepares
and explains the handoff.
{latestRasterTileManifestPath ||
'No tile manifest generated yet. Generate tiles before handing this raster to Detection Lab.'}
</p>
<button type="button" onClick={onUseTileManifestForDetection} disabled={!latestRasterTileManifestPath}>
Use in Detection Lab
</button>
</div>
</section>
<section className="raster-guardrail-surface" aria-label="Processing guardrails">
+23 -1
View File
@@ -27,6 +27,15 @@ function toRasterMetadata(metadata: Record<string, unknown> | null | undefined):
return metadata as unknown as RasterMetadataResponse
}
function extractRasterTileManifestPath(job: JobRead | null | undefined): string {
const result = job?.result_json
if (!result) {
return ''
}
const manifestPath = result.manifest_path
return typeof manifestPath === 'string' ? manifestPath : ''
}
export function useDatasetWorkflow({
selectedProjectId,
areas,
@@ -43,6 +52,7 @@ export function useDatasetWorkflow({
const [datasetContent, setDatasetContent] = useState<GeoJSON.FeatureCollection | null>(null)
const [jobs, setJobs] = useState<JobRead[]>([])
const [rasterPreview, setRasterPreview] = useState<RasterPreviewResponse | null>(null)
const [latestRasterTileManifestPath, setLatestRasterTileManifestPath] = useState('')
const [selectedIntersectTargetId, setSelectedIntersectTargetId] = useState('')
const [selectedClipAreaId, setSelectedClipAreaId] = useState('')
const [rasterTileSize, setRasterTileSize] = useState(512)
@@ -100,6 +110,10 @@ export function useDatasetWorkflow({
const loadDatasetJobs = async (projectId: string, datasetId: string) => {
const response = await jobsApi.list(projectId, { dataset_id: datasetId, limit: 20, offset: 0 })
setJobs(response.items)
const latestRasterTileJob = response.items.find(
(job) => job.job_type === 'raster.tile' && extractRasterTileManifestPath(job),
)
setLatestRasterTileManifestPath(extractRasterTileManifestPath(latestRasterTileJob))
}
const loadDatasetDetails = async (projectId: string, dataset: DatasetCreateResponse) => {
@@ -111,6 +125,7 @@ export function useDatasetWorkflow({
setSelectedRasterStats(null)
setDatasetContent(null)
setRasterPreview(null)
setLatestRasterTileManifestPath('')
setSelectedDatasetId(dataset.id)
setJobs([])
try {
@@ -352,12 +367,17 @@ export function useDatasetWorkflow({
return
}
try {
await datasetsApi.rasterTile(selectedProjectId, selectedDatasetId, {
const job = await datasetsApi.rasterTile(selectedProjectId, selectedDatasetId, {
tile_size: rasterTileSize,
overlap: rasterTileOverlap,
output_name: rasterTileOutputName || undefined,
})
const manifestPath = extractRasterTileManifestPath(job)
setLatestRasterTileManifestPath(manifestPath)
await refreshSelectedDatasetAfterJob()
if (manifestPath) {
setLatestRasterTileManifestPath(manifestPath)
}
setDatasetDetailError(null)
} catch (error) {
setDatasetDetailError(formatError(error, 'Raster tile failed'))
@@ -444,6 +464,7 @@ export function useDatasetWorkflow({
setSelectedRasterStats(null)
setDatasetContent(null)
setRasterPreview(null)
setLatestRasterTileManifestPath('')
setJobs([])
}
@@ -456,6 +477,7 @@ export function useDatasetWorkflow({
datasetContent,
jobs,
rasterPreview,
latestRasterTileManifestPath,
selectedIntersectTargetId,
selectedClipAreaId,
rasterTileSize,