Skip to content

Interventions API

Agricultural intervention definitions and their variable configurations. Interventions represent specific agricultural strategies (Organic Farming, Micro-Irrigation, etc.) that can be evaluated for feasibility across blocks.

Interventions are auto-detected from the Cluster column in the DSS metadata CSV (DSS_input2.csv). Each intervention has a set of associated variables with predefined acceptable ranges, weights, and preference directions.


How Interventions Work

  1. Definition - Each intervention groups related variables that determine its feasibility
  2. Configuration - Each variable has a range (min/max), weight (importance), and preference (higher/lower/moderate)
  3. Scoring - When a user selects an intervention, the system applies its variable config as filters to the feasibility calculation
  4. Customization - Users can override the default config in the UI's Configure modal
Intervention "Organic Farming"
  └─ Variable AD (Agricultural Diversity): range 20-80, weight 1.0, prefer higher
  └─ Variable WA (Water Availability): range 30-70, weight 0.8, prefer moderate
  └─ Variable CF (Crop Finance): range 10-60, weight 0.6, prefer higher

List All Interventions

Returns all available agricultural interventions with their names and descriptions.

GET /api/interventions

Response

{
  "interventions": [
    {
      "key": "Organic Farming",
      "name": "Organic Farming",
      "description": "Organic Farming focuses on sustainable agricultural practices tailored to local conditions.",
      "parent": null,
      "children": []
    },
    {
      "key": "Livestock",
      "name": "Livestock",
      "description": "Livestock focuses on sustainable agricultural practices tailored to local conditions.",
      "parent": null,
      "children": ["Goatery", "Piggery", "Dairy"]
    },
    {
      "key": "Goatery",
      "name": "Goatery",
      "description": "Goatery focuses on sustainable agricultural practices tailored to local conditions.",
      "parent": "Livestock",
      "children": []
    }
  ]
}
Field Type Description
interventions[].key string Unique identifier (same as name)
interventions[].name string Display name
interventions[].description string Brief description
interventions[].parent string | null Parent intervention name for a sub-category, else null
interventions[].children string[] Sub-category names grouped under this intervention (parents only)

Sub-categories (sub-filter)

Interventions can form a one-level hierarchy via an optional parent column in the configuration sheet. For example, Livestock is a parent with children Goatery, Piggery, Dairy. Selecting a parent shows its combined config; selecting a child shows that sub-category's own variables and feasibility. When the parent column is absent, all interventions are top-level (parent: null).

Example

curl https://leaf-asrlm.in/api/interventions
import requests

r = requests.get("https://leaf-asrlm.in/api/interventions")
for i in r.json()["interventions"]:
    print(f"{i['name']}: {i['description']}")
const r = await fetch('/api/interventions');
const data = await r.json();

// Populate dropdown
data.interventions.forEach(i => {
  const option = document.createElement('option');
  option.value = i.key;
  option.textContent = i.name;
  interventionSelect.appendChild(option);
});

Export Livestock Sub-filter CSV

Downloads the Livestock sub-category configuration currently in effect — one row per (sub-type, variable) for Dairy, Goatery, Piggery, Backyard_Poultry, Duckery, Fishery_Activity, with the same columns as the Intervention & Variable Config sheet plus the parent column (always Livestock).

GET /api/livestock-subfilter.csv

Response

CSV file (livestock_subfilter.csv):

Cluster,I_variable,range_min,range_max,Preference,I_weight,I_label,I_description,group,subgroup,variable,Weight,label,Description,parent
Dairy,BF,0.33,0.987,higher,1,Cattle density (per 100 ha),Existing cattle base,,,,,,,Livestock
Dairy,BG,0.33,0.969,higher,1,Buffalo density (per 100 ha),Existing buffalo base,,,,,,,Livestock
Goatery,BI,0.2,0.9,higher,1,Goat density (per 100 ha),Existing goat base,,,,,,,Livestock

Source resolution

Mirrors the runtime overlay (LEAF-51):

  • When the dss_input Google Sheet declares all six sub-types as parent: Livestock children, the sheet's rows are returned (the sheet owns the config).
  • Otherwise the app's built-in defaults are returned.

Edit flow

  1. GET /api/livestock-subfilter.csv (or the Download Sub-filter CSV button on the /update page) → download what the app is using right now.
  2. Edit ranges / weights / labels. Keep Cluster = sub-type name and parent = Livestock, and keep all six commodities.
  3. Upload the edited file from the /update page (Upload Sub-filter CSV, admin only) or POST /api/livestock-subfilter — see below. It is validated and applied immediately.

Sheet still wins

If the dss_input Google Sheet itself declares all six sub-types as parent: Livestock children, the sheet owns the configuration and the uploaded CSV is ignored. The upload drives the built-in/overlay path used when the sheet does not.

Example

curl -O https://leaf-asrlm.in/api/livestock-subfilter.csv
import pandas as pd
df = pd.read_csv("https://leaf-asrlm.in/api/livestock-subfilter.csv")
print(df.groupby("Cluster").size())  # variables per sub-type

Upload Livestock Sub-filter CSV

Uploads an edited Livestock sub-filter CSV and applies it immediately — no redeploy. This makes the six Livestock commodities fully data-driven from the /update page (download → edit → upload). The uploaded file is persisted as the app's overlay source and the dss_input cache is refreshed so the new ranges/weights/labels take effect on the next request.

Admin only — requires the admin guard (?admin=1 query param or X-Admin: 1 header).

POST /api/livestock-subfilter

Request

multipart/form-data with a single field:

Field Type Required Description
file file Yes The edited Livestock sub-filter CSV (the file produced by GET /api/livestock-subfilter.csv).

Validation

The upload is rejected with 400 and a plain-language message unless all of the following hold:

  • Required columns present: Cluster, I_variable, range_min, range_max, parent.
  • Every data row has parent = Livestock (case-insensitive).
  • All six commodities are present, each with at least one variable row: Dairy, Goatery, Piggery, Backyard_Poultry, Duckery, Fishery_Activity.
  • range_min and range_max are numeric, and range_minrange_max on every row.

Response

{
  "ok": true,
  "rows": 57,
  "message": "Livestock sub-filter updated. The new configuration is now in effect."
}
Field Type Description
ok boolean true when persisted and applied
rows integer Number of data rows persisted
message string Human-readable confirmation

Errors

Code Description
400 No file provided, or the CSV failed validation (message explains which rule)
403 Caller is not an admin
500 Server error while saving the configuration

Example

curl -X POST "https://leaf-asrlm.in/api/livestock-subfilter?admin=1" \
  -F "file=@livestock_subfilter.csv"
import requests

with open("livestock_subfilter.csv", "rb") as f:
    r = requests.post(
        "https://leaf-asrlm.in/api/livestock-subfilter",
        params={"admin": "1"},
        files={"file": f},
    )
print(r.status_code, r.json())
const fd = new FormData();
fd.append('file', fileInput.files[0]);

const r = await fetch('/api/livestock-subfilter?admin=1', {
  method: 'POST',
  headers: { 'X-Admin': '1' },
  body: fd,
});
const data = await r.json();
if (data.ok) console.log(`Applied ${data.rows} rows`);

Get Intervention Configuration

Returns the variable filters and weights configured for a specific intervention. This is the core configuration that drives feasibility analysis - it defines which variables matter for this intervention and what ranges are acceptable.

GET /api/intervention/{name}/config

Parameters

Parameter In Type Required Description
name path string Yes Intervention key name (e.g. "Organic Farming"). Must be URL-encoded if it contains spaces.

Response

{
  "intervention": "Organic Farming",
  "name": "Organic Farming",
  "description": "Organic Farming focuses on sustainable agricultural practices tailored to local conditions.",
  "variables": [
    {
      "field": "AD",
      "label": "Agricultural Diversity",
      "description": "Percentage of agricultural land diversity",
      "group": "Land & Agriculture",
      "preference": "higher",
      "range_min": 20,
      "range_max": 80,
      "weight": 1.0,
      "data_min": 0.0,
      "data_max": 95.5,
      "data_mean": 42.3
    },
    {
      "field": "WA",
      "label": "Water Availability",
      "description": "Water availability index",
      "group": "Water Resources",
      "preference": "moderate",
      "range_min": 30,
      "range_max": 70,
      "weight": 0.8,
      "data_min": 5.0,
      "data_max": 88.0,
      "data_mean": 35.7
    }
  ]
}
Field Type Description
intervention string Intervention key
name string Display name
description string Intervention description
variables array Variable configurations for this intervention
variables[].field string Column name in the shapefile
variables[].label string Human-readable variable name
variables[].description string What this variable measures
variables[].group string Category group
variables[].preference string Preferred direction: "higher", "lower", or "moderate"
variables[].range_min number Minimum acceptable value
variables[].range_max number Maximum acceptable value
variables[].weight number Importance weight (0-1)
variables[].data_min number Actual minimum across all blocks
variables[].data_max number Actual maximum across all blocks
variables[].data_mean number Actual mean across all blocks

Errors

Code Description
404 Intervention not found

Example

curl "https://leaf-asrlm.in/api/intervention/Organic%20Farming/config"
import requests

name = "Organic Farming"
r = requests.get(f"https://leaf-asrlm.in/api/intervention/{name}/config")
config = r.json()

print(f"Intervention: {config['name']}")
print(f"Variables: {len(config['variables'])}")
for v in config['variables']:
    print(f"  {v['label']} ({v['field']}): {v['range_min']}-{v['range_max']} "
          f"(weight {v['weight']}, prefer {v['preference']})")
const name = encodeURIComponent('Organic Farming');
const r = await fetch(`/api/intervention/${name}/config`);
const config = await r.json();

config.variables.forEach(v => {
  console.log(`${v.label}: ${v.range_min}-${v.range_max} (w=${v.weight})`);
});

Using with Feasibility

The intervention config defines the default filters used by the feasibility calculation. When you POST to /api/calculate-feasibility with just {"intervention": "Organic Farming"}, the system fetches this config and uses its variables as filters. You can override these by passing custom filters in the POST body.

Data Range vs Filter Range

data_min/data_max are the actual min/max across all blocks. range_min/range_max are the acceptable thresholds for feasibility scoring. Blocks with values inside the range score positively; blocks outside score zero for that variable.