Tool/naip fetcher (#12)

* Add initial NAIP fetcher

* Swap to Element84's EarthSearch API for NAIP STAC search and download

* clip to bounds of aoi

* Swap to Element84's EarthSearch API for NAIP STAC search and download

* rename bands and remove dask chunking

* Add DS_Store to .gitignore

* restrict date range for naip test

* Adjust timerange for tests

* Add xarray to pyproj

* Reduce aoi size

* revert test to use tmp path

* Update return types for tool to ensure state gets updated

* Mark naip test as xfail

* Fix geom creation

---------

Co-authored-by: lillythomas <lillyelizathomas@gmail.com>
Co-authored-by: Daniel Wiesmann <yellowcap@users.noreply.github.com>
This commit is contained in:
Leo Thomas
2025-12-05 08:53:04 +00:00
committed by GitHub
parent be8affaa6c
commit 8f0239c1c9
9 changed files with 2444 additions and 1780 deletions
+7 -2
View File
@@ -12,7 +12,12 @@ def geo_assistant_fixture():
geometry=Point(type="Point", coordinates=[-9.1393, 38.7223]),
properties={"name": "Neighbourhood Cafe Lisbon"},
)
return GeoAssistantState(place=place_geojson, search_area=None, messages=[])
return GeoAssistantState(
place=place_geojson,
search_area=None,
messages=[],
naip_png_path="path/to/naip.png",
)
async def test_get_search_area(geo_assistant_fixture):
@@ -37,4 +42,4 @@ async def test_get_search_area(geo_assistant_fixture):
# Verify the buffer was created around the correct place
search_area = command.update["search_area"]
assert search_area["type"] == "Polygon"
assert search_area.geometry.type == "Polygon"
+58
View File
@@ -0,0 +1,58 @@
import pytest
from pathlib import Path
from shapely.geometry import box, mapping
from langchain_core.tools.base import ToolCall
from geo_assistant.tools.naip import fetch_naip_img
@pytest.mark.asyncio
@pytest.mark.xfail
async def test_fetch_naip(tmp_path):
"""
Integration test: hit MPC STAC for NAIP around Union Market (DC),
load imagery via odc-stac, and save an RGB PNG.
NOTE: This test requires:
- Internet access (to reach Planetary Computer STAC + blobs)
- Planetary Computer / NAIP service to be up
"""
# Union Market coordinates from GeoNames: 38.90789, -76.99831
# N 38°5428″ W 76°5954″
# We'll use a small neighborhood AOI around that point.
# :contentReference[oaicite:0]{index=0}
lat = 38.90789
lon = -76.99831
# ~0.01 degrees (~1.1 km) buffer in each direction
aoi = box(lon - 0.0001, lat - 0.0001, lon + 0.0001, lat + 0.0001)
aoi_geojson = mapping(aoi)
out_png = tmp_path / "naip_test_img.png"
tool_call = ToolCall(
name="fetch_naip_img",
args={
"aoi_geojson": aoi_geojson,
"start_date": "2021-01-01",
"end_date": "2021-12-31",
"out_png_path": str(out_png),
"resolution": 1.0,
},
type="tool_call",
id="test_tool_call_id",
)
# Call the actual tool no STAC / odc-stac mocking
result = await fetch_naip_img.ainvoke(tool_call["args"])
# Basic sanity checks on result
assert result["stac_item_count"] > 0, "Expected at least one NAIP item"
assert "time" in result["dataset_dims"]
assert result["dataset_dims"]["time"] >= 1
# PNG should have been written to disk
png_path = Path(result["png_path"])
assert png_path == out_png
assert png_path.is_file(), f"PNG was not created at {png_path}"