Add operator YOLO training dataset tooling
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-07-07 05:19:16 +02:00
parent 306fcd1b24
commit 31a2aa6138
10 changed files with 607 additions and 0 deletions
+32
View File
@@ -278,6 +278,38 @@ python scripts/configure_yolo_model.py \
The smoke loads only the supplied local model file, does not run inference and
does not download weights.
Operator-only local training preparation is available when real public model
candidates are too weak for the target imagery. It is not a browser feature and
does not change API contracts:
```bash
docker exec -it geointel python /app/scripts/export_operator_yolo_dataset.py \
--manifest-path /app/storage/operator-data/operator_samples_manifest.json \
--output-dir /app/storage/operator-data/yolo-building-dataset \
--val-samples turnhout \
--force
```
In an AI-enabled runtime with an existing local base model:
```bash
docker exec \
-e OPERATOR_YOLO_DATASET_DIR=/app/storage/operator-data/yolo-building-dataset \
-e YOLO_BASE_MODEL_PATH=/app/models/yolov8n.pt \
-e TRAIN_MODEL_OUTPUT_PATH=/app/models/geointel-building-detector.pt \
-e TRAIN_EPOCHS=8 \
-e TRAIN_IMGSZ=512 \
-e TRAIN_BATCH=2 \
-e TRAIN_WORKERS=0 \
-e TRAIN_DEVICE=cpu \
geointel bash /app/scripts/train_operator_yolo_detector.sh
```
The exporter creates a YOLO `dataset.yaml` plus image/label folders from the
explicit operator sample manifest. The training wrapper writes
`training_summary.json` and a local `.pt` artifact, which still must be
validated through model preflight and the real-data QA matrix before use.
The backend also exposes a read-only model asset catalog for the mounted model
directory:
@@ -0,0 +1,68 @@
from pathlib import Path
import subprocess
import sys
ROOT = Path(__file__).resolve().parents[2]
def test_operator_yolo_dataset_export_script_contract() -> None:
script_path = ROOT / "scripts" / "export_operator_yolo_dataset.py"
readiness = (ROOT / "scripts" / "run_readiness_check.sh").read_text(encoding="utf-8")
assert script_path.exists()
script = script_path.read_text(encoding="utf-8")
assert "py_compile scripts/export_operator_yolo_dataset.py" in readiness
assert "operator_samples_manifest.json" in script
assert "dataset.yaml" in script
assert "images/train" in script
assert "labels/train" in script
assert "images/val" in script
assert "labels/val" in script
assert "building" in script
assert "reference_feature_count" in script
assert "source_name" in script
assert "reference_layer_name" in script
assert "rasterio" in script
assert "Transformer" in script
assert "demo/workflow" not in script
assert "fixture_mode" not in script
assert "will_download_models" not in script
def test_operator_yolo_dataset_export_help_does_not_require_gis_dependencies() -> None:
script_path = ROOT / "scripts" / "export_operator_yolo_dataset.py"
result = subprocess.run(
[sys.executable, str(script_path), "--help"],
check=False,
capture_output=True,
text=True,
)
assert result.returncode == 0
assert "Export operator real-data samples to a YOLO detection dataset" in result.stdout
assert "--manifest-path" in result.stdout
assert "--val-samples" in result.stdout
def test_operator_yolo_train_smoke_script_contract() -> None:
script_path = ROOT / "scripts" / "train_operator_yolo_detector.sh"
readiness = (ROOT / "scripts" / "run_readiness_check.sh").read_text(encoding="utf-8")
assert script_path.exists()
script = script_path.read_text(encoding="utf-8")
assert "bash -n scripts/train_operator_yolo_detector.sh" in readiness
assert "OPERATOR_YOLO_DATASET_DIR" in script
assert "YOLO_BASE_MODEL_PATH" in script
assert "TRAIN_MODEL_OUTPUT_PATH" in script
assert "TRAIN_EPOCHS" in script
assert "TRAIN_IMGSZ" in script
assert "dataset.yaml" in script
assert "from ultralytics import YOLO" in script
assert "model.train" in script
assert "training_summary.json" in script
assert "download" not in script.lower()
assert "fixture_mode" not in script