feat: add source-grounded evolution and Ollama assistant
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-15 06:45:56 +02:00
parent 0baa9b069c
commit beacdf2560
37 changed files with 2246 additions and 58 deletions
@@ -87,6 +87,8 @@ class ThemeDefinition:
key: str
label: str
class_ids: tuple[int, ...]
reference_layer_name: str
metric_label: str
@dataclass(frozen=True)
@@ -101,7 +103,18 @@ class PreparedSnapshot:
vector_sha256: str
THEMES = (ThemeDefinition("forest", "Bos", (12,)),)
THEMES = (
ThemeDefinition("forest", "Bos", (12,), "forest", "Bosoppervlakte"),
ThemeDefinition("water", "Water", (17,), "water", "Wateroppervlakte"),
ThemeDefinition(
"built",
"Bebouwde functies",
(1, 2, 3, 4, 6, 7, 8),
"buildings",
"Oppervlakte bebouwde functies",
),
ThemeDefinition("transport", "Transportinfrastructuur", (5,), "roads", "Oppervlakte transportinfrastructuur"),
)
def parse_args() -> argparse.Namespace:
@@ -113,7 +126,7 @@ def parse_args() -> argparse.Namespace:
parser.add_argument("--nis-code", default=DEFAULT_NIS_CODE)
parser.add_argument("--scope-key", default=DEFAULT_SCOPE_KEY)
parser.add_argument("--years", default=",".join(str(year) for year in SUPPORTED_YEARS))
parser.add_argument("--themes", default="forest")
parser.add_argument("--themes", default="forest,water,built,transport")
parser.add_argument(
"--boundary-path",
type=Path,
@@ -528,8 +541,8 @@ def polygonize_snapshot(
"properties": {
"source_name": "department_omgeving_land_use",
"source_feature_id": feature_id,
"reference_layer_name": theme.key,
"layer_type": theme.key,
"reference_layer_name": theme.reference_layer_name,
"layer_type": theme.reference_layer_name,
"authority_level": "authoritative",
"coverage_scope": scope_key,
**identity,
@@ -619,9 +632,12 @@ def prepare_snapshot(
partition_boundaries: list[tuple[str, Any]],
year: int,
theme: ThemeDefinition,
refresh_source: bool = False,
) -> PreparedSnapshot:
stem = f"{args.scope_key}_land_use_{theme.key}_{year}"
raster_path = args.output_dir / f"{stem}.tif"
legacy_forest_raster = args.output_dir / f"{args.scope_key}_land_use_forest_{year}.tif"
shared_raster = args.output_dir / f"{args.scope_key}_land_use_source_{year}.tif"
raster_path = legacy_forest_raster if not args.force and legacy_forest_raster.exists() else shared_raster
vector_path = args.output_dir / f"{stem}.geojson"
manifest_path = args.output_dir / f"{stem}.manifest.json"
if not args.force:
@@ -636,7 +652,7 @@ def prepare_snapshot(
return prepared
raster_profile: dict[str, Any]
if args.force or not raster_path.exists():
if refresh_source or not raster_path.exists():
if partition_boundaries:
raster_profile = download_partitioned_raster(
session,
@@ -797,13 +813,18 @@ def build_source_metadata(args: argparse.Namespace, snapshot: PreparedSnapshot)
"polygon_crs": OUTPUT_CRS,
"land_use_class_ids": list(snapshot.theme.class_ids),
"land_use_class_names": [LAND_USE_CLASSES[class_id] for class_id in snapshot.theme.class_ids],
"temporal_series_label": SERIES_LABEL,
"theme": snapshot.theme.reference_layer_name,
"temporal_series_label": (
SERIES_LABEL if snapshot.theme.key == "forest" else f"{SERIES_LABEL} - {snapshot.theme.label}"
),
"observation_date_precision": "year",
"identity_stable": False,
"semantic_metrics": False,
"identity_limitation": "Raster-derived polygons can split or merge between source editions; object lineage is not inferred.",
"selection_aggregation": {
"method": "intersection_area",
"label": "Oppervlakte",
"metric_key": f"{snapshot.theme.key}_area",
"label": snapshot.theme.metric_label,
"unit": "ha",
"is_estimate": False,
"warning": "Oppervlakte is exact binnen de officiele 10 m rasterrepresentatie en is niet perceelsnauwkeurig.",
@@ -856,7 +877,7 @@ def upload_snapshot(
"source": "operator_official_import",
"dataset_role": "reference",
"source_name": "department_omgeving_land_use",
"reference_layer_name": snapshot.theme.key,
"reference_layer_name": snapshot.theme.reference_layer_name,
"source_metadata_json": json.dumps(build_source_metadata(args, snapshot), ensure_ascii=False),
"provenance_metadata_json": json.dumps(build_provenance_metadata(args, snapshot), ensure_ascii=False),
"area_id": area_id,
@@ -915,6 +936,7 @@ def main() -> int:
partition_boundaries=partition_boundaries,
year=year,
theme=theme,
refresh_source=args.force and theme is definitions[0],
)
)
+1 -1
View File
@@ -138,7 +138,7 @@ def build_operator_commands(
"--years",
args.landuse_years,
"--themes",
"forest",
"forest,water,built,transport",
"--boundary-path",
str(boundary_path),
*partition_flags,