geomind-ai 1.0.0__py3-none-any.whl → 1.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- geomind/__init__.py +11 -11
- geomind/agent.py +441 -445
- geomind/cli.py +125 -125
- geomind/config.py +55 -55
- geomind/tools/__init__.py +27 -27
- geomind/tools/geocoding.py +108 -108
- geomind/tools/processing.py +351 -349
- geomind/tools/stac_search.py +234 -231
- {geomind_ai-1.0.0.dist-info → geomind_ai-1.0.2.dist-info}/METADATA +78 -85
- geomind_ai-1.0.2.dist-info/RECORD +14 -0
- {geomind_ai-1.0.0.dist-info → geomind_ai-1.0.2.dist-info}/licenses/LICENSE +21 -21
- geomind_ai-1.0.0.dist-info/RECORD +0 -14
- {geomind_ai-1.0.0.dist-info → geomind_ai-1.0.2.dist-info}/WHEEL +0 -0
- {geomind_ai-1.0.0.dist-info → geomind_ai-1.0.2.dist-info}/entry_points.txt +0 -0
- {geomind_ai-1.0.0.dist-info → geomind_ai-1.0.2.dist-info}/top_level.txt +0 -0
geomind/tools/stac_search.py
CHANGED
|
@@ -1,231 +1,234 @@
|
|
|
1
|
-
"""
|
|
2
|
-
STAC API search tools for querying Sentinel-2 imagery.
|
|
3
|
-
|
|
4
|
-
Uses the EOPF STAC API at https://stac.core.eopf.eodc.eu
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from typing import Optional, List
|
|
8
|
-
from datetime import datetime, timedelta
|
|
9
|
-
from pystac_client import Client
|
|
10
|
-
|
|
11
|
-
from ..config import (
|
|
12
|
-
STAC_API_URL,
|
|
13
|
-
STAC_COLLECTION,
|
|
14
|
-
DEFAULT_MAX_CLOUD_COVER,
|
|
15
|
-
DEFAULT_MAX_ITEMS,
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def _get_stac_client() -> Client:
|
|
20
|
-
"""Get a STAC API client instance."""
|
|
21
|
-
return Client.open(STAC_API_URL)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def _format_item(item) -> dict:
|
|
25
|
-
"""Format a STAC item into a simplified dictionary."""
|
|
26
|
-
props = item.properties
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
"id": item.id,
|
|
30
|
-
"datetime": props.get("datetime"),
|
|
31
|
-
"cloud_cover": props.get("eo:cloud_cover"),
|
|
32
|
-
"platform": props.get("platform"),
|
|
33
|
-
"bbox": item.bbox,
|
|
34
|
-
"geometry": item.geometry,
|
|
35
|
-
"assets": {
|
|
36
|
-
key: {
|
|
37
|
-
"title": asset.title,
|
|
38
|
-
"href": asset.href,
|
|
39
|
-
"type": asset.media_type,
|
|
40
|
-
}
|
|
41
|
-
for key, asset in item.assets.items()
|
|
42
|
-
if key in ["SR_10m", "SR_20m", "SR_60m", "TCI_10m", "product"]
|
|
43
|
-
},
|
|
44
|
-
"stac_url": f"{STAC_API_URL}/collections/{STAC_COLLECTION}/items/{item.id}",
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def search_imagery(
|
|
49
|
-
bbox: Optional[List[float]] = None,
|
|
50
|
-
start_date: Optional[str] = None,
|
|
51
|
-
end_date: Optional[str] = None,
|
|
52
|
-
max_cloud_cover: Optional[float] = None,
|
|
53
|
-
max_items: Optional[int] = None,
|
|
54
|
-
) -> dict:
|
|
55
|
-
"""
|
|
56
|
-
Search for Sentinel-2 L2A imagery in the EOPF STAC catalog.
|
|
57
|
-
|
|
58
|
-
Args:
|
|
59
|
-
bbox: Bounding box [min_lon, min_lat, max_lon, max_lat]
|
|
60
|
-
start_date: Start date in YYYY-MM-DD format
|
|
61
|
-
end_date: End date in YYYY-MM-DD format
|
|
62
|
-
max_cloud_cover: Maximum cloud cover percentage (0-100)
|
|
63
|
-
max_items: Maximum number of items to return
|
|
64
|
-
|
|
65
|
-
Returns:
|
|
66
|
-
Dictionary with search results including items found
|
|
67
|
-
|
|
68
|
-
Example:
|
|
69
|
-
>>> search_imagery(
|
|
70
|
-
... bbox=[-74.0, 40.7, -73.9, 40.8],
|
|
71
|
-
... start_date="2024-12-01",
|
|
72
|
-
... end_date="2024-12-20",
|
|
73
|
-
... max_cloud_cover=20
|
|
74
|
-
... )
|
|
75
|
-
"""
|
|
76
|
-
if max_cloud_cover is None:
|
|
77
|
-
max_cloud_cover = DEFAULT_MAX_CLOUD_COVER
|
|
78
|
-
if max_items is None:
|
|
79
|
-
max_items = DEFAULT_MAX_ITEMS
|
|
80
|
-
|
|
81
|
-
# Build datetime string
|
|
82
|
-
datetime_str = None
|
|
83
|
-
if start_date or end_date:
|
|
84
|
-
start = start_date or "2015-01-01"
|
|
85
|
-
end = end_date or datetime.now().strftime("%Y-%m-%d")
|
|
86
|
-
datetime_str = f"{start}/{end}"
|
|
87
|
-
|
|
88
|
-
try:
|
|
89
|
-
client = _get_stac_client()
|
|
90
|
-
|
|
91
|
-
# Build search parameters
|
|
92
|
-
search_params = {
|
|
93
|
-
"collections": [STAC_COLLECTION],
|
|
94
|
-
"max_items": max_items,
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if bbox:
|
|
98
|
-
search_params["bbox"] = bbox
|
|
99
|
-
|
|
100
|
-
if datetime_str:
|
|
101
|
-
search_params["datetime"] = datetime_str
|
|
102
|
-
|
|
103
|
-
# Execute search
|
|
104
|
-
search = client.search(**search_params)
|
|
105
|
-
items = list(search.items())
|
|
106
|
-
|
|
107
|
-
# Filter by cloud cover (post-filter since API may not support query param)
|
|
108
|
-
filtered_items = [
|
|
109
|
-
item
|
|
110
|
-
for item in items
|
|
111
|
-
if item.properties.get("eo:cloud_cover", 100) <= max_cloud_cover
|
|
112
|
-
]
|
|
113
|
-
|
|
114
|
-
# Sort by date (newest first)
|
|
115
|
-
filtered_items.sort(
|
|
116
|
-
key=lambda x: x.properties.get("datetime", ""), reverse=True
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
# Format results
|
|
120
|
-
formatted_items = [_format_item(item) for item in filtered_items]
|
|
121
|
-
|
|
122
|
-
return {
|
|
123
|
-
"success": True,
|
|
124
|
-
"total_found": len(items),
|
|
125
|
-
"filtered_count": len(filtered_items),
|
|
126
|
-
"items": formatted_items,
|
|
127
|
-
"search_params": {
|
|
128
|
-
"bbox": bbox,
|
|
129
|
-
"datetime": datetime_str,
|
|
130
|
-
"max_cloud_cover": max_cloud_cover,
|
|
131
|
-
},
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
except Exception as e:
|
|
135
|
-
return {
|
|
136
|
-
"success": False,
|
|
137
|
-
"error": str(e),
|
|
138
|
-
"items": [],
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def get_item_details(item_id: str) -> dict:
|
|
143
|
-
"""
|
|
144
|
-
Get detailed information about a specific STAC item.
|
|
145
|
-
|
|
146
|
-
Args:
|
|
147
|
-
item_id: The STAC item ID (e.g., "S2B_MSIL2A_20251218T110359_...")
|
|
148
|
-
|
|
149
|
-
Returns:
|
|
150
|
-
Dictionary with full item details including all assets
|
|
151
|
-
"""
|
|
152
|
-
try:
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
1
|
+
"""
|
|
2
|
+
STAC API search tools for querying Sentinel-2 imagery.
|
|
3
|
+
|
|
4
|
+
Uses the EOPF STAC API at https://stac.core.eopf.eodc.eu
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Optional, List
|
|
8
|
+
from datetime import datetime, timedelta
|
|
9
|
+
from pystac_client import Client
|
|
10
|
+
|
|
11
|
+
from ..config import (
|
|
12
|
+
STAC_API_URL,
|
|
13
|
+
STAC_COLLECTION,
|
|
14
|
+
DEFAULT_MAX_CLOUD_COVER,
|
|
15
|
+
DEFAULT_MAX_ITEMS,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _get_stac_client() -> Client:
|
|
20
|
+
"""Get a STAC API client instance."""
|
|
21
|
+
return Client.open(STAC_API_URL)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _format_item(item) -> dict:
|
|
25
|
+
"""Format a STAC item into a simplified dictionary."""
|
|
26
|
+
props = item.properties
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
"id": item.id,
|
|
30
|
+
"datetime": props.get("datetime"),
|
|
31
|
+
"cloud_cover": props.get("eo:cloud_cover"),
|
|
32
|
+
"platform": props.get("platform"),
|
|
33
|
+
"bbox": item.bbox,
|
|
34
|
+
"geometry": item.geometry,
|
|
35
|
+
"assets": {
|
|
36
|
+
key: {
|
|
37
|
+
"title": asset.title,
|
|
38
|
+
"href": asset.href,
|
|
39
|
+
"type": asset.media_type,
|
|
40
|
+
}
|
|
41
|
+
for key, asset in item.assets.items()
|
|
42
|
+
if key in ["SR_10m", "SR_20m", "SR_60m", "TCI_10m", "product"]
|
|
43
|
+
},
|
|
44
|
+
"stac_url": f"{STAC_API_URL}/collections/{STAC_COLLECTION}/items/{item.id}",
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def search_imagery(
|
|
49
|
+
bbox: Optional[List[float]] = None,
|
|
50
|
+
start_date: Optional[str] = None,
|
|
51
|
+
end_date: Optional[str] = None,
|
|
52
|
+
max_cloud_cover: Optional[float] = None,
|
|
53
|
+
max_items: Optional[int] = None,
|
|
54
|
+
) -> dict:
|
|
55
|
+
"""
|
|
56
|
+
Search for Sentinel-2 L2A imagery in the EOPF STAC catalog.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
bbox: Bounding box [min_lon, min_lat, max_lon, max_lat]
|
|
60
|
+
start_date: Start date in YYYY-MM-DD format
|
|
61
|
+
end_date: End date in YYYY-MM-DD format
|
|
62
|
+
max_cloud_cover: Maximum cloud cover percentage (0-100)
|
|
63
|
+
max_items: Maximum number of items to return
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Dictionary with search results including items found
|
|
67
|
+
|
|
68
|
+
Example:
|
|
69
|
+
>>> search_imagery(
|
|
70
|
+
... bbox=[-74.0, 40.7, -73.9, 40.8],
|
|
71
|
+
... start_date="2024-12-01",
|
|
72
|
+
... end_date="2024-12-20",
|
|
73
|
+
... max_cloud_cover=20
|
|
74
|
+
... )
|
|
75
|
+
"""
|
|
76
|
+
if max_cloud_cover is None:
|
|
77
|
+
max_cloud_cover = DEFAULT_MAX_CLOUD_COVER
|
|
78
|
+
if max_items is None:
|
|
79
|
+
max_items = DEFAULT_MAX_ITEMS
|
|
80
|
+
|
|
81
|
+
# Build datetime string
|
|
82
|
+
datetime_str = None
|
|
83
|
+
if start_date or end_date:
|
|
84
|
+
start = start_date or "2015-01-01"
|
|
85
|
+
end = end_date or datetime.now().strftime("%Y-%m-%d")
|
|
86
|
+
datetime_str = f"{start}/{end}"
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
client = _get_stac_client()
|
|
90
|
+
|
|
91
|
+
# Build search parameters
|
|
92
|
+
search_params = {
|
|
93
|
+
"collections": [STAC_COLLECTION],
|
|
94
|
+
"max_items": max_items,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if bbox:
|
|
98
|
+
search_params["bbox"] = bbox
|
|
99
|
+
|
|
100
|
+
if datetime_str:
|
|
101
|
+
search_params["datetime"] = datetime_str
|
|
102
|
+
|
|
103
|
+
# Execute search
|
|
104
|
+
search = client.search(**search_params)
|
|
105
|
+
items = list(search.items())
|
|
106
|
+
|
|
107
|
+
# Filter by cloud cover (post-filter since API may not support query param)
|
|
108
|
+
filtered_items = [
|
|
109
|
+
item
|
|
110
|
+
for item in items
|
|
111
|
+
if item.properties.get("eo:cloud_cover", 100) <= max_cloud_cover
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
# Sort by date (newest first)
|
|
115
|
+
filtered_items.sort(
|
|
116
|
+
key=lambda x: x.properties.get("datetime", ""), reverse=True
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Format results
|
|
120
|
+
formatted_items = [_format_item(item) for item in filtered_items]
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
"success": True,
|
|
124
|
+
"total_found": len(items),
|
|
125
|
+
"filtered_count": len(filtered_items),
|
|
126
|
+
"items": formatted_items,
|
|
127
|
+
"search_params": {
|
|
128
|
+
"bbox": bbox,
|
|
129
|
+
"datetime": datetime_str,
|
|
130
|
+
"max_cloud_cover": max_cloud_cover,
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
except Exception as e:
|
|
135
|
+
return {
|
|
136
|
+
"success": False,
|
|
137
|
+
"error": str(e),
|
|
138
|
+
"items": [],
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def get_item_details(item_id: str) -> dict:
|
|
143
|
+
"""
|
|
144
|
+
Get detailed information about a specific STAC item.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
item_id: The STAC item ID (e.g., "S2B_MSIL2A_20251218T110359_...")
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Dictionary with full item details including all assets
|
|
151
|
+
"""
|
|
152
|
+
try:
|
|
153
|
+
client = _get_stac_client()
|
|
154
|
+
collection = client.get_collection(STAC_COLLECTION)
|
|
155
|
+
|
|
156
|
+
# Get the item
|
|
157
|
+
item_url = f"{STAC_API_URL}/collections/{STAC_COLLECTION}/items/{item_id}"
|
|
158
|
+
|
|
159
|
+
import requests
|
|
160
|
+
|
|
161
|
+
response = requests.get(item_url)
|
|
162
|
+
response.raise_for_status()
|
|
163
|
+
item_data = response.json()
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
"success": True,
|
|
167
|
+
"item": item_data,
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
except Exception as e:
|
|
171
|
+
return {
|
|
172
|
+
"success": False,
|
|
173
|
+
"error": str(e),
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def list_recent_imagery(
|
|
178
|
+
location_name: Optional[str] = None,
|
|
179
|
+
days: int = 7,
|
|
180
|
+
max_cloud_cover: Optional[float] = None,
|
|
181
|
+
max_items: Optional[int] = None,
|
|
182
|
+
) -> dict:
|
|
183
|
+
"""
|
|
184
|
+
List recent Sentinel-2 imagery, optionally for a specific location.
|
|
185
|
+
|
|
186
|
+
This is a convenience function that combines geocoding and search.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
location_name: Optional place name to search around
|
|
190
|
+
days: Number of days to look back (default: 7)
|
|
191
|
+
max_cloud_cover: Maximum cloud cover percentage
|
|
192
|
+
max_items: Maximum items to return
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Dictionary with recent imagery items
|
|
196
|
+
"""
|
|
197
|
+
from .geocoding import get_bbox_from_location
|
|
198
|
+
|
|
199
|
+
# Calculate date range
|
|
200
|
+
end_date = datetime.now()
|
|
201
|
+
start_date = end_date - timedelta(days=days)
|
|
202
|
+
|
|
203
|
+
# Get bbox if location provided
|
|
204
|
+
bbox = None
|
|
205
|
+
location_info = None
|
|
206
|
+
|
|
207
|
+
if location_name:
|
|
208
|
+
bbox_result = get_bbox_from_location(location_name)
|
|
209
|
+
if bbox_result["success"]:
|
|
210
|
+
bbox = bbox_result["bbox"]
|
|
211
|
+
location_info = {
|
|
212
|
+
"name": location_name,
|
|
213
|
+
"center": bbox_result["center"],
|
|
214
|
+
"address": bbox_result["address"],
|
|
215
|
+
}
|
|
216
|
+
else:
|
|
217
|
+
return {
|
|
218
|
+
"success": False,
|
|
219
|
+
"error": f"Could not geocode location: {location_name}",
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
# Search for imagery
|
|
223
|
+
result = search_imagery(
|
|
224
|
+
bbox=bbox,
|
|
225
|
+
start_date=start_date.strftime("%Y-%m-%d"),
|
|
226
|
+
end_date=end_date.strftime("%Y-%m-%d"),
|
|
227
|
+
max_cloud_cover=max_cloud_cover,
|
|
228
|
+
max_items=max_items,
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
if location_info:
|
|
232
|
+
result["location"] = location_info
|
|
233
|
+
|
|
234
|
+
return result
|
|
@@ -1,85 +1,78 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: geomind-ai
|
|
3
|
-
Version: 1.0.
|
|
4
|
-
Summary: AI agent for geospatial analysis
|
|
5
|
-
Author: Harsh Shinde
|
|
6
|
-
License-Expression: MIT
|
|
7
|
-
Project-URL: Homepage, https://
|
|
8
|
-
Project-URL: Repository, https://github.com/HarshShinde0/GeoMind
|
|
9
|
-
Project-URL: Documentation, https://github.com/HarshShinde0/GeoMind#readme
|
|
10
|
-
Project-URL: Issues, https://github.com/HarshShinde0/GeoMind/issues
|
|
11
|
-
Keywords: geospatial,satellite-imagery,sentinel-2,ai-agent,remote-sensing,earth-observation
|
|
12
|
-
Classifier: Development Status :: 4 - Beta
|
|
13
|
-
Classifier: Intended Audience :: Science/Research
|
|
14
|
-
Classifier: Intended Audience :: Developers
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
-
Classifier: Topic :: Scientific/Engineering
|
|
19
|
-
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
-
Requires-Python: >=3.10
|
|
21
|
-
Description-Content-Type: text/markdown
|
|
22
|
-
License-File: LICENSE
|
|
23
|
-
Requires-Dist: openai>=1.0.0
|
|
24
|
-
Requires-Dist: pystac-client>=0.8.0
|
|
25
|
-
Requires-Dist: pystac>=1.10.0
|
|
26
|
-
Requires-Dist: xarray>=2024.1.0
|
|
27
|
-
Requires-Dist: zarr>=2.18.0
|
|
28
|
-
Requires-Dist: dask>=2024.1.0
|
|
29
|
-
Requires-Dist: geopy>=2.4.0
|
|
30
|
-
Requires-Dist: fsspec>=2024.1.0
|
|
31
|
-
Requires-Dist: aiohttp>=3.9.0
|
|
32
|
-
Requires-Dist: requests>=2.31.0
|
|
33
|
-
Requires-Dist: s3fs>=2024.1.0
|
|
34
|
-
Requires-Dist: matplotlib>=3.8.0
|
|
35
|
-
Requires-Dist: numpy>=1.26.0
|
|
36
|
-
Requires-Dist: python-dotenv>=1.0.0
|
|
37
|
-
Dynamic: license-file
|
|
38
|
-
|
|
39
|
-
###
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
pip install -r requirements.txt
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
###
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### GeoMind Approach (Zarr + fsspec)
|
|
82
|
-
```
|
|
83
|
-
HTTP Range Request → Stream Chunks → Process in Memory → Result
|
|
84
|
-
~1-5 MB No disk Fast
|
|
85
|
-
```
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: geomind-ai
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: AI agent for geospatial analysis with Sentinel-2 satellite imagery
|
|
5
|
+
Author: Harsh Shinde
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/HarshShinde0/GeoMind
|
|
8
|
+
Project-URL: Repository, https://github.com/HarshShinde0/GeoMind
|
|
9
|
+
Project-URL: Documentation, https://github.com/HarshShinde0/GeoMind#readme
|
|
10
|
+
Project-URL: Issues, https://github.com/HarshShinde0/GeoMind/issues
|
|
11
|
+
Keywords: geospatial,satellite-imagery,sentinel-2,ai-agent,remote-sensing,earth-observation
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: openai>=1.0.0
|
|
24
|
+
Requires-Dist: pystac-client>=0.8.0
|
|
25
|
+
Requires-Dist: pystac>=1.10.0
|
|
26
|
+
Requires-Dist: xarray>=2024.1.0
|
|
27
|
+
Requires-Dist: zarr>=2.18.0
|
|
28
|
+
Requires-Dist: dask>=2024.1.0
|
|
29
|
+
Requires-Dist: geopy>=2.4.0
|
|
30
|
+
Requires-Dist: fsspec>=2024.1.0
|
|
31
|
+
Requires-Dist: aiohttp>=3.9.0
|
|
32
|
+
Requires-Dist: requests>=2.31.0
|
|
33
|
+
Requires-Dist: s3fs>=2024.1.0
|
|
34
|
+
Requires-Dist: matplotlib>=3.8.0
|
|
35
|
+
Requires-Dist: numpy>=1.26.0
|
|
36
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
### Install Dependencies
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install -r requirements.txt
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Run the Agent
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Interactive mode
|
|
49
|
+
geomind
|
|
50
|
+
|
|
51
|
+
# Single query
|
|
52
|
+
geomind --query "Find recent imagery of Paris"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Example Queries
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
💬 "Create an RGB composite for the most recent image of London"
|
|
60
|
+
|
|
61
|
+
💬 "Calculate NDVI for Central Park, New York"
|
|
62
|
+
|
|
63
|
+
💬 "What images are available for Tokyo with less than 10% cloud cover?"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Approach
|
|
67
|
+
|
|
68
|
+
### Traditional Approach
|
|
69
|
+
```
|
|
70
|
+
Full Scene Download → Local Storage → Process → Result
|
|
71
|
+
~720 MB Disk I/O Slow
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### GeoMind Approach (Zarr + fsspec)
|
|
75
|
+
```
|
|
76
|
+
HTTP Range Request → Stream Chunks → Process in Memory → Result
|
|
77
|
+
~1-5 MB No disk Fast
|
|
78
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
geomind/__init__.py,sha256=mma_vqNjiOpc0WOvclIdFqULWUnc7P8cDfAfqkPOsd4,151
|
|
2
|
+
geomind/agent.py,sha256=iE-mwRLuA5sn4YtCQYU30GxcwsJoDhbhxdUrYsUJU0c,15010
|
|
3
|
+
geomind/cli.py,sha256=tmMkvO9scyvzpRtiKbcb1jtWn3fSgFoywQmuusmjDuI,3283
|
|
4
|
+
geomind/config.py,sha256=hv3DNM7QbCuOSWuPmXeiVxEbGxH7fRLxOc8jexd7rrY,2011
|
|
5
|
+
geomind/tools/__init__.py,sha256=8iumGwIFHh8Bj1VJNgZtmKnEBqCy6_cRkzYENDUH7x4,720
|
|
6
|
+
geomind/tools/geocoding.py,sha256=hiLpzHpkJP6IgWAUtZMnHL6qpkWcYWVLpGe0yfYxXv8,3007
|
|
7
|
+
geomind/tools/processing.py,sha256=vMp8PMb8h8QiBRBFRvI_TGRqEDBTDQvSV0zvC1Ji5bc,9976
|
|
8
|
+
geomind/tools/stac_search.py,sha256=V6230l4aHjedPWXu-3Cjmfc6diSFh5zsycewUko0W8k,6452
|
|
9
|
+
geomind_ai-1.0.2.dist-info/licenses/LICENSE,sha256=aveu0ERm7I3NnIu8rtpKdvd0eyRpmktXKU0PBABtSN0,1069
|
|
10
|
+
geomind_ai-1.0.2.dist-info/METADATA,sha256=tF0kr6M6J_Vo1_RiU3sAqseL_76xU2rvJUT52yej8Mw,2233
|
|
11
|
+
geomind_ai-1.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
12
|
+
geomind_ai-1.0.2.dist-info/entry_points.txt,sha256=2nPR3faYKl0-1epccvzMJ2xdi-Q1Vt7aOSvA84oIWnw,45
|
|
13
|
+
geomind_ai-1.0.2.dist-info/top_level.txt,sha256=rjKWNSNRhq4R9xJoZGsG-eAaH7BmTVNvfrrbcaJMIIs,8
|
|
14
|
+
geomind_ai-1.0.2.dist-info/RECORD,,
|