Add reusable GIS run mode and AI runtime opt-in
This commit is contained in:
+5
-1
@@ -2,6 +2,8 @@ FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ARG GEOINTEL_INSTALL_AI=false
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
gdal-bin \
|
||||
@@ -15,7 +17,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
COPY pyproject.toml README.md /app/
|
||||
COPY app /app/app
|
||||
RUN pip install --no-cache-dir --upgrade pip setuptools
|
||||
RUN pip install --no-cache-dir ".[gis]"
|
||||
RUN extras=".[gis]" \
|
||||
&& if [ "$GEOINTEL_INSTALL_AI" = "true" ]; then extras=".[gis,ai]"; fi \
|
||||
&& pip install --no-cache-dir "$extras"
|
||||
|
||||
COPY . /app
|
||||
RUN python scripts/gis_import_smoke.py
|
||||
|
||||
@@ -216,6 +216,17 @@ cd backend
|
||||
python -m pip install -e .[ai]
|
||||
```
|
||||
|
||||
Docker and Unraid builds keep AI dependencies disabled by default. To build an
|
||||
image with local PyTorch/Ultralytics support, set:
|
||||
|
||||
```bash
|
||||
GEOINTEL_INSTALL_AI=true
|
||||
```
|
||||
|
||||
The default remains `false` so normal GIS deployments do not install the large AI
|
||||
runtime. GeoIntel still requires an explicit local model path and never downloads
|
||||
weights automatically.
|
||||
|
||||
Configured YOLO requires:
|
||||
|
||||
```bash
|
||||
@@ -235,6 +246,15 @@ In Docker, run the same smoke through the backend container:
|
||||
docker compose exec -T backend python scripts/yolo_preflight.py --model-path /absolute/path/to/local-model.pt --tile-manifest-path /absolute/path/to/manifest.json --check-model-load --json
|
||||
```
|
||||
|
||||
In the all-in-one Unraid runtime, place model files under the configured models
|
||||
directory, mounted as `/app/models` by default:
|
||||
|
||||
```bash
|
||||
GEOINTEL_MODELS_PATH=/mnt/user/appdata/geointel/models
|
||||
YOLO_ENABLED=true
|
||||
YOLO_MODEL_PATH=/app/models/local-model.pt
|
||||
```
|
||||
|
||||
The smoke loads only the supplied local model file, does not run inference and
|
||||
does not download weights.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ def test_backend_dockerfile_copies_package_sources_before_pip_install() -> None:
|
||||
dockerfile = ROOT / "backend" / "Dockerfile"
|
||||
lines = dockerfile.read_text(encoding="utf-8").splitlines()
|
||||
|
||||
pip_install_index = lines.index('RUN pip install --no-cache-dir ".[gis]"')
|
||||
pip_install_index = lines.index('RUN extras=".[gis]" \\')
|
||||
preceding = "\n".join(lines[:pip_install_index])
|
||||
|
||||
assert "COPY pyproject.toml README.md /app/" in preceding
|
||||
@@ -18,7 +18,9 @@ def test_backend_dockerfile_copies_package_sources_before_pip_install() -> None:
|
||||
def test_backend_dockerfile_installs_approved_gis_runtime_stack() -> None:
|
||||
dockerfile = (ROOT / "backend" / "Dockerfile").read_text(encoding="utf-8")
|
||||
|
||||
assert 'RUN pip install --no-cache-dir ".[gis]"' in dockerfile
|
||||
assert "ARG GEOINTEL_INSTALL_AI=false" in dockerfile
|
||||
assert 'extras=".[gis]"' in dockerfile
|
||||
assert 'extras=".[gis,ai]"' in dockerfile
|
||||
assert "RUN python scripts/gis_import_smoke.py" in dockerfile
|
||||
assert "gdal-bin" in dockerfile
|
||||
assert "libgdal-dev" in dockerfile
|
||||
@@ -37,6 +39,16 @@ def test_backend_pyproject_exposes_gis_optional_dependency_group() -> None:
|
||||
assert '"ultralytics>=8.3,<9"' not in pyproject.split("gis = [", 1)[1].split("]", 1)[0]
|
||||
|
||||
|
||||
def test_all_in_one_dockerfile_can_opt_into_ai_dependencies_without_base_install() -> None:
|
||||
dockerfile = (ROOT / "deploy" / "unraid" / "Dockerfile.all-in-one").read_text(encoding="utf-8")
|
||||
|
||||
assert "ARG GEOINTEL_INSTALL_AI=false" in dockerfile
|
||||
assert 'extras=".[gis]"' in dockerfile
|
||||
assert 'extras=".[gis,ai]"' in dockerfile
|
||||
assert "python scripts/gis_import_smoke.py" in dockerfile
|
||||
assert "yolo_preflight.py" in dockerfile
|
||||
|
||||
|
||||
def test_compose_does_not_require_missing_root_env_file() -> None:
|
||||
compose = (ROOT / "docker-compose.yml").read_text(encoding="utf-8")
|
||||
|
||||
@@ -60,6 +72,7 @@ def test_compose_exposes_frontend_on_configurable_host_port_with_cors_origin() -
|
||||
def test_env_example_uses_runtime_env_names_read_by_backend_and_frontend() -> None:
|
||||
env_example = (ROOT / ".env.example").read_text(encoding="utf-8")
|
||||
|
||||
assert "GEOINTEL_INSTALL_AI=false" in env_example
|
||||
assert "YOLO_ENABLED=false" in env_example
|
||||
assert "YOLO_MODEL_PATH=" in env_example
|
||||
assert "YOLO_MAX_TILES=100" in env_example
|
||||
@@ -182,3 +195,19 @@ def test_gis_import_smoke_script_checks_runtime_imports() -> None:
|
||||
|
||||
def test_backend_docker_context_contains_gis_import_smoke_script() -> None:
|
||||
assert (ROOT / "backend" / "scripts" / "gis_import_smoke.py").exists()
|
||||
|
||||
|
||||
def test_unraid_deploy_passes_ai_build_arg_and_yolo_runtime_env() -> None:
|
||||
deploy_ps1 = (ROOT / "scripts" / "deploy_tower.ps1").read_text(encoding="utf-8")
|
||||
deploy_sh = (ROOT / "scripts" / "deploy_tower.sh").read_text(encoding="utf-8")
|
||||
run_script = (ROOT / "deploy" / "unraid" / "run-dockerman-container.sh").read_text(encoding="utf-8")
|
||||
|
||||
assert "--build-arg GEOINTEL_INSTALL_AI=${GEOINTEL_INSTALL_AI:-false}" in deploy_sh
|
||||
assert "--build-arg GEOINTEL_INSTALL_AI='$InstallAi'" in deploy_ps1
|
||||
assert "[string]$InstallAi" in deploy_ps1
|
||||
|
||||
assert 'YOLO_ENABLED="${YOLO_ENABLED:-false}"' in run_script
|
||||
assert '-e YOLO_ENABLED="$YOLO_ENABLED"' in run_script
|
||||
assert '-e YOLO_MODEL_PATH="$YOLO_MODEL_PATH"' in run_script
|
||||
assert '-e YOLO_MAX_TILES="$YOLO_MAX_TILES"' in run_script
|
||||
assert "-v \"${GEOINTEL_MODELS_PATH}:/app/models\"" in run_script
|
||||
|
||||
@@ -38,9 +38,15 @@ def test_map_workspace_can_select_persisted_database_layer_and_run_query() -> No
|
||||
assert "runFullGisWorkflow" in map_workspace
|
||||
assert "fullWorkflowStatus" in map_workspace
|
||||
assert "Query, save, QA and export" in map_workspace
|
||||
assert "fullWorkflowMode" in map_workspace
|
||||
assert "Create new dataset/export" in map_workspace
|
||||
assert "Reuse latest saved dataset for QA" in map_workspace
|
||||
assert "Reusing latest saved dataset for QA/QC" in map_workspace
|
||||
assert "latestSelectionDataset" in map_workspace
|
||||
assert "selectedMapDatasetId=" in app_shell
|
||||
assert ".basemap-policy-notice" in styles
|
||||
assert ".guided-gis-flow" in styles
|
||||
assert ".guided-gis-batch-status" in styles
|
||||
assert ".guided-gis-run-mode" in styles
|
||||
assert ".gis-test-run-surface" in styles
|
||||
assert ".gis-test-run-grid" in styles
|
||||
|
||||
@@ -58,7 +58,7 @@ def test_unraid_readme_explains_port_changes_and_safe_cleanup() -> None:
|
||||
|
||||
assert "cp deploy/unraid/geointel.env.example .env" in readme
|
||||
assert "GEOINTEL_FRONTEND_PORT=1203" in readme
|
||||
assert "docker build -f deploy/unraid/Dockerfile.all-in-one -t geointel-all-in-one:latest ." in readme
|
||||
assert "docker build --build-arg GEOINTEL_INSTALL_AI=${GEOINTEL_INSTALL_AI:-false} -f deploy/unraid/Dockerfile.all-in-one -t geointel-all-in-one:latest ." in readme
|
||||
assert "bash deploy/unraid/run-dockerman-container.sh" in readme
|
||||
assert "net.unraid.docker.managed=dockerman" in readme
|
||||
assert "curl -fsS" in readme
|
||||
@@ -111,7 +111,8 @@ def test_tower_deploy_uses_single_container_unraid_compose() -> None:
|
||||
|
||||
for script in (powershell, bash):
|
||||
assert "docker compose -f docker-compose.unraid.yml config" in script
|
||||
assert "docker build -f deploy/unraid/Dockerfile.all-in-one -t geointel-all-in-one:latest ." in script
|
||||
assert "--build-arg GEOINTEL_INSTALL_AI=" in script
|
||||
assert "-f deploy/unraid/Dockerfile.all-in-one -t geointel-all-in-one:latest ." in script
|
||||
assert "docker compose -f docker-compose.unraid.yml build geointel" not in script
|
||||
assert "bash deploy/unraid/run-dockerman-container.sh" in script
|
||||
assert "LIVE_SMOKE_CONTAINER=geointel bash scripts/live_migration_smoke.sh" in script
|
||||
|
||||
Reference in New Issue
Block a user