unknown commited on
Commit ·
059a062
1
Parent(s): d60f9a3
cleaning commit
Browse files- CLAUDE.md +0 -199
- README.md +0 -64
- agent/__init__.py +0 -1
- app/__init__.py +0 -1
- app/main.py +28 -44
- data/README.md +3 -0
- docs/Agent4EO_PRD.md +0 -289
- environment.yml +0 -17
- eo/__init__.py +0 -1
CLAUDE.md
DELETED
|
@@ -1,199 +0,0 @@
|
|
| 1 |
-
# CLAUDE.md
|
| 2 |
-
|
| 3 |
-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
| 4 |
-
|
| 5 |
-
## Project Overview
|
| 6 |
-
|
| 7 |
-
**Agent4EO** is a single-process, local demonstration platform for agentic Earth Observation (EO) analysis. It routes natural language queries to appropriate EO processing tools, executes computations on curated satellite imagery samples, and returns visual outputs with AI-generated interpretations.
|
| 8 |
-
|
| 9 |
-
**Current Status**: Project is in planning phase. The complete specification is in [docs/Agent4EO_PRD.md](docs/Agent4EO_PRD.md).
|
| 10 |
-
|
| 11 |
-
**Stack**: Python 3.11, GDAL/Rasterio (geospatial), LangChain + Mistral AI (agent orchestration), Gradio (UI).
|
| 12 |
-
|
| 13 |
-
## Development Commands
|
| 14 |
-
|
| 15 |
-
### Environment Setup
|
| 16 |
-
```bash
|
| 17 |
-
# Environment must be created externally via conda/mamba with dependencies from conda-forge
|
| 18 |
-
# Dependencies: python=3.11, numpy, gdal, rasterio, gradio, pydantic, pyyaml
|
| 19 |
-
# langchain-core, langchain-community, mistralai, matplotlib (optional), pytest (optional)
|
| 20 |
-
```
|
| 21 |
-
|
| 22 |
-
### Running the Application
|
| 23 |
-
```bash
|
| 24 |
-
export MISTRAL_API_KEY="your_key_here"
|
| 25 |
-
python -m app.main
|
| 26 |
-
```
|
| 27 |
-
|
| 28 |
-
### Testing
|
| 29 |
-
```bash
|
| 30 |
-
pytest tests/ # Run all tests
|
| 31 |
-
pytest tests/test_ndvi_math_small.py # Run specific test
|
| 32 |
-
```
|
| 33 |
-
|
| 34 |
-
## High-Level Architecture
|
| 35 |
-
|
| 36 |
-
### Agent Flow Pattern
|
| 37 |
-
The application uses **LLM-powered tool routing** with structured outputs, not heavy agent frameworks:
|
| 38 |
-
|
| 39 |
-
```
|
| 40 |
-
User Input (sample selection + NL query)
|
| 41 |
-
↓
|
| 42 |
-
agent/router.py (Mistral LLM selects tool via LangChain tool-calling)
|
| 43 |
-
↓
|
| 44 |
-
agent/tools.py (LangChain tool wrappers)
|
| 45 |
-
↓
|
| 46 |
-
eo/{ndvi|lst|dnbr}.py (geospatial computation)
|
| 47 |
-
↓
|
| 48 |
-
agent/interpreter.py (Mistral LLM generates narrative)
|
| 49 |
-
↓
|
| 50 |
-
Gradio UI (display preview, histogram, stats, interpretation)
|
| 51 |
-
```
|
| 52 |
-
|
| 53 |
-
**Key Pattern**: Strict mismatch handling—if `sample.task` doesn't match the intended tool, the system refuses with a clear message rather than attempting execution.
|
| 54 |
-
|
| 55 |
-
### Three Core EO Tools
|
| 56 |
-
|
| 57 |
-
#### 1. NDVI (Normalized Difference Vegetation Index)
|
| 58 |
-
- **File**: `eo/ndvi.py`
|
| 59 |
-
- **Input**: Single Sentinel-2 GeoTIFF with RED & NIR bands
|
| 60 |
-
- **Formula**: `(NIR - RED) / (NIR + RED + 1e-6)`, clipped to [-1, 1]
|
| 61 |
-
- **Output**: float32 GeoTIFF, preview PNG, histogram, stats (min/max/mean/std/percentiles)
|
| 62 |
-
- **Use case**: Vegetation health assessment
|
| 63 |
-
|
| 64 |
-
#### 2. LST (Land Surface Temperature)
|
| 65 |
-
- **File**: `eo/lst.py`
|
| 66 |
-
- **Input**: Single Landsat 8/9 thermal band (Band 10) + metadata constants
|
| 67 |
-
- **Process**: DN → Radiance → Brightness Temp → LST (with emissivity correction)
|
| 68 |
-
- **Critical**: Uses Planck constants (K1, K2), emissivity (ε), wavelength (λ ≈ 10.895µm)
|
| 69 |
-
- **Constants**: Stored per-sample in `config/samples_index.json` metadata
|
| 70 |
-
- **Output**: float32 GeoTIFF in Celsius, preview, histogram, temperature stats
|
| 71 |
-
- **Use case**: Urban heat island analysis
|
| 72 |
-
|
| 73 |
-
#### 3. dNBR (Differenced Normalized Burn Ratio)
|
| 74 |
-
- **File**: `eo/dnbr.py`
|
| 75 |
-
- **Input**: Pre/post Sentinel-2 pair with NIR & SWIR2 bands
|
| 76 |
-
- **Formula**: `NBR = (NIR - SWIR2) / (NIR + SWIR2 + 1e-6); dNBR = NBR_post - NBR_pre`
|
| 77 |
-
- **Severity classes**: Unburned/Low/Moderate/High/Very High based on thresholds in `config/heuristics.yaml`
|
| 78 |
-
- **Output**: float32 GeoTIFF, preview, histogram, stats + severity class distributions
|
| 79 |
-
- **Use case**: Wildfire burn severity mapping
|
| 80 |
-
|
| 81 |
-
### Configuration-Driven Architecture
|
| 82 |
-
|
| 83 |
-
**Sample Registry** (`config/samples_index.json`):
|
| 84 |
-
- Single source of truth for all input data
|
| 85 |
-
- Contains paths, task types, band indices (1-based), and metadata constants
|
| 86 |
-
- Router validates `sample.task` against requested tool
|
| 87 |
-
|
| 88 |
-
**Interpretation Thresholds** (`config/heuristics.yaml`):
|
| 89 |
-
- Thresholds inform LLM wording, don't change math
|
| 90 |
-
- Examples: NDVI mean ranges, LST temperature thresholds, dNBR severity bins
|
| 91 |
-
- Separate from computation logic for easy tuning
|
| 92 |
-
|
| 93 |
-
### Structured Output Pattern
|
| 94 |
-
|
| 95 |
-
All outputs use **Pydantic schemas** enforced via LangChain's `JsonOutputParser`:
|
| 96 |
-
|
| 97 |
-
```python
|
| 98 |
-
class ToolResult(BaseModel):
|
| 99 |
-
raster_path: str # Output GeoTIFF path
|
| 100 |
-
preview_png: str # 8-bit normalized preview
|
| 101 |
-
histogram_png: Optional[str]
|
| 102 |
-
metrics: Dict[str, float] # Stats: min/max/mean/std/percentiles
|
| 103 |
-
extras: Dict[str, Any] # Tool-specific data (e.g., severity counts)
|
| 104 |
-
|
| 105 |
-
class Interpretation(BaseModel):
|
| 106 |
-
headline: str
|
| 107 |
-
bullets: List[str] # Must include numeric values
|
| 108 |
-
caveats: List[str] # 0-2 items
|
| 109 |
-
```
|
| 110 |
-
|
| 111 |
-
## Critical Implementation Details
|
| 112 |
-
|
| 113 |
-
### Geospatial I/O Requirements
|
| 114 |
-
- **CRS/Transform**: All outputs MUST preserve input CRS and geotransform
|
| 115 |
-
- **NoData handling**: Consistent handling of NoData values across all tools
|
| 116 |
-
- **Band indices**: 1-based (GDAL convention), specified per-sample in registry
|
| 117 |
-
- **Output storage**: `outputs/<task>/<sample_id>/<timestamp>/` (internal use)
|
| 118 |
-
|
| 119 |
-
### LLM Orchestration Constraints
|
| 120 |
-
- **Router**: Use LangChain tool-calling (not heavy agents) for tool selection
|
| 121 |
-
- **Mismatch handling**: If tool doesn't match `sample.task`, refuse immediately—no retries
|
| 122 |
-
- **Interpretation**: Pass `{task, sample.title, metrics, extras, thresholds_excerpt}` to LLM
|
| 123 |
-
- **Schema enforcement**: Use `JsonOutputParser` to guarantee `Interpretation` structure
|
| 124 |
-
|
| 125 |
-
### Dependency Management
|
| 126 |
-
- **Package manager**: Conda/conda-forge ONLY (not pip)
|
| 127 |
-
- **Python version**: 3.11 (pinned for GDAL compatibility)
|
| 128 |
-
- **No environment commands**: README lists dependencies but doesn't run conda commands
|
| 129 |
-
- **Environment setup**: Handled externally by user
|
| 130 |
-
|
| 131 |
-
### Scope Constraints (Do NOT implement)
|
| 132 |
-
- No file uploads
|
| 133 |
-
- No remote STAC catalogs or cloud data access
|
| 134 |
-
- No FastAPI/REST API (single-process only)
|
| 135 |
-
- No databases
|
| 136 |
-
- No ML models (CLIP, segmentation, etc.)
|
| 137 |
-
- No Docker containers
|
| 138 |
-
- No batch processing
|
| 139 |
-
- No vector analytics
|
| 140 |
-
- No download feature in UI (display-only)
|
| 141 |
-
- No CI/CD pipelines in v1
|
| 142 |
-
|
| 143 |
-
## Code Organization Principles
|
| 144 |
-
|
| 145 |
-
### File Length and Structure
|
| 146 |
-
- Keep files **< 200 lines** when possible
|
| 147 |
-
- Functions should be small and focused
|
| 148 |
-
- Separate concerns: math in `eo/`, orchestration in `agent/`, UI in `app/`
|
| 149 |
-
|
| 150 |
-
### Module Responsibilities
|
| 151 |
-
- **`eo/`**: Pure geospatial computation (NDVI/LST/dNBR math + I/O)
|
| 152 |
-
- **`eo/io.py`**: Raster read/write helpers with CRS/transform preservation
|
| 153 |
-
- **`eo/viz.py`**: Preview PNG and histogram generation
|
| 154 |
-
- **`agent/schema.py`**: Pydantic models only
|
| 155 |
-
- **`agent/tools.py`**: LangChain tool wrappers (thin layer over `eo/` functions)
|
| 156 |
-
- **`agent/router.py`**: LLM tool selection logic
|
| 157 |
-
- **`agent/interpreter.py`**: LLM narrative generation
|
| 158 |
-
- **`agent/prompts/`**: Externalized system prompts
|
| 159 |
-
- **`app/main.py`**: Gradio UI only (no business logic)
|
| 160 |
-
|
| 161 |
-
### Prompt Engineering
|
| 162 |
-
- **Router prompt**: Include user sentence, sample ID, sample.task, and strict tool contracts
|
| 163 |
-
- **Interpreter prompt**: Concise style, require numeric values in bullets, limit caveats to 0-2
|
| 164 |
-
- **Externalize prompts**: Store in `agent/prompts/*.txt` for easy editing
|
| 165 |
-
|
| 166 |
-
## Performance Targets
|
| 167 |
-
|
| 168 |
-
- App startup: < 3 seconds
|
| 169 |
-
- Tool execution (50-100 MB samples): < 2-3 seconds
|
| 170 |
-
- Memory footprint: < 400 MB during processing
|
| 171 |
-
|
| 172 |
-
## Testing Focus
|
| 173 |
-
|
| 174 |
-
### Critical Test Cases
|
| 175 |
-
1. **Routing correctness**: Vegetation query → NDVI, heat query → LST, burn query → dNBR
|
| 176 |
-
2. **Mismatch handling**: Wrong tool for sample type → clear refusal message
|
| 177 |
-
3. **Output quality**: Valid GeoTIFF with preserved CRS/transform, correct NoData handling
|
| 178 |
-
4. **Interpretation format**: Valid JSON with numeric values in bullets
|
| 179 |
-
|
| 180 |
-
### Test Files
|
| 181 |
-
- `tests/test_router_mismatch.py`: Validate refusal on tool-sample mismatches
|
| 182 |
-
- `tests/test_ndvi_math_small.py`: Verify NDVI computation accuracy
|
| 183 |
-
|
| 184 |
-
## Common Pitfalls
|
| 185 |
-
|
| 186 |
-
1. **LST constants**: Don't hardcode K1/K2/emissivity—read from sample metadata
|
| 187 |
-
2. **Band indices**: Registry uses 1-based indices (GDAL convention), not 0-based
|
| 188 |
-
3. **CRS preservation**: Always copy input CRS/transform to output GeoTIFF
|
| 189 |
-
4. **Router retries**: Don't implement retry logic—refuse on mismatch immediately
|
| 190 |
-
5. **UI downloads**: Do not add download buttons (display-only requirement)
|
| 191 |
-
6. **Dependency installation**: README must NOT include conda/pip commands
|
| 192 |
-
|
| 193 |
-
## Key Files to Reference
|
| 194 |
-
|
| 195 |
-
- **[docs/Agent4EO_PRD.md](docs/Agent4EO_PRD.md)**: Complete specification (definitive source)
|
| 196 |
-
- **`config/samples_index.json`**: Sample registry with paths, tasks, bands, constants
|
| 197 |
-
- **`config/heuristics.yaml`**: Interpretation thresholds for LLM narratives
|
| 198 |
-
- **`agent/schema.py`**: Pydantic models for structured outputs
|
| 199 |
-
- **`eo/ndvi.py`, `eo/lst.py`, `eo/dnbr.py`**: Core computation logic
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
README.md
DELETED
|
@@ -1,64 +0,0 @@
|
|
| 1 |
-
---
|
| 2 |
-
title: Agent4EO
|
| 3 |
-
emoji: 🛰️
|
| 4 |
-
colorFrom: blue
|
| 5 |
-
colorTo: purple
|
| 6 |
-
sdk: gradio
|
| 7 |
-
sdk_version: 5.49.1
|
| 8 |
-
app_file: app/main.py
|
| 9 |
-
pinned: false
|
| 10 |
-
---
|
| 11 |
-
|
| 12 |
-
# Agent4EO
|
| 13 |
-
|
| 14 |
-
A single-process, local demonstration platform for agentic Earth Observation (EO) analysis. Routes natural language queries to appropriate EO processing tools, executes computations on curated satellite imagery samples, and returns visual outputs with AI-generated interpretations.
|
| 15 |
-
|
| 16 |
-
## Stack
|
| 17 |
-
|
| 18 |
-
- Python 3.11
|
| 19 |
-
- GDAL/Rasterio (geospatial)
|
| 20 |
-
- LangChain + Mistral AI (agent orchestration)
|
| 21 |
-
- Gradio (UI)
|
| 22 |
-
|
| 23 |
-
## Dependencies
|
| 24 |
-
|
| 25 |
-
Create a conda/mamba environment with the following packages from conda-forge:
|
| 26 |
-
|
| 27 |
-
- `python=3.11`
|
| 28 |
-
- `numpy`
|
| 29 |
-
- `gdal`
|
| 30 |
-
- `rasterio`
|
| 31 |
-
- `gradio`
|
| 32 |
-
- `pydantic`
|
| 33 |
-
- `pyyaml`
|
| 34 |
-
- `langchain-core`
|
| 35 |
-
- `langchain-community`
|
| 36 |
-
- `mistralai`
|
| 37 |
-
- `matplotlib` (optional, for histograms)
|
| 38 |
-
- `pytest` (optional, for testing)
|
| 39 |
-
|
| 40 |
-
## Configuration
|
| 41 |
-
|
| 42 |
-
### Mistral API Key
|
| 43 |
-
|
| 44 |
-
Provide your Mistral API key via one of these methods (checked in order):
|
| 45 |
-
|
| 46 |
-
1. **Environment variable** (recommended):
|
| 47 |
-
'''bash
|
| 48 |
-
export MISTRAL_API_KEY="your_key_here"
|
| 49 |
-
'''
|
| 50 |
-
|
| 51 |
-
2. **Config file**: Copy `config/app.yaml.example` to `config/app.yaml` and set `mistral_api_key`.
|
| 52 |
-
|
| 53 |
-
## Running the Application
|
| 54 |
-
|
| 55 |
-
'''bash
|
| 56 |
-
python -m app.main
|
| 57 |
-
'''
|
| 58 |
-
|
| 59 |
-
The Gradio UI will launch at http://localhost:7860.
|
| 60 |
-
|
| 61 |
-
## Notes
|
| 62 |
-
|
| 63 |
-
- **UI is display-only**: No download buttons. Artifacts are written to `outputs/<task>/<sample_id>/<timestamp>/` for internal use.
|
| 64 |
-
- **Curated samples only**: No file uploads. Samples are defined in `config/samples_index.json`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
agent/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
"""Agent orchestration for Agent4EO."""
|
|
|
|
|
|
app/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
"""Gradio UI application."""
|
|
|
|
|
|
app/main.py
CHANGED
|
@@ -129,65 +129,49 @@ def run_analysis(
|
|
| 129 |
except Exception as e:
|
| 130 |
return None, None, None, "", f"❌ Error: {str(e)}"
|
| 131 |
|
| 132 |
-
about_md = """
|
| 133 |
-
# Agent4EO — **Exploring agentic workflows for Earth Observation (EO).**
|
| 134 |
-
|
| 135 |
-
Despite the abundance of EO data, many use cases still struggle to cross the gap from research to deployment, from geopsatial experts to every day end-users.
|
| 136 |
-
Inspired by Google's Earth AI, this project goal is to interrogate and unpack what lies behind **geospatial reasoning**: how modern AI weaves physics, context and satellite pixels into clear operational insights.
|
| 137 |
-
|
| 138 |
-
Agent4EO demonstrates how recent advances in Large Language Models and Earth-observation algorithms can be composed into agentic workflows to translate EO data potential into practical understandble analyses.
|
| 139 |
-
|
| 140 |
-
---
|
| 141 |
-
## Current capabilities:
|
| 142 |
-
The user selects a curated sample and submits a plain-text request.
|
| 143 |
-
A routing agent (Ministral-3B via LangChain tool calling) chooses exactly one analysis tool and executes it.
|
| 144 |
-
Implemented tools include NDVI on Sentinel-2 (vegetation condition), LST on Landsat 8/9 (land surface temperature in °C), and dNBR on paired Sentinel-2 scenes (burn severity).
|
| 145 |
-
Processing relies on rasterio/GDAL with correct CRS/transform and NoData handling.
|
| 146 |
-
The interface returns a quicklook, a histogram, quantitative metrics (e.g., min/mean/max and percentiles), and a concise, number-grounded interpretation generated by the LLM.
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
* **Operational by design.** The same pattern can scale to monitoring jobs, alerts, and reports—without burying users in geospatial plumbing.
|
| 150 |
-
|
| 151 |
-
Future directions:
|
| 152 |
-
SAR-based oil-spill detection, flood mapping,
|
| 153 |
-
multi-temporal change maps
|
| 154 |
-
region-of-interest operations and overlays
|
| 155 |
-
semantic scene search, multilingual explanations, and confidence cues.
|
| 156 |
-
The aim is a lightweight, extensible path from prompt to analysis to interpretation that supports real-world, repeatable EO workflows.
|
| 157 |
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
## What this could do next (ideas)
|
| 161 |
-
|
| 162 |
-
* **New skills:** NDWI for surface water, UHI intensity, vegetation anomalies, SAR-based flood extent, cloud/shadow masking, multi-temporal change maps.
|
| 163 |
-
* **Richer narratives:** Compare samples (“today vs last month”), generate incident summaries, or “explain like I’m a mayor” vs “explain like I’m a hydrologist.”
|
| 164 |
-
* **Spatial drill-downs:** Simple zonal stats over neighborhoods, parks, burn perimeters; hotspot labeling and quadrant summaries.
|
| 165 |
-
* **Quality controls:** Confidence scores, basic QA flags, and transparent assumptions (e.g., emissivity choices).
|
| 166 |
-
* **Interoperability:** Hook into STAC catalogs, task queues, or ops notebooks—while keeping the same agentic front door.
|
| 167 |
-
* **Human-in-the-loop:** Let reviewers approve/rewrite the agent’s explanations before sharing.
|
| 168 |
|
| 169 |
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
|
| 171 |
-
## Notes & caveats
|
| 172 |
-
|
| 173 |
-
* This is a **display-only MVP** using curated samples; outputs are saved locally for inspection.
|
| 174 |
-
* Thresholds (e.g., dNBR classes, “hot” LST) are **demo defaults**—tune them to your context.
|
| 175 |
-
* Interpretations are grounded in computed metrics but **not a substitute for expert analysis**.
|
| 176 |
-
|
| 177 |
-
If you’re excited by agentic EO—and believe satellite analytics should be as simple as **asking a question**—you’re in the right place.
|
| 178 |
|
| 179 |
"""
|
| 180 |
|
|
|
|
| 181 |
def create_ui():
|
| 182 |
"""Create Gradio interface."""
|
| 183 |
samples = load_sample_registry()
|
| 184 |
sample_choices = [s.title for s in samples.values()]
|
| 185 |
|
| 186 |
with gr.Blocks(title="Agent4EO") as demo:
|
| 187 |
-
gr.Markdown("# 🛰️ Agent4EO
|
| 188 |
|
| 189 |
|
| 190 |
-
with gr.Accordion("
|
|
|
|
| 191 |
gr.Markdown(about_md)
|
| 192 |
|
| 193 |
with gr.Row():
|
|
|
|
| 129 |
except Exception as e:
|
| 130 |
return None, None, None, "", f"❌ Error: {str(e)}"
|
| 131 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
|
| 133 |
+
about_md = """
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
|
| 135 |
---
|
| 136 |
+
## Challenge
|
| 137 |
+
- **Decision-makers** don’t need raw imagery; they need clear, **operational signals**, still many Earth Observation (EO) use-cases fail to cross the gap from geospatial experts to end-users, **from research to deployment**.
|
| 138 |
+
- Staying current with a **fast-moving field** while making **geospatial reasoning** explicit : As a **curiosity-driven AI Research Engineer**, I had to **investigate agentic workflows** and the pipeline structures behind groundbreaking initiatives capturing attention: [Google Earth AI](https://ai.google/earth-ai/), [Axion Planetary MCP](https://github.com/Dhenenjay/axion-planetary-mcp), [Ageospatial](https://ageospatial.com/), [GeoRetina](https://www.georetina.com/)
|
| 139 |
+
|
| 140 |
+
## Solution
|
| 141 |
+
- Curated samples are fed to a **routing agent** that selects the appropriate analysis, like a geospatial expert would.
|
| 142 |
+
- Implemented tools: **Vegetation condition analysis** (NDVI), **Urban Heat Island monitoring** (LST), and **burn scars charcterization** (dNBR).
|
| 143 |
+
- **OpenStreetMap context** (API call) is attached to computed metrics to anchor results to places.
|
| 144 |
+
- A second **LLM** pass turns numbers + context into a concise operational narrative.
|
| 145 |
+
- The interface displays a **quicklook**, **histogram**, quantitative **metrics**, and a short, number-grounded **explanation**.
|
| 146 |
+
- The agent is powered by **Ministral-3B** for efficiency; orchestration uses **LangChain**. EO I/O uses **Rasterio** with proper CRS/transform and not-relevant data handling.
|
| 147 |
+
|
| 148 |
+
## Results
|
| 149 |
+
- A **live, accessible project** : I believe in public demos over private perfection.
|
| 150 |
+
- **Clear visual and textual outputs** understandable by non-experts, revealing Earth Observation's added value.
|
| 151 |
+
- A concrete **exploration of agentic orchestration** for EO that other practitioners can reuse as a reference pattern.
|
| 152 |
+
|
| 153 |
+
## Possible extensions
|
| 154 |
+
- Move to true **prompt-driven analysis**: users specify topic, period, and region; the agent fetches data on demand (from a way larger range of sources) and selects tools accordingly.
|
| 155 |
+
- **Richer narratives** tailored to roles (territorial planning, insurers...) with domain-aware capacity.
|
| 156 |
+
- Expand the **toolset**: multi-temporal change maps, flood risk, landslide tracking, building characterization, oil-spill detection, SAR flood mapping, and embeddings-based heads with integration of **Foundation Models**
|
| 157 |
+
- Enable **on-the-fly tool drafting** (code synthesis) when safe and auditable.
|
| 158 |
+
- Be **deliberate with LLMs**: for such a small range of tools, selection via LLM isn’t necessary, and with such low context models can hallucinate. Agents should be used where they add real leverage, beyond conventional programming capacities.
|
| 159 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
|
| 161 |
"""
|
| 162 |
|
| 163 |
+
|
| 164 |
def create_ui():
|
| 165 |
"""Create Gradio interface."""
|
| 166 |
samples = load_sample_registry()
|
| 167 |
sample_choices = [s.title for s in samples.values()]
|
| 168 |
|
| 169 |
with gr.Blocks(title="Agent4EO") as demo:
|
| 170 |
+
gr.Markdown("# 🛰️ Agent4EO - A demo by Thomas OLIVE")
|
| 171 |
|
| 172 |
|
| 173 |
+
with gr.Accordion("Agent4EO is a demo that investigates and demystifies geospatial reasoning by using a lightweight agent to turn curated satellite samples into clear, operational insights with concise narratives.",
|
| 174 |
+
open=True):
|
| 175 |
gr.Markdown(about_md)
|
| 176 |
|
| 177 |
with gr.Row():
|
data/README.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
---
|
docs/Agent4EO_PRD.md
DELETED
|
@@ -1,289 +0,0 @@
|
|
| 1 |
-
# Agent4EO — PRD (MVP, one‑shot build)
|
| 2 |
-
|
| 3 |
-
> **Purpose**: Provide Claude Code with everything needed to generate an almost‑ready‑to‑use local demo platform that routes a plain‑text user request to the correct Earth Observation (EO) tool, runs the computation on a curated sample from `data/samples/`, and returns visuals, stats, and an interpretation. **The UI is display‑only** (no download feature). **Environment setup is handled externally**; Claude must only specify dependencies, not run conda/mamba commands.
|
| 4 |
-
|
| 5 |
-
---
|
| 6 |
-
|
| 7 |
-
## 1) Summary
|
| 8 |
-
|
| 9 |
-
Agent4EO is a **single‑process, local app** (conda‑based) where a user:
|
| 10 |
-
1) picks a curated **sample** from `/data/samples/`,
|
| 11 |
-
2) writes a **plain text sentence** (e.g., “give me burn severity for this S2 pair”), and
|
| 12 |
-
3) the **agent** routes to exactly one tool and executes it:
|
| 13 |
-
|
| 14 |
-
- **NDVI (Sentinel‑2 single scene)**
|
| 15 |
-
- **LST (Landsat 8/9 single scene)**
|
| 16 |
-
- **dNBR (Sentinel‑2 pre/post pair)**
|
| 17 |
-
|
| 18 |
-
Outputs: **preview PNG**, **histogram PNG** (if matplotlib present), compact **stats** (JSON/table), and a short **LLM interpretation** (displayed in UI). Artifacts (e.g., computed GeoTIFF) may be written under `outputs/` for internal inspection, but **no download control** is exposed in the UI.
|
| 19 |
-
|
| 20 |
-
**No file uploads. No STAC/cloud. No Docker.** LLM = **Mistral** (via API) orchestrated with **LangChain** tool‑calling. (See §11 for Claude Code execution guidelines.)
|
| 21 |
-
|
| 22 |
-
---
|
| 23 |
-
|
| 24 |
-
## 2) Goals (MVP)
|
| 25 |
-
|
| 26 |
-
- **Samples‑only** selection from `config/samples_index.json`.
|
| 27 |
-
- **Natural‑language routing** → one tool (NDVI, LST, dNBR) or a clear refusal if the sample is incompatible with the requested tool.
|
| 28 |
-
- **EO math implemented** for all three tools (NDVI, LST, dNBR) with correct I/O (CRS/transform, nodata).
|
| 29 |
-
- **Interpretation**: concise, numeric, grounded in computed metrics (no external data).
|
| 30 |
-
- **Display‑only** for the computed product (no download in MVP).
|
| 31 |
-
|
| 32 |
-
---
|
| 33 |
-
|
| 34 |
-
## 3) Non‑Goals (MVP)
|
| 35 |
-
|
| 36 |
-
- No file uploads, no remote catalogs, no FastAPI/REST, no databases, no CLIP, no segmentation/ML.
|
| 37 |
-
- No batch processing, no vector analytics beyond tiny helpers, no cloud infra, no CI in v1.
|
| 38 |
-
- No download feature in the UI.
|
| 39 |
-
|
| 40 |
-
---
|
| 41 |
-
|
| 42 |
-
## 4) Users & Jobs
|
| 43 |
-
|
| 44 |
-
- **Demo owner / reviewer** validates an end‑to‑end **agentic** EO workflow on curated samples and reads a short explanation of outcomes.
|
| 45 |
-
|
| 46 |
-
---
|
| 47 |
-
|
| 48 |
-
## 5) UX (single page)
|
| 49 |
-
|
| 50 |
-
**Left column**
|
| 51 |
-
- **Sample dropdown** (from `samples_index.json`).
|
| 52 |
-
- **Prompt textbox** (one sentence like “analyze urban heat for this Landsat scene”).
|
| 53 |
-
- **Run** button.
|
| 54 |
-
|
| 55 |
-
**Right column**
|
| 56 |
-
- **Preview PNG** (quicklook).
|
| 57 |
-
- **Histogram PNG** (if matplotlib present).
|
| 58 |
-
- **Stats table** (metrics dictionary).
|
| 59 |
-
- **Interpretation card** (headline + bullets + caveats).
|
| 60 |
-
- *(No download button in MVP.)*
|
| 61 |
-
|
| 62 |
-
Errors: show a clear banner when tool–sample mismatch or missing files.
|
| 63 |
-
|
| 64 |
-
---
|
| 65 |
-
|
| 66 |
-
## 6) Data & Registry
|
| 67 |
-
|
| 68 |
-
All inputs are curated and registered in **`config/samples_index.json`** (single source of truth). Example items:
|
| 69 |
-
|
| 70 |
-
```json
|
| 71 |
-
[
|
| 72 |
-
{
|
| 73 |
-
"id": "s2_green",
|
| 74 |
-
"task": "NDVI",
|
| 75 |
-
"title": "Sentinel-2 — green area",
|
| 76 |
-
"paths": ["data/samples/s2_ndvi/s2_green.tif"],
|
| 77 |
-
"bands": {"red": 1, "nir": 2}
|
| 78 |
-
},
|
| 79 |
-
{
|
| 80 |
-
"id": "l8_paris_hot",
|
| 81 |
-
"task": "LST",
|
| 82 |
-
"title": "Landsat 8 — Paris (hot)",
|
| 83 |
-
"paths": ["data/samples/landsat_lst/l8_paris_hot.tif"],
|
| 84 |
-
"meta": {"emissivity": 0.97, "k1": 774.89, "k2": 1321.08}
|
| 85 |
-
},
|
| 86 |
-
{
|
| 87 |
-
"id": "s2_fire_pair_a",
|
| 88 |
-
"task": "DNBR",
|
| 89 |
-
"title": "Sentinel-2 — fire pair A",
|
| 90 |
-
"paths": [
|
| 91 |
-
"data/samples/s2_dnbr/pair_a/pre.tif",
|
| 92 |
-
"data/samples/s2_dnbr/pair_a/post.tif"
|
| 93 |
-
],
|
| 94 |
-
"bands": {"nir": 1, "swir2": 2}
|
| 95 |
-
}
|
| 96 |
-
]
|
| 97 |
-
```
|
| 98 |
-
|
| 99 |
-
Assume band indices are **1‑based**. Constants required for LST (e.g., emissivity, Planck constants) can be embedded per sample.
|
| 100 |
-
|
| 101 |
-
---
|
| 102 |
-
|
| 103 |
-
## 7) Tools & Math (to be implemented by Claude)
|
| 104 |
-
|
| 105 |
-
### 7.1 NDVI (Sentinel‑2)
|
| 106 |
-
- **Input**: single GeoTIFF with **RED** & **NIR** bands (indices from registry).
|
| 107 |
-
- **Formula**: `NDVI = (NIR - RED) / (NIR + RED + eps)` with `eps = 1e-6`; clip to `[-1, 1]`; respect NoData.
|
| 108 |
-
- **Outputs**: GeoTIFF `float32` (same CRS/transform, nodata), preview PNG (8‑bit normalized), histogram PNG (optional), stats: `min`, `max`, `mean`, `std`, `p10`, `p50`, `p90`, `%valid`.
|
| 109 |
-
|
| 110 |
-
### 7.2 LST (Landsat 8/9 TIRS)
|
| 111 |
-
- **Input**: single thermal band GeoTIFF (e.g., Band 10) plus constants from metadata.
|
| 112 |
-
- **Assumptions** (embedded; no external reads):
|
| 113 |
-
1) Radiance: `Lλ = ML * DN + AL` (or assume DN already radiance if ML/AL missing, controlled via metadata).
|
| 114 |
-
2) Brightness Temperature: `TB(K) = K2 / ln(K1 / Lλ + 1)`.
|
| 115 |
-
3) Emissivity: constant `ε` from metadata (e.g., 0.97).
|
| 116 |
-
4) LST: `LST(K) = TB / (1 + (λ * TB / ρ) * ln(ε))`, with `λ ≈ 10.895µm`, `ρ = 1.438e-2 m·K`; convert to °C for output.
|
| 117 |
-
- **Outputs**: LST GeoTIFF (`float32`, °C), preview + histogram, stats: `min`, `max`, `mean`, `std`, `p10`, `p50`, `p90`.
|
| 118 |
-
|
| 119 |
-
### 7.3 dNBR (Sentinel‑2 pre/post pair)
|
| 120 |
-
- **Inputs**: two GeoTIFFs (pre, post) with **NIR** & **SWIR2** bands.
|
| 121 |
-
- **Formulas**: `NBR = (NIR - SWIR2) / (NIR + SWIR2 + eps)`; `dNBR = NBR_post - NBR_pre`.
|
| 122 |
-
- **Severity bins** (configurable; see §8): Unburned ≤ 0.10, Low ≤ 0.27, Moderate ≤ 0.44, High ≤ 0.66, Very High ≤ 1.00.
|
| 123 |
-
- **Outputs**: dNBR GeoTIFF (`float32`), preview + histogram, stats + **class counts/percentages** per severity bin.
|
| 124 |
-
|
| 125 |
-
**Common I/O**: preserve CRS and transform; set sensible NoData; save artifacts under `outputs/<task>/<sample_id>/<timestamp>/` (internal; UI does not expose a download).
|
| 126 |
-
|
| 127 |
-
---
|
| 128 |
-
|
| 129 |
-
## 8) Thresholds for Interpretation (config file)
|
| 130 |
-
|
| 131 |
-
Thresholds **inform wording**; they don’t change math. Store in `config/heuristics.yaml`:
|
| 132 |
-
|
| 133 |
-
```yaml
|
| 134 |
-
ndvi:
|
| 135 |
-
mean_low: 0.2
|
| 136 |
-
mean_med: 0.5
|
| 137 |
-
lst:
|
| 138 |
-
hot_mean_c: 32.0
|
| 139 |
-
very_hot_p90_c: 38.0
|
| 140 |
-
dnbr:
|
| 141 |
-
bins:
|
| 142 |
-
- {label: "Unburned", max: 0.10}
|
| 143 |
-
- {label: "Low", max: 0.27}
|
| 144 |
-
- {label: "Moderate", max: 0.44}
|
| 145 |
-
- {label: "High", max: 0.66}
|
| 146 |
-
- {label: "Very High",max: 1.00}
|
| 147 |
-
```
|
| 148 |
-
|
| 149 |
-
---
|
| 150 |
-
|
| 151 |
-
## 9) Agent & LLM Orchestration
|
| 152 |
-
|
| 153 |
-
- **Router**: LLM **tool‑calling** selects **exactly one** tool or refuses with one‑sentence mismatch reasoning. Provide three LangChain tools that wrap `eo/ndvi.py::run`, `eo/lst.py::run`, `eo/dnbr.py::run`.
|
| 154 |
-
- **Interpreter**: After a tool runs, pass `{task, sample.title, metrics, extras, thresholds_excerpt}` to LLM and return validated JSON.
|
| 155 |
-
|
| 156 |
-
### 9.1 Pydantic Schemas
|
| 157 |
-
```python
|
| 158 |
-
class ToolResult(BaseModel):
|
| 159 |
-
raster_path: str
|
| 160 |
-
preview_png: str
|
| 161 |
-
histogram_png: Optional[str] = None
|
| 162 |
-
metrics: Dict[str, float]
|
| 163 |
-
extras: Dict[str, Any] = {}
|
| 164 |
-
|
| 165 |
-
class Interpretation(BaseModel):
|
| 166 |
-
headline: str
|
| 167 |
-
bullets: List[str] # include at least one numeric value per bullet
|
| 168 |
-
caveats: List[str] # 0–2 items
|
| 169 |
-
```
|
| 170 |
-
|
| 171 |
-
### 9.2 LangChain wiring
|
| 172 |
-
- Minimal **tool calling** composition (no heavy agents). Use `JsonOutputParser` for `Interpretation` parsing.
|
| 173 |
-
- The router prompt includes: user sentence, selected `sample_id` and its declared `task`, and strict tool contracts.
|
| 174 |
-
- If the chosen tool doesn’t match the sample’s declared task → **refusal** (no hidden retry).
|
| 175 |
-
|
| 176 |
-
---
|
| 177 |
-
|
| 178 |
-
## 10) Folder Structure (to generate)
|
| 179 |
-
|
| 180 |
-
```
|
| 181 |
-
agent4eo/
|
| 182 |
-
app/
|
| 183 |
-
main.py # Gradio UI: dropdown + prompt + run; render outputs
|
| 184 |
-
agent/
|
| 185 |
-
schema.py # Pydantic models
|
| 186 |
-
tools.py # LangChain tool wrappers for the 3 Python funcs
|
| 187 |
-
router.py # LLM router (tool-calling)
|
| 188 |
-
interpreter.py # LLM narrative -> Interpretation
|
| 189 |
-
prompts/
|
| 190 |
-
system_router.txt
|
| 191 |
-
system_interpret.txt
|
| 192 |
-
eo/
|
| 193 |
-
ndvi.py # math + I/O
|
| 194 |
-
lst.py # math + I/O
|
| 195 |
-
dnbr.py # math + I/O
|
| 196 |
-
viz.py # quicklook, histogram helpers
|
| 197 |
-
io.py # read/write helpers
|
| 198 |
-
config/
|
| 199 |
-
samples_index.json # curated registry
|
| 200 |
-
heuristics.yaml # thresholds for narratives
|
| 201 |
-
outputs/ # gitignored runtime artifacts
|
| 202 |
-
data/samples/... # curated small rasters
|
| 203 |
-
tests/
|
| 204 |
-
test_router_mismatch.py
|
| 205 |
-
test_ndvi_math_small.py
|
| 206 |
-
environment.yml
|
| 207 |
-
README.md
|
| 208 |
-
.gitignore
|
| 209 |
-
```
|
| 210 |
-
|
| 211 |
-
---
|
| 212 |
-
|
| 213 |
-
## 11) “For Claude Code” — Execution & Output Rules
|
| 214 |
-
|
| 215 |
-
**Why these rules**: Claude Code performs best with clear scope, explicit constraints, and **returning diffs/patches** plus runnable pointers. Use tool‑calling for structure and schemas for JSON outputs. *Do not add features or deps not listed here.*
|
| 216 |
-
|
| 217 |
-
**When generating the repo in one shot, follow these constraints:**
|
| 218 |
-
- **Dependency whitelist** (conda/`conda-forge` only): `python=3.11`, `numpy`, `gdal`, `rasterio`, `gradio`, `pydantic`, `pyyaml`, `langchain-core`, `langchain-community`, `mistralai`, `matplotlib` (optional), `pytest` (optional).
|
| 219 |
-
- Keep files **short** (< ~200 lines when possible); keep functions small.
|
| 220 |
-
- **Output only unified diffs (patches)** plus a short **README**.
|
| 221 |
-
- README must **list dependencies** and the **entry point** but **must not include conda/mamba install commands**. Environment creation is handled externally.
|
| 222 |
-
- Ensure **structured outputs** via tool‑calling & `JsonOutputParser` for the `Interpretation` schema.
|
| 223 |
-
- Implement **strict mismatch handling**: if sample.task ≠ intended tool, return a one‑sentence refusal; don’t run anything.
|
| 224 |
-
- All outputs saved under `outputs/<task>/<sample_id>/<timestamp>/` (internal). UI is **display‑only** (no download).
|
| 225 |
-
|
| 226 |
-
**Run (README excerpt):**
|
| 227 |
-
- Ensure required dependencies (see §12) exist in the environment (managed externally).
|
| 228 |
-
- Set `MISTRAL_API_KEY` in your shell.
|
| 229 |
-
- Start the app with: `python -m app.main`.
|
| 230 |
-
|
| 231 |
-
---
|
| 232 |
-
|
| 233 |
-
## 12) Dependencies (conda, conda‑forge)
|
| 234 |
-
|
| 235 |
-
- EO: `numpy`, `gdal`, `rasterio`, `matplotlib` (optional)
|
| 236 |
-
- App/Agent: `gradio`, `pydantic`, `pyyaml`
|
| 237 |
-
- LLM: `langchain-core`, `langchain-community`, `mistralai`
|
| 238 |
-
- Python: `3.11`
|
| 239 |
-
- Tests (optional): `pytest`
|
| 240 |
-
|
| 241 |
-
---
|
| 242 |
-
|
| 243 |
-
## 13) Performance Targets
|
| 244 |
-
|
| 245 |
-
- App start < **3s** on a typical laptop.
|
| 246 |
-
- Each tool run (on ~50–100 MB samples) < **2–3s** to compute + render preview.
|
| 247 |
-
- Memory footprint < **400 MB** during processing.
|
| 248 |
-
|
| 249 |
-
---
|
| 250 |
-
|
| 251 |
-
## 14) Acceptance Criteria
|
| 252 |
-
|
| 253 |
-
1) **Routing correctness**
|
| 254 |
-
- NDVI sample + “show vegetation condition” → NDVI tool called.
|
| 255 |
-
- LST sample + “analyze urban heat” → LST tool called.
|
| 256 |
-
- dNBR pair + “burn severity map” → dNBR tool called.
|
| 257 |
-
|
| 258 |
-
2) **Mismatch handling**
|
| 259 |
-
- NDVI sample + “burn severity” prompt → **refusal** explaining that dNBR needs a pre/post pair.
|
| 260 |
-
|
| 261 |
-
3) **Artifacts & UI**
|
| 262 |
-
- Each successful run produces artifacts under `outputs/...` and renders **preview**, **histogram** (if available), **stats**, and **interpretation** in the UI (display‑only).
|
| 263 |
-
|
| 264 |
-
4) **Interpretation**
|
| 265 |
-
- LLM returns valid `Interpretation` JSON; UI displays headline + bullets + caveats.
|
| 266 |
-
|
| 267 |
-
5) **I/O fidelity**
|
| 268 |
-
- Output GeoTIFF preserves CRS & transform; nodata handled consistently.
|
| 269 |
-
|
| 270 |
-
---
|
| 271 |
-
|
| 272 |
-
## 15) Risks & Mitigations
|
| 273 |
-
|
| 274 |
-
- **GDAL/rasterio installs** → use `conda-forge` only; pin Python=3.11; keep README dependency list exact.
|
| 275 |
-
- **LST constants ambiguity** → store needed constants per sample in `samples_index.json`; document assumptions in code.
|
| 276 |
-
- **Router hallucination** → precise tool descriptions; enforce sample.task check; refusal on mismatch.
|
| 277 |
-
- **Over‑verbose LLM outputs** → enforce JSON schema; concise style prompts.
|
| 278 |
-
|
| 279 |
-
---
|
| 280 |
-
|
| 281 |
-
## 16) References
|
| 282 |
-
|
| 283 |
-
- Internal EO formulas and thresholds as specified above.
|
| 284 |
-
- LangChain tool‑calling patterns and JSON parsing best practices.
|
| 285 |
-
- Mistral API usage for function/tool calling.
|
| 286 |
-
|
| 287 |
-
---
|
| 288 |
-
|
| 289 |
-
*End of PRD.*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
environment.yml
DELETED
|
@@ -1,17 +0,0 @@
|
|
| 1 |
-
name: agent4eo
|
| 2 |
-
channels:
|
| 3 |
-
- conda-forge
|
| 4 |
-
dependencies:
|
| 5 |
-
- python=3.11
|
| 6 |
-
- numpy
|
| 7 |
-
- gdal
|
| 8 |
-
- rasterio
|
| 9 |
-
- gradio
|
| 10 |
-
- pydantic
|
| 11 |
-
- pyyaml
|
| 12 |
-
- langchain-core
|
| 13 |
-
- langchain-community
|
| 14 |
-
- mistralai
|
| 15 |
-
- matplotlib
|
| 16 |
-
- pytest
|
| 17 |
-
- tenacity
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eo/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
"""Earth Observation processing tools."""
|
|
|
|
|
|