scripts/evaluate_belgium_building_candidate.py freezes its post-processing before the protected test — NMS IoU and a containment threshold selected during calibration, defaulting to 1.0. The runtime applied a hardcoded 0.85, so a promoted candidate was served under suppression its evaluation never measured and dropped detections the gate had counted. Neither report showed the difference. That constant was mine, added without noticing the evaluation pipeline already had a tuned value for the same concept. Containment is now configuration, recorded on every run beside the duplicate IoU threshold, so an operator can serve a candidate at the value it was gated at and afterwards see which value produced a given score. Two runs that post-processed differently produced different candidate sets from the same model output, so the comparison endpoint refuses to rank them. Runs recorded before those values were persisted carry none, and absence is not treated as a difference. The remaining gap is deliberate and documented rather than closed: the gate scores the model on its protected test set, the workbench scores the whole pipeline including coverage clipping and the tile-edge filter. A promoted candidate will not reproduce its gate F1 exactly, and pretending otherwise would be the worse answer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
199 lines
8.1 KiB
Bash
199 lines
8.1 KiB
Bash
# Backend
|
|
GEOINTEL_ENV=development
|
|
GEOINTEL_API_PREFIX=/api/v1
|
|
DATABASE_URL=postgresql+psycopg://geointel:geointel@localhost:5432/geointel?connect_timeout=1
|
|
STORAGE_ROOT=./storage
|
|
MAX_UPLOAD_MB=500
|
|
CORS_ORIGINS=http://localhost:1202,http://127.0.0.1:1202
|
|
|
|
# Optional single-operator access gate. Store only a PBKDF2-SHA256 hash and
|
|
# a unique 32+ character signing secret. Guest access is enabled by default
|
|
# whenever this gate is active; disable it explicitly on non-demo instances.
|
|
GEOINTEL_AUTH_ENABLED=false
|
|
GEOINTEL_AUTH_USERNAME=
|
|
GEOINTEL_AUTH_PASSWORD_HASH=
|
|
GEOINTEL_AUTH_SESSION_SECRET=
|
|
GEOINTEL_AUTH_SESSION_TTL_SECONDS=43200
|
|
GEOINTEL_GUEST_ACCESS_ENABLED=true
|
|
GEOINTEL_GUEST_DISPLAY_NAME=Gast
|
|
GEOINTEL_GUEST_SESSION_TTL_SECONDS=7200
|
|
ORTHOPHOTO_ENABLED=true
|
|
ORTHOPHOTO_WMS_URL=https://geo.api.vlaanderen.be/OMWRGBMRVL/wms
|
|
SPW_ORTHOPHOTO_WMS_URL=https://geoservices.wallonie.be/arcgis/services/IMAGERIE/ORTHO_LAST/MapServer/WMSServer
|
|
BRUSSELS_ORTHOPHOTO_WMS_URL=https://geoservices-grid.irisnet.be/geoserver/urbisgrid/ows
|
|
ORTHOPHOTO_WMS_LAYER=Ortho
|
|
ORTHOPHOTO_RESOLUTION_M=1.0
|
|
ORTHOPHOTO_MIN_SIDE_M=128
|
|
ORTHOPHOTO_MAX_SIDE_M=1024
|
|
ORTHOPHOTO_CACHE_TTL_HOURS=24
|
|
SOURCE_CATALOG_PROBE_ENABLED=true
|
|
SOURCE_CATALOG_GRB_WFS_URL=https://geo.api.vlaanderen.be/GRB/wfs
|
|
GRB_ENABLED=true
|
|
GRB_OGC_API_URL=https://geo.api.vlaanderen.be/GRB/ogc/features/v1
|
|
GRB_MIN_SIDE_M=10
|
|
GRB_MAX_SIDE_M=20000
|
|
GRB_PAGE_SIZE=1000
|
|
GRB_MAX_PAGES=200
|
|
GRB_MAX_FEATURES=150000
|
|
GRB_TIMEOUT_SECONDS=180
|
|
GRB_MAX_RESPONSE_MB=20
|
|
GRB_MAX_TOTAL_RESPONSE_MB=256
|
|
GRB_CACHE_TTL_HOURS=24
|
|
OFFICIAL_VECTOR_ENABLED=true
|
|
BWK_WFS_URL=https://geo.api.vlaanderen.be/BWK/wfs
|
|
DOV_SOIL_WFS_URL=https://www.dov.vlaanderen.be/geoserver/wfs
|
|
SPW_PICC_ENABLED=true
|
|
SPW_PICC_MAPSERVER_URL=https://geoservices.wallonie.be/arcgis/rest/services/TOPOGRAPHIE/PICC_VDIFF/MapServer
|
|
SPW_FLOOD_HAZARD_ENABLED=true
|
|
SPW_FLOOD_HAZARD_MAPSERVER_URL=https://geoservices.wallonie.be/arcgis/rest/services/EAU/ALEA_INOND/MapServer
|
|
URBIS_ENABLED=true
|
|
URBIS_WFS_URL=https://geoservices-vector.irisnet.be/geoserver/urbisvector/ows
|
|
OFFICIAL_VECTOR_MIN_SIDE_M=10
|
|
OFFICIAL_VECTOR_MAX_SIDE_M=20000
|
|
OFFICIAL_VECTOR_PAGE_SIZE=1000
|
|
OFFICIAL_VECTOR_MAX_PAGES=200
|
|
OFFICIAL_VECTOR_MAX_FEATURES=100000
|
|
OFFICIAL_VECTOR_TIMEOUT_SECONDS=180
|
|
OFFICIAL_VECTOR_MAX_RESPONSE_MB=20
|
|
OFFICIAL_VECTOR_MAX_TOTAL_RESPONSE_MB=256
|
|
OFFICIAL_VECTOR_CACHE_TTL_HOURS=24
|
|
SOURCE_CATALOG_STATBEL_DCAT_URL=https://doc.statbel.be/publications/DCAT/DCAT_opendata_datasets.ttl
|
|
SOURCE_CATALOG_STATBEL_MAX_RESPONSE_MB=5
|
|
SOURCE_CATALOG_ALZ_RELEASE_URL=https://landbouwcijfers.vlaanderen.be/open-geodata-landbouwgebruikspercelen
|
|
SOURCE_CATALOG_PROBE_TIMEOUT_SECONDS=10
|
|
SOURCE_CATALOG_PROBE_MAX_RESPONSE_MB=2
|
|
SOURCE_CATALOG_PROBE_CACHE_TTL_SECONDS=900
|
|
DHMV_ENABLED=true
|
|
DHMV_WCS_URL=https://geo.api.vlaanderen.be/DHMV/wcs
|
|
DHMV_RESOLUTION_M=5.0
|
|
DHMV_MIN_SIDE_M=10
|
|
DHMV_MAX_SIDE_M=20000
|
|
DHMV_MAX_PIXELS=12000000
|
|
DHMV_TIMEOUT_SECONDS=300
|
|
DHMV_MAX_RESPONSE_MB=160
|
|
FLOOD_HAZARD_ENABLED=true
|
|
FLOOD_HAZARD_WCS_URL=https://geoservice.waterinfo.be/OGRK/wcs
|
|
FLOOD_HAZARD_RESOLUTION_M=5.0
|
|
FLOOD_HAZARD_MIN_SIDE_M=10
|
|
FLOOD_HAZARD_MAX_SIDE_M=20000
|
|
FLOOD_HAZARD_MAX_PIXELS=12000000
|
|
FLOOD_HAZARD_TIMEOUT_SECONDS=300
|
|
FLOOD_HAZARD_MAX_RESPONSE_MB=160
|
|
BATHYMETRY_PROFILES_ENABLED=true
|
|
BATHYMETRY_PROFILES_LAYER_URL=https://vha.waterinfo.be/arcgis/rest/services/digitale_atlas/MapServer/0
|
|
BATHYMETRY_WATERCOURSE_LAYER_URL=https://vha.waterinfo.be/arcgis/rest/services/digitale_atlas/MapServer/1
|
|
BATHYMETRY_PROFILES_PAGE_SIZE=1000
|
|
BATHYMETRY_PROFILES_MAX_FEATURES=50000
|
|
BATHYMETRY_PROFILES_TIMEOUT_SECONDS=120
|
|
BATHYMETRY_PROFILES_MAX_RESPONSE_MB=32
|
|
MDK_BATHYMETRY_PROBE_ENABLED=true
|
|
MDK_BATHYMETRY_WCS_URL=https://bathy.agentschapmdk.be/spatialfusionserver/services/ows/wcs/EL_wcs
|
|
MDK_BATHYMETRY_PROBE_TIMEOUT_SECONDS=20
|
|
MDK_BATHYMETRY_PROBE_MAX_RESPONSE_MB=4
|
|
# Bounded MDK acquisition stays fail-closed until the readiness probe reports
|
|
# "reachable" and an advertised coverage id is configured explicitly.
|
|
MDK_BATHYMETRY_ACQUISITION_ENABLED=false
|
|
MDK_BATHYMETRY_COVERAGE_ID=
|
|
MDK_BATHYMETRY_REQUEST_CRS=EPSG:4326
|
|
MDK_BATHYMETRY_MAX_BBOX_DEG2=0.25
|
|
MDK_BATHYMETRY_ACQUISITION_TIMEOUT_SECONDS=120
|
|
MDK_BATHYMETRY_ACQUISITION_MAX_RESPONSE_MB=160
|
|
THEMATIC_RASTER_ENABLED=true
|
|
THEMATIC_RASTER_WCS_URL=https://www.mercator.vlaanderen.be/raadpleegdienstenmercatorpubliek/wcs
|
|
THEMATIC_RASTER_MIN_SIDE_M=100
|
|
THEMATIC_RASTER_MAX_SIDE_M=60000
|
|
THEMATIC_RASTER_MAX_PIXELS=30000000
|
|
THEMATIC_RASTER_TIMEOUT_SECONDS=300
|
|
THEMATIC_RASTER_MAX_RESPONSE_MB=160
|
|
WALOUS_ENABLED=true
|
|
WALOUS_SOURCE_DIR=/app/storage/source-cache/walous
|
|
WALOUS_ANALYSIS_RESOLUTION_M=10
|
|
WALOUS_MAX_SIDE_M=60000
|
|
WALOUS_MAX_PIXELS=36000000
|
|
YOLO_ENABLED=false
|
|
YOLO_MODELS_DIR=/app/models
|
|
YOLO_MODEL_PATH=
|
|
YOLO_MODEL_ID=yolo-configured
|
|
YOLO_MODEL_DISPLAY_NAME=Configured YOLO detector
|
|
YOLO_MODEL_VERSION=
|
|
YOLO_MODEL_CLASSES=building
|
|
YOLO_ENFORCE_VALIDATION_SCOPE=false
|
|
# Required when scope enforcement is enabled. The manifest is bound to exact
|
|
# model bytes and contains the allowed EPSG:4326 validation geometry.
|
|
YOLO_VALIDATION_SCOPE_MANIFEST_PATH=
|
|
YOLO_VALIDATION_SCOPE_MANIFEST_SHA256=
|
|
# Deprecated display metadata; never used as an inference authorization gate.
|
|
YOLO_VALIDATED_AREA_NAMES=Mol,Kempen
|
|
YOLO_CONFIG_DIR=./storage/ultralytics
|
|
YOLO_DEVICE=cpu
|
|
YOLO_REQUIRE_CUDA=false
|
|
YOLO_IMAGE_SIZE=640
|
|
YOLO_MAX_TILES=100
|
|
YOLO_MAX_DETECTIONS=1000
|
|
YOLO_DUPLICATE_IOU_THRESHOLD=0.5
|
|
# Tiles per model.predict call. 1 leaves most of a modern GPU idle on a run of
|
|
# a hundred tiles; raise it until VRAM is the limit.
|
|
YOLO_BATCH_SIZE=1
|
|
# Drop boxes truncated by an interior tile edge. Because tiles overlap, the
|
|
# neighbouring tile saw the same object whole, so the truncated half is a
|
|
# duplicate and a shape error at once. Boxes on the outer raster edge are kept.
|
|
YOLO_SUPPRESS_TILE_EDGE_DETECTIONS=true
|
|
# Intersection over the smaller box. scripts/evaluate_belgium_building_candidate.py
|
|
# freezes this during calibration (--containment-nms) before the protected test.
|
|
# Serving a promoted model at a different value means the runtime suppresses
|
|
# detections its gate counted, so set this to the value the candidate was gated at.
|
|
YOLO_CONTAINMENT_NMS_THRESHOLD=0.85
|
|
|
|
# Local segmentation models. GeoIntel never downloads model weights
|
|
# automatically; point these to existing local files to enable inference.
|
|
YOLO_SEG_ENABLED=false
|
|
YOLO_SEG_MODEL_PATH=
|
|
YOLO_SEG_MODEL_ID=yolo-seg-configured
|
|
YOLO_SEG_MODEL_DISPLAY_NAME=Configured YOLO segmentation
|
|
YOLO_SEG_MODEL_VERSION=
|
|
SAM_ENABLED=false
|
|
SAM_MODEL_PATH=
|
|
SAM_MODEL_ID=sam-configured
|
|
SAM_MODEL_DISPLAY_NAME=Configured SAM segmentation
|
|
SAM_MODEL_VERSION=
|
|
SEGMENTATION_MAX_MASKS_PER_TILE=300
|
|
SEGMENTATION_DUPLICATE_IOU_THRESHOLD=0.5
|
|
ENABLE_GRB_WFS=false
|
|
GRB_WFS_URL=
|
|
OSM_OVERPASS_URL=https://overpass-api.de/api/interpreter
|
|
|
|
# Install backend raster dependencies when needed:
|
|
# python -m pip install rasterio
|
|
|
|
# Frontend
|
|
VITE_API_BASE_URL=
|
|
VITE_API_PROXY_TARGET=http://localhost:8000
|
|
# Leave empty to use the local/demo OpenStreetMap fallback with visible attribution.
|
|
# Set this to a managed MapLibre style URL for production or heavier tile traffic.
|
|
VITE_MAP_STYLE_URL=
|
|
|
|
# Docker Compose / Unraid
|
|
GEOINTEL_FRONTEND_PORT=1202
|
|
GEOINTEL_BACKEND_PORT=8000
|
|
GEOINTEL_INSTALL_AI=false
|
|
GEOINTEL_STORAGE_PATH=./storage
|
|
GEOINTEL_BACKUPS_PATH=./backups
|
|
GEOINTEL_MODELS_PATH=./models
|
|
GEOINTEL_POSTGIS_DATA_PATH=./postgres-data
|
|
GEOINTEL_POSTGRES_DB=geointel
|
|
GEOINTEL_POSTGRES_USER=geointel
|
|
GEOINTEL_POSTGRES_PASSWORD=geointel
|
|
GEOINTEL_CORS_ORIGINS=https://geointel.itworx.tech,http://geointel.itworx.tech,http://localhost:1202,http://127.0.0.1:1202,http://192.168.10.150:1202
|
|
GEOINTEL_MAX_UPLOAD_MB=500
|
|
GEOINTEL_AOI_WORKER_ENABLED=false
|
|
GEOINTEL_AOI_WORKER_POLL_SECONDS=2
|
|
# Executes queued detection.run / segmentation.run jobs from POST
|
|
# /detection/run-async, so tiled GPU inference never blocks an HTTP request.
|
|
GEOINTEL_ANALYSIS_WORKER_ENABLED=false
|
|
GEOINTEL_ANALYSIS_WORKER_POLL_SECONDS=2
|
|
# Analysis consumes only artifacts under STORAGE_ROOT: a tile manifest path
|
|
# arrives in the request and a manifest entry may name an absolute tile
|
|
# path, so without this an API field is an unbounded filesystem reference.
|
|
# Provisioning workflows that stage tiles elsewhere before ingest can opt out.
|
|
GEOINTEL_ALLOW_EXTERNAL_ARTIFACT_PATHS=false
|