farm-layout-model / README.md
spacedout-bits's picture
Update Gradio sdk_version to 6.14.0 to fix static asset 404s
d8aa682
---
title: Farm Drip Irrigation Designer
emoji: πŸ’§
colorFrom: green
colorTo: blue
sdk: gradio
sdk_version: 6.14.0
app_file: app.py
pinned: false
short_description: 'Design drip irrigation layouts with deterministic geometry'
---
# Farm Drip Irrigation Designer
## Overview
A conversational tool for designing drip irrigation systems for farms. **Phase 1** focuses on the geometry engine: deterministic pipe layout generation using shapely and pyproj.
Key features:
- Parse farm boundaries (geofences) from text input
- Generate drip irrigation layouts (main lines + parallel laterals)
- Calculate material requirements and cost estimates
- Support for multiple crop types with optimized spacing parameters
## Architecture
### Phase 1: Geometry Engine (Current)
**Core modules:**
- `drip_engine.py` – Pure geometry functions (no ML)
- Geofence parsing and validation
- UTM coordinate conversion (via pyproj)
- Drip layout generation (main + laterals with clipping)
- Bill of materials (BOM) estimation
- Human-readable design summaries
- `app.py` – Gradio UI for testing
- Input: farm boundary (geofence), crop type, design parameters
- Output: visualized layout, BOM (JSON), design summary
- Example geofences for quick testing
- `test_drip_engine.py` – Comprehensive test suite
- 26 unit tests covering parsing, geometry, BOM, edge cases
- All tests passing βœ…
### Phase 2: LLM Integration (Planned)
- `llm_handler.py` – Conversational interface
- LLM as drip irrigation specialist
- Guides users through design decisions
- Calls geometry engine to update designs
- Answers domain-specific questions
### Phase 3: Deployment & Polish
- Error handling and input validation
- HF Spaces deployment with live inference
- Documentation and user workflows
## Getting Started
### Install Dependencies
```bash
pip install -r requirements.txt
```
### Run Tests
```bash
python3 -m pytest test_drip_engine.py -v
```
Expected: 26/26 tests passing
### Run the UI
```bash
python3 app.py
```
Then open `http://localhost:7860` in your browser.
### Example: 1-hectare tomato field
1. Default geofence: `0,0;100,0;100,100;0,100` (100m Γ— 100m = 1 ha)
2. Select crop: "tomato" (0.5m lateral spacing)
3. Headland: 1.0 m
4. Click "Generate Design"
**Output:**
- Visual layout (green boundary, red main line, blue laterals)
- BOM with pipe lengths and costs
- Design summary with emitter count and flow rate
## Design Decisions
### Why Geometry, Not ML?
Drip design is **deterministic**. Given a field shape, crop type, and spacing preferences, the layout is fully determined. ML would be:
- Slower
- Harder to debug
- Less accurate
- Overkill for a well-defined problem
The geometry engine is the source of truth. Future ML (e.g., SAM for boundary extraction) would feed *into* this engine, not replace it.
### Why LLM in Phase 2?
Users think in **intent** ("I want to grow tomatoes on 3 hectares, budget $500"), not **parameters** ("0.5m lateral spacing, 100m mains"). The LLM:
- Translates intent β†’ geometry parameters
- Explains design tradeoffs
- Answers agronomic questions
- Iteratively refines based on feedback
### Coordinate Systems
- **Input**: Pixel coords (from map screenshots) or lat/lon (GPS)
- **Internal**: UTM (meters) – accurate area/length calculations
- **Output**: Geometry objects (shapely) + JSON specs
## Extensibility
### Add a New Crop
Edit `drip_engine.py`'s `CROP_DEFAULTS`:
```python
CROP_DEFAULTS = {
"my_crop": {
"lateral_spacing_m": 0.75,
"emitter_spacing_m": 0.35,
"emitter_discharge_lph": 5
},
# ...
}
```
### Adjust Cost Estimates
Edit `PIPE_COSTS` in `drip_engine.py`:
```python
PIPE_COSTS = {
"main_line_16mm": 0.60, # Update $/meter
# ...
}
```
### Support Lat/Lon Input
Use `latlon_to_utm()` instead of treating pixel coords as UTM:
```python
polygon_latlon = parse_geofence_to_polygon(user_input)
polygon_utm = latlon_to_utm(polygon_latlon) # Auto-selects UTM zone
design = generate_drip_layout(polygon_utm, ...)
```
## Testing
Test coverage includes:
- βœ… Geofence parsing (valid, invalid, edge cases)
- βœ… Polygon validation (self-intersecting, too small, etc.)
- βœ… Area calculation (hectares from UTM)
- βœ… Layout generation (rectangular, irregular, triangular fields)
- βœ… Headland buffering
- βœ… Crop-specific spacing
- βœ… BOM cost breakdown
- βœ… Edge cases (tiny fields, long strips, etc.)
## REST API
In addition to the Gradio UI, the Space exposes a one-shot REST endpoint that accepts a flat `farm / plots / water_sources` payload β€” no Gradio `/call/` two-step required.
### Endpoints
- `GET /api/v1/health` β†’ `{ "status": "ok", "schema_version": "v1" }`
- `POST /api/v1/design` β†’ returns `{ farm_name, design_summary, bom, zone_details, warnings, geojson }`
### Request schema
```json
{
"farm": {
"name": "DakshFarm",
"location": { "address": "...", "latitude": 20.5937, "longitude": 78.9629 },
"size": { "value": 2.5, "unit": "acres" },
"crop_name": "Wheat"
},
"plots": [
{
"plot_id": "plot_1",
"name": "Plot 1",
"area_sq_m": 12450.0,
"centroid": { "latitude": 20.5938, "longitude": 78.9627 },
"boundaries": [
{ "latitude": 20.5937, "longitude": 78.9626 },
{ "latitude": 20.5939, "longitude": 78.9626 },
{ "latitude": 20.5939, "longitude": 78.9628 },
{ "latitude": 20.5937, "longitude": 78.9628 }
]
}
],
"water_sources": [
{
"water_source_id": "ws_1",
"type": "Motor",
"name": "Motor-1",
"location": { "latitude": 20.5938, "longitude": 78.9627 },
"plot_id": "plot_1"
}
],
"pump_hp": 5.0,
"headland_buffer_m": 1.0
}
```
### `curl` example
```bash
curl -X POST 'https://uniphy-farm-layout-model.hf.space/api/v1/design' \
-H 'Content-Type: application/json' \
-d @samples/rest_input_example.json
```
### Notes / current limits
- Multiple `water_sources` are accepted, but only the first is used as the pump (returned in `warnings`).
- All plots inherit `farm.crop_name` as their crop. Per-plot crop overrides aren't wired up yet.
- If plot polygons don't overlap, the engine sees the convex hull of their union as the farm boundary.
## API Reference
### `parse_geofence_to_polygon(geofence_input: str) β†’ Polygon`
Parse text like `"0,0;100,0;100,100;0,100"` into a Shapely Polygon.
### `generate_drip_layout(polygon_utm, crop, headland_buffer_m, ...) β†’ Dict`
Generate layout. Returns dict with:
- `farm_area_ha`: Area in hectares
- `main_line`: LineString
- `laterals`: List of LineStrings
- `total_drip_tape_m`: Total lateral length
- `emitter_count`: Estimated emitters
- `design_params`: Spacing, discharge, etc.
### `estimate_bom(design, unit="usd") β†’ Dict`
Bill of materials with quantities and costs.
### `design_summary(design, bom) β†’ str`
Human-readable summary for the user.
## Next Steps
1. **Deploy Phase 1 to HF Spaces** – test with real users
2. **Build Phase 2** – add LLM conversational layer
3. **Integrate boundary extraction** – use SAM or segmentation model for auto-boundary from aerial imagery (optional)
4. **Real-world validation** – test designs with actual irrigation installers
## References
- [Shapely geometry library](https://shapely.readthedocs.io/)
- [Pyproj coordinate transformations](https://pyproj4.github.io/pyproj/stable/)
- [Web Mercator projection](https://en.wikipedia.org/wiki/Web_Mercator_projection)
- [Drip irrigation design standards](https://www.fao.org/3/s2022e/s2022e00.htm)
## License
MIT (for now – update as needed)