Add governed VMM flood hazard scenarios
This commit is contained in:
@@ -21,6 +21,9 @@ from app.schemas.assistant import (
|
||||
AssistantStatus,
|
||||
AssistantTemporalSeries,
|
||||
)
|
||||
from app.schemas.flood_hazard import FloodHazardSelectionRequest
|
||||
from app.services.flood_hazard_acquisition_service import FloodHazardAcquisitionService
|
||||
from app.services.flood_hazard_analysis_service import FloodHazardAnalysisService
|
||||
from app.services.vector_feature_service import VectorFeatureService
|
||||
|
||||
|
||||
@@ -252,16 +255,22 @@ class GeoAssistantService:
|
||||
db.query(Dataset)
|
||||
.filter(Dataset.project_id == project_id)
|
||||
.filter(Dataset.status == "ready")
|
||||
.filter(Dataset.dataset_type.in_(["vector", "geojson"]))
|
||||
.all()
|
||||
)
|
||||
vector_datasets = [dataset for dataset in datasets if dataset.dataset_type in {"vector", "geojson"}]
|
||||
flood_hazard_datasets = [
|
||||
dataset
|
||||
for dataset in datasets
|
||||
if dataset.dataset_type == "raster" and dataset.source_name == FloodHazardAcquisitionService.PROVIDER
|
||||
and (area is None or dataset.area_id is None or dataset.area_id == area.id)
|
||||
]
|
||||
warnings: list[str] = []
|
||||
context_metrics: list[AssistantContextMetric] = []
|
||||
source_dataset_ids: list[UUID] = []
|
||||
current_context: list[dict[str, Any]] = []
|
||||
|
||||
if bbox is not None:
|
||||
for dataset in self._current_datasets(datasets):
|
||||
for dataset in self._current_datasets(vector_datasets):
|
||||
kwargs: dict[str, Any] = {"dataset": dataset, "bbox": bbox}
|
||||
if area is not None:
|
||||
kwargs["selection_geometry"] = area.geometry
|
||||
@@ -314,10 +323,60 @@ class GeoAssistantService:
|
||||
}
|
||||
)
|
||||
|
||||
for dataset in sorted(
|
||||
flood_hazard_datasets,
|
||||
key=lambda item: str((item.source_metadata or {}).get("product_key") or item.name),
|
||||
):
|
||||
try:
|
||||
result = FloodHazardAnalysisService.analyze(
|
||||
db,
|
||||
project_id,
|
||||
dataset.id,
|
||||
FloodHazardSelectionRequest(bbox=bbox, area_id=area.id if area is not None else None),
|
||||
settings=self.settings,
|
||||
)
|
||||
except AppError as exc:
|
||||
warnings.append(f"{dataset.name}: {exc.message}")
|
||||
continue
|
||||
metadata = dataset.source_metadata if isinstance(dataset.source_metadata, dict) else {}
|
||||
scenario_label = str(metadata.get("product_display_name") or result["product_key"])
|
||||
serialized_metrics: list[dict[str, Any]] = []
|
||||
for metric in result["summary"]["metrics"]:
|
||||
item = AssistantContextMetric(
|
||||
theme="flood_hazard",
|
||||
label=f"{metric['metric_label']} - {scenario_label}",
|
||||
value=float(metric["metric_value"]),
|
||||
unit=str(metric["metric_unit"]),
|
||||
source=FloodHazardAcquisitionService.ATTRIBUTION,
|
||||
dataset_id=dataset.id,
|
||||
is_estimate=False,
|
||||
)
|
||||
context_metrics.append(item)
|
||||
serialized_metrics.append(item.model_dump(mode="json"))
|
||||
serialized_metrics[-1]["measurement_quality"] = "exacte_berekening_binnen_gemodelleerd_scenario"
|
||||
source_dataset_ids.append(dataset.id)
|
||||
current_context.append(
|
||||
{
|
||||
"dataset_name": dataset.name,
|
||||
"dataset_id": str(dataset.id),
|
||||
"theme": "flood_hazard",
|
||||
"source": FloodHazardAcquisitionService.ATTRIBUTION,
|
||||
"scenario": {
|
||||
"label": scenario_label,
|
||||
"mechanism": result["mechanism"],
|
||||
"climate_context": result["climate_context"],
|
||||
"probability_class": result["probability_class"],
|
||||
"return_period_years": result["return_period_years"],
|
||||
},
|
||||
"metrics": serialized_metrics,
|
||||
"warning": result["limitation_message"],
|
||||
}
|
||||
)
|
||||
|
||||
temporal_series: list[AssistantTemporalSeries] = []
|
||||
temporal_context: list[dict[str, Any]] = []
|
||||
include_history = self.history_requested(payload.question)
|
||||
for key, observations in self._series(datasets):
|
||||
for key, observations in self._series(vector_datasets):
|
||||
first = observations[0]
|
||||
last = observations[-1]
|
||||
source_metadata = last.source_metadata if isinstance(last.source_metadata, dict) else {}
|
||||
@@ -364,7 +423,9 @@ class GeoAssistantService:
|
||||
"available_temporal_series": temporal_context,
|
||||
"rules": {
|
||||
"water_volume_available": False,
|
||||
"water_volume_reason": "Geen gebiedsdekkende waterdiepte of bathymetrie gekoppeld.",
|
||||
"water_volume_reason": "Geen bathymetrie gekoppeld voor de permanente inhoud van waterlichamen.",
|
||||
"flood_hazard_scenarios_available": bool(flood_hazard_datasets),
|
||||
"flood_depth_area_integral_is_concurrent_volume": False,
|
||||
"object_counts_are_supporting_metrics": True,
|
||||
"causal_explanations_available": False,
|
||||
"forecast_available": False,
|
||||
@@ -402,6 +463,7 @@ class GeoAssistantService:
|
||||
"Neem waarden en jaren letterlijk over en bereken zelf geen gemiddelde, tempo, oorzaak of afgeleide trend. "
|
||||
"Gebruik platte tekst met korte alinea's en opsommingen, zonder Markdown-symbolen. "
|
||||
"Bereken of suggereer nooit watervolume zonder gekoppelde diepte of bathymetrie. "
|
||||
"Noem de VMM-diepte-oppervlakte-integraal nooit een werkelijk, permanent of gelijktijdig watervolume. "
|
||||
"Als de gevraagde informatie niet in de context staat, zeg precies welke bron of meting ontbreekt. "
|
||||
"CONTEXT_JSON:\n" + json.dumps(context, ensure_ascii=False, separators=(",", ":"))
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user