diff --git a/backend/tests/test_sprint129_operator_yolo_training_dataset.py b/backend/tests/test_sprint129_operator_yolo_training_dataset.py index b4a5b1b1..79a9ec10 100644 --- a/backend/tests/test_sprint129_operator_yolo_training_dataset.py +++ b/backend/tests/test_sprint129_operator_yolo_training_dataset.py @@ -64,6 +64,9 @@ def test_operator_yolo_train_smoke_script_contract() -> None: assert "from ultralytics import YOLO" in script assert "model.train" in script assert "plots=False" in script + assert "seed_ultralytics_font" in script + assert "DejaVuSans.ttf" in script + assert "Arial.ttf" in script assert "training_summary.json" in script assert "download" not in script.lower() assert "fixture_mode" not in script diff --git a/docs/CODEX_EXECUTION_LOG.md b/docs/CODEX_EXECUTION_LOG.md index 980768af..b233b84d 100644 --- a/docs/CODEX_EXECUTION_LOG.md +++ b/docs/CODEX_EXECUTION_LOG.md @@ -23,7 +23,7 @@ Tested: - `bash -n scripts/train_operator_yolo_detector.sh` passed. - Live Tower export passed: `/app/storage/operator-data/yolo-building-dataset` contains 3 images and 1427 labels from the current Geel/Mol/Turnhout samples. - Live Tower training smoke passed with the existing `/app/models/yolov8n.pt` base model and wrote `/app/models/geointel-building-yolov8n-smoke.pt`. -- The first live smoke showed Ultralytics fetching an auxiliary plot font. The wrapper now sets `plots=False` so the operator smoke path does not invoke plot/font network behavior. +- The first live smoke showed Ultralytics fetching an auxiliary plot font. The wrapper now sets `plots=False` and seeds `Arial.ttf` from an existing local system font before importing Ultralytics so the operator smoke path does not invoke plot/font network behavior. Open: - Run the exporter and training smoke inside the AI-enabled Tower runtime, then benchmark the trained artifact through the existing multi-sample Detection + QA matrix. diff --git a/scripts/train_operator_yolo_detector.sh b/scripts/train_operator_yolo_detector.sh index 8eeea724..c3dce548 100644 --- a/scripts/train_operator_yolo_detector.sh +++ b/scripts/train_operator_yolo_detector.sh @@ -80,6 +80,25 @@ import os import shutil from pathlib import Path + +def seed_ultralytics_font() -> None: + font_candidates = [ + Path("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"), + Path("/usr/share/fonts/truetype/liberation2/LiberationSans-Regular.ttf"), + Path("/usr/share/fonts/truetype/freefont/FreeSans.ttf"), + ] + source_font = next((font for font in font_candidates if font.exists()), None) + if source_font is None: + return + config_root = Path(os.environ.get("YOLO_CONFIG_DIR", str(Path.home() / ".config"))) + target_font = config_root / "Ultralytics" / "Arial.ttf" + target_font.parent.mkdir(parents=True, exist_ok=True) + if not target_font.exists(): + shutil.copy2(source_font, target_font) + + +seed_ultralytics_font() + from ultralytics import YOLO dataset_yaml = Path(os.environ["DATASET_YAML"])