agrosense / README.md
johnpitteera's picture
Upload folder using huggingface_hub
d27b187 verified
|
Raw
History Blame Contribute Delete
40.1 kB
---
title: AgroSense
emoji: 🌱
colorFrom: green
colorTo: yellow
sdk: docker
app_port: 7860
pinned: false
short_description: Offline-first AI farming advisor for India
---
# 🌱 AgroSense β€” RAG-Based Agriculture Farming Advisor
A working implementation of the **AgroSense** concept from the project report: a
Retrieval-Augmented Generation (RAG) advisor that answers farmer questions with
**grounded, cited** guidance drawn from an agriculture knowledge base.
This is the **Phase 1 MVP** (text interface, offline) β€” built as a full stack:
```
Knowledge Base (JSON) -> Embeddings -> Vector Store -> Retrieve + Re-rank -> Grounded Generation (cited)
|
Modern Web App (SPA) / Streamlit UI / CLI <---- FastAPI <---- RAGEngine
```
## πŸ–₯️ Modern web app
A responsive single-page dashboard (no build step β€” modern HTML/CSS/vanilla JS in
[web/](web/)) is **served by FastAPI itself**. Start the API and open it:
```powershell
uvicorn api.main:app --reload # then open:
# http://127.0.0.1:8000/ui/ (the web app)
# http://127.0.0.1:8000/docs (API docs)
```
It covers every feature via the API: the date/calendar/IST header, news + commodities
tickers, the advisor chat with a **speaking avatar** ("AgroBot" β€” an animated SVG
mascot that reads answers aloud via the browser's Web Speech API, keyless and
multilingual, with an Auto-speak toggle), a **Location intel** dashboard (weather Β· satellite Β· NDVI Β·
environment Β· sky Β· hazards Β· advisories), market prices, and the **Plant clinic** β€”
AI image diagnosis + telemedicine that escalates to a **live verified plant doctor**
(expert routing, video room, chat) in one tab.
There is also a polished **marketing landing page** (the campaign destination) at
**`/landing`** ([web/landing/index.html](web/landing/index.html)) β€” hero, features,
how-it-works, audience segments, CTAs into the app, and the downloadable campaign kit.
A headless render test lives at [web/smoke.mjs](web/smoke.mjs) (`node web/smoke.mjs`,
needs `npm i jsdom`). The Streamlit UI (`streamlit run ui/app.py`) and CLI remain as
alternatives.
### πŸ“˜ Documentation & marketing kit (Word + PDF, downloadable)
A full set of documents is provided in **both Word and PDF**, with download links in
the web app header. They live in [docs/](docs/):
| Document | What it covers |
| --- | --- |
| **User Manual** | End-user guide to every feature/tab |
| **Technical Guide** | Architecture, modules, API, config, extending, deployment, security |
| **Standard Operating Procedure (SOP)** | Operational runbook: start/stop, monitoring, KB + doctor admin, incident response, backup/recovery |
| **Go-to-Market & Monetization Plan (India)** | Freemium tiers, pricing, monetization streams, 3-year financial projection, unit economics, GTM strategy |
| **Instagram Campaign** | Reels/storyboards, voiceover + audio direction, captions, hashtags |
| **Facebook Campaign** | Page, Groups, Meta Ads + Lead Ads, ad copy |
| **LinkedIn (B2B) Campaign** | FPOs, agri-input partners, investors, enterprise/API |
| **30-Day Content Calendar** | Post-launch monthly plan with recurring series |
Served at `GET /downloads/{user-manual|technical-guide|sop|gtm-plan|instagram-campaign|`
`facebook-campaign|linkedin-campaign|content-calendar}.{pdf|docx}`. All share a
renderer ([scripts/docgen.py](scripts/docgen.py)) so the two formats never drift.
**Regenerate everything with one command:**
```powershell
pip install python-docx fpdf2
python scripts/build_docs.py
```
### βš™οΈ Admin β€” configure the knowledge base
The web app has an **Admin** tab to add / edit / delete knowledge-base entries. Saving
persists to [data/knowledge_base.json](data/knowledge_base.json) and **rebuilds the
live vector index**, so new guidance is retrievable immediately. Admin endpoints are
token-gated (`X-Admin-Token` header):
```
GET /admin/kb Β· POST /admin/kb Β· PUT /admin/kb/{id} Β· DELETE /admin/kb/{id}
```
Set the token with `AGROSENSE_ADMIN_TOKEN` (defaults to `admin` for the local POC β€”
**change it** for any shared deployment). Logic lives in
[agrosense/kb_admin.py](agrosense/kb_admin.py); validation requires at least `crop`
and `source`.
### Live local weather (optional, no API key)
Provide a **location** and AgroSense attaches a real-time forecast + farming
advisory from **[Open-Meteo](https://open-meteo.com/)** (free, **no API key**),
implementing the report's Data Layer "dynamic (weather) data" source:
```powershell
python cli.py --location Belagavi "I grow cotton on black soil β€” fertilizer and pest steps?"
```
The advisory is computed strictly from the forecast numbers (e.g. *"rain likely on
2026-05-30 β€” postpone foliar sprays and nitrogen top-dressing to avoid wash-off"*),
so it stays as trustworthy as the KB-grounded advice. If there's no internet (or the
place can't be resolved), weather is silently skipped and the KB answer is unaffected.
### Satellite monitoring (optional, no API key)
Provide a location and AgroSense pulls **real satellite monitoring** from two free,
keyless NASA sources:
- **NASA GIBS** β€” MODIS **true-color** and **NDVI** (vegetation greenness) imagery
for your area's bounding box, plus a one-click NASA Worldview link.
- **NASA POWER** β€” satellite-derived **agroclimate** (solar radiation, temperature,
rainfall) for the point, with number-grounded notes (e.g. *"ample solar radiation
β€” good for growth"*, *"very little rainfall β€” check soil moisture"*).
```powershell
python cli.py --location Belagavi --satellite "How is my paddy field doing?"
```
In the UI, set a location and tick **πŸ›°οΈ Show satellite monitoring** to see the
imagery and agroclimate panel.
### Field-level numeric NDVI (optional, Google Earth Engine)
For a true **per-field Sentinel-2 (~10 m) NDVI time series** β€” latest value, mean,
trend, and a health status (`healthy/dense` Β· `moderate` Β· `sparse/stressed`) β€”
AgroSense integrates **Google Earth Engine**. It is fully optional and **credential-
gated**: with no credentials the app silently uses MODIS NDVI imagery + POWER
agroclimate instead (see [agrosense/ndvi.py](agrosense/ndvi.py)).
**Enable it:**
```powershell
pip install earthengine-api
# Option A β€” user / default credentials (after a one-time browser auth):
earthengine authenticate
$env:AGROSENSE_EE_PROJECT = "your-gcp-project-id"
# Option B β€” service account (for servers / CI, no browser):
$env:AGROSENSE_EE_SERVICE_ACCOUNT = "agro@your-project.iam.gserviceaccount.com"
$env:AGROSENSE_EE_KEY_FILE = "C:\path\to\service-account-key.json"
$env:AGROSENSE_EE_PROJECT = "your-gcp-project-id"
```
Then any satellite request (UI checkbox, `--satellite`, or `GET /satellite`) adds a
`numeric_ndvi` block with the time series, trend, and number-grounded notes (e.g.
*"NDVI is trending down β€” investigate for stress, senescence, or recent harvest"*).
Tunables: `AGROSENSE_NDVI_DAYS` (60), `AGROSENSE_NDVI_BUFFER_M` (100 m field radius),
`AGROSENSE_NDVI_MAX_CLOUD` (40%). The architecture is provider-agnostic β€” swap in
Sentinel Hub by adding a sibling provider in [agrosense/ndvi.py](agrosense/ndvi.py).
Cloud handling is two-layer: scenes are filtered by `CLOUDY_PIXEL_PERCENTAGE`, **and**
clouds/shadows/cirrus/snow are masked **per pixel** via the Sentinel-2 SCL band
(`build_scl_mask`), so cloud over the field can't skew the field-mean NDVI.
### Location environment profile
Display a full environment readout for a place or lat/lon β€” **keyless** (Open-Meteo):
| Field | Source | Notes |
| --- | --- | --- |
| Longitude, Latitude | geocoding | |
| Altitude (sea level) | geocoding / elevation API | metres |
| Local population | geocoding | of the resolved place |
| Humidity | forecast `current` | % |
| Sunlight | forecast | sunshine hours/day, UV-index max, live solar W/mΒ² |
| Wind speed & direction | forecast `current` | km/h + 16-point compass |
| Air quality | Air Quality API | US/EU AQI, PM2.5, PM10, ozone + category |
| Pollen | Air Quality API | **Europe-only (CAMS)** β€” shows "not available for this region" elsewhere |
| Ground water level | CGWB / data.gov.in (keyed) | real nearest-well water-table depth when `AGROSENSE_GROUNDWATER_RESOURCE` + `AGROSENSE_DATAGOV_API_KEY` are set ([agrosense/groundwater.py](agrosense/groundwater.py)); otherwise a labelled **soil-moisture proxy** (3–9 cm) |
```powershell
python cli.py --location Belagavi --environment "..."
```
Endpoint: `GET /environment?location=…` or `?latitude=…&longitude=…`. UI: tick
**🌍 Show location environment**. See [agrosense/environment.py](agrosense/environment.py).
**Real ground-water level (optional):** set a CGWB "depth to water level" resource id
and a data.gov.in key to replace the proxy with an actual nearest-observation-well
water-table depth:
```powershell
$env:AGROSENSE_DATAGOV_API_KEY = "your-data.gov.in-key"
$env:AGROSENSE_GROUNDWATER_RESOURCE = "<cgwb-resource-id>"
$env:AGROSENSE_GROUNDWATER_STATE = "Karnataka" # optional server-side filter
```
The nearest-well geometry (haversine + parsing) is unit-tested; the live fetch is
mock-tested. **Caveat:** CGWB data is station-based and ~quarterly (not real-time),
and resource field names vary β€” confirm your resource's schema (see
[agrosense/groundwater.py](agrosense/groundwater.py)).
### Natural-hazard events & active fires (NASA EONET + FIRMS)
Shows natural-hazard events and active fires near the location:
- **NASA EONET** β€” **keyless** open natural events (wildfires, severe storms, floods,
drought, dust/haze…) filtered to a radius of the farm and sorted by distance.
- **NASA FIRMS** β€” active fire / thermal anomalies (VIIRS/MODIS); needs a **free
map-key** (`AGROSENSE_FIRMS_MAP_KEY`) β€” shows "set key to enable" otherwise.
UI: tick **⚠️ Show hazards & fires**. `GET /hazards?location=…` (or lat/lon).
See [agrosense/hazards.py](agrosense/hazards.py).
### Plant-disease, plant-ID & pest vision
Upload a leaf/plant/insect photo (UI: **🌿 Plant image diagnosis**, or
`POST /vision/classify?task=all`) to get three classifications β€” **disease/health**,
**plant ID**, and **pest ID**:
- With trained models configured (`AGROSENSE_VISION_DISEASE_MODEL` / `_PLANT_MODEL` /
`_PEST_MODEL`) and TensorFlow installed, real CNN inference runs.
- Without them, an **honest Pillow colour heuristic** gives a leaf-health indication
(clearly labelled "not a diagnosis"); plant-ID and pest-ID report that a trained
model is required. See [agrosense/vision.py](agrosense/vision.py).
**Train the models** (needs TensorFlow + datasets β€” run outside this sandbox) with
[scripts/train_plant_models.py](scripts/train_plant_models.py):
- **disease** β†’ PlantVillage (~54k images, 38 classes)
- **plant** β†’ any per-class leaf/plant folder dataset (Flavia, Oxford-102…)
- **pest** β†’ **IP102** (~75k images, 102 crop-pest classes) or the Kaggle
"Agricultural Pests Image Dataset" (12 classes)
Point the env vars at the resulting `.keras` + labels files to activate real inference.
> Note: this Python 3.14 POC has Pillow + numpy but **not** TensorFlow/ONNX, so only
> the heuristic path runs here; the model backend activates wherever TF is available.
### Plant telemedicine (diagnosis β†’ prescription)
A clinician-style consult that fuses the image diagnosis (disease/pest vision) +
symptom intake + the KB's treatment fields + weather-aware timing into a structured
**diagnosis β†’ health assessment β†’ prescription β†’ follow-up**:
- Intake: crop, free-text symptoms, optional leaf photo, location.
- Assessment: diagnosis (from image and/or symptom keywords), health status, severity.
- **Diagnosis-driven prescription**: a recognized disease/pest **class** β€” from the
vision model's predicted label (e.g. PlantVillage `Tomato___Late_blight`) or from
symptom text that names the condition β€” is mapped to a **targeted IPM prescription**
via [agrosense/ipm.py](agrosense/ipm.py) + [data/ipm_prescriptions.json](data/ipm_prescriptions.json)
(e.g. *"Late blight β†’ spray Mancozeb 0.25%…"*). This specific treatment is listed
first, then the crop's KB-grounded steps follow.
- **Prescription**: treatment + nutrition + cultural/IPM steps composed **only** from
the IPM lookup and retrieved KB fields (dosages verbatim, every line cited) β€” never invented.
- Weather-aware timing (e.g. "rain likely β†’ postpone foliar sprays") + a clear
**safety disclaimer** (decision support, not a substitute for an expert).
UI: sidebar **🩺 Plant telemedicine** (crop + symptoms + the uploaded photo) β†’
consultation card. `POST /telemedicine` (multipart: crop/symptoms/location + optional
image). See [agrosense/telemedicine.py](agrosense/telemedicine.py).
### Farmers' digital clubs
**Location-wise** and **commodity-wise** farmer communities (πŸ‘₯ Clubs tab). Browse/filter
clubs by location or commodity, **create** a club, **join**, post to a **discussion feed**
and **share information/links**, and start a **live video meeting** (Jitsi room per club,
keyless). Each club has members, a feed, and its own meeting room. Seeded with starter
clubs (Karnataka/Maharashtra; Tomato/Cotton/Coffee/Paddy). API: `GET/POST /clubs`,
`GET /clubs/{id}`, `POST /clubs/{id}/join`, `POST /clubs/{id}/post`. See
[agrosense/clubs.py](agrosense/clubs.py) (persisted to `data/clubs.json`).
### Live agri-doctor consultation
Escalate from the AI consult to a **human expert**: a consultation request is **routed
to a matching available expert** (pest β†’ entomologist, disease β†’ pathologist, etc.,
honoring language), attaches the **AI telemedicine consult as context**, and opens a
**live video room** (Jitsi, keyless) plus an in-app **chat thread**.
UI: sidebar **πŸ‘¨β€βš•οΈ Live agri-doctor** (name + channel + language) β†’ session card with
the assigned expert, a *Join live video room* button, and chat. API: `GET /experts`,
`POST /consult/request`, `GET /consult/{id}`, `POST /consult/{id}/message`. See
[agrosense/consultation.py](agrosense/consultation.py) + [data/agri_experts.json](data/agri_experts.json).
**Onboarding & verification:** anyone can **apply to become a plant doctor**
(`POST /doctors/apply`, status `pending`); an **admin verifies** them
(`POST /admin/doctors/{id}/verify`, token-gated) β€” and only **verified** doctors enter
the consultation directory (`GET /experts`) and can be routed live consults.
Applications require name, specialization, region, contact, languages, credentials,
and a format-checked **ICAR / registration number**; routing tags are derived from the
specialization.
**Profiles & ratings:** each verified doctor has a public **profile page**
(`GET /doctors/{id}`) showing specialization, region, languages, registration number,
and an aggregate **star rating** with recent reviews; farmers rate a doctor
(`POST /doctors/{id}/rate`, 1-5 stars + comment). Ratings show in the directory and on
the profile. The web app has an *Apply as a plant doctor* form + *View profile* with a
rating widget (in the Plant clinic tab's live-doctor section) and a *Plant doctor
verification* panel (Admin tab).
Backed by [agrosense/doctors.py](agrosense/doctors.py) (`data/plant_doctors.json`,
seeded from [data/agri_experts.json](data/agri_experts.json)).
**Expert notifications:** when a consult is routed, the assigned expert is notified β€”
always recorded in an in-app **audit log** (`GET /notifications`), and, when
configured, delivered via **webhook** (`AGROSENSE_NOTIFY_WEBHOOK` β€” Slack/Discord/
Zapier/custom, keyless) and/or **email** (`AGROSENSE_NOTIFY_EMAIL_TO` + SMTP env). See
[agrosense/notifications.py](agrosense/notifications.py).
> Honest scope: the experts are **demo/seed entries** β€” there are no real practitioners
> on the other end in the POC. Connecting real experts means populating the directory
> with availability + contact, and they'll be alerted via the notification channels
> above; the video room, chat, and notifications are functional. The default Jitsi room
> (meet.jit.si) may ask the first joiner to sign in as moderator β€” set
> `AGROSENSE_VIDEO_BASE` to a self-hosted Jitsi for production.
### Traditional Advisor (traditional knowledge + Panchang)
A **πŸͺ” Traditional** advisor for daily farm activities that combines **Indian
traditional/desi practices** with **Panchang (astrological) guidance**. For an activity
(sowing, transplanting, harvesting, pest control, …) it gives:
- an **astrological suitability** verdict from today's Panchang β€” favourable nakshatras
for sowing, waxing vs waning moon (Shukla/Krishna paksha), Vishti (Bhadra) karana and
Amavasya/Rikta-tithi cautions β€” with the reasons, and
- relevant **traditional practices** (Beejamrit, Jeevamrit, lunar/nakshatra sowing, neem
& panchagavya pest control, mixed cropping…), **matched to the area/region**.
`GET /traditional?activity=…&location=…` (keyless). See
[agrosense/traditional.py](agrosense/traditional.py) +
[data/traditional_knowledge.json](data/traditional_knowledge.json).
### Finance β€” bank assistance + government schemes & subsidies
A single **🏦 Finance** tab combines two things a farmer needs money-wise:
**Bank assistance & agri-loans.** A curated catalog of agri-credit products β€” KCC and
crop/production loans, term/investment loans, farm-mechanization, allied
(dairy/AH/fisheries), agri gold loans, warehouse-receipt finance, FPO & SHG credit, the
Agriculture Infrastructure Fund, solar-pump (PM-KUSUM) and horticulture loans. Each lists
**provider, interest, loan amount, tenure, benefits, eligibility, step-by-step application
process, documents, portal and helpline**. Browse/filter by **category** or search, then
**lodge a loan enquiry** (name + contact + requested amount) β€” applications are recorded
and visible to an admin in the βš™οΈ Admin tab (`GET /admin/finance/applications`,
token-gated). API: `GET /finance?category=&provider=&search=`, `GET /finance/{id}`,
`POST /finance/{id}/apply`. See [agrosense/finance.py](agrosense/finance.py) +
[data/finance.json](data/finance.json) (enquiries persist to the gitignored runtime
`data/finance_applications.json`).
**Government schemes & subsidies.** Central and state agricultural schemes with the full
publication for each β€” **summary, benefits, eligibility, step-by-step application
process, documents required, official portal, helpline** β€” plus an
**announcements/updates** feed. Browse and filter by **level** (Central / State),
**state** (the sidebar Location surfaces schemes that apply to you β€” central schemes
always show), **category**, or free-text **search**; open any scheme for its full detail,
and see a **latest-announcements** feed aggregated across all schemes (newest first).
Seeded with 13 schemes β€” 10 central (PM-KISAN, PMFBY, KCC, PMKSY, Soil Health Card, SMAM,
PKVY, eNAM, AIF, PM-KMY) and 3 state (Krishi Bhagya/Karnataka, Rythu Bandhu/Telangana,
Magel Tyala Shettale/Maharashtra). Admins can **append updates** to a scheme
(`POST /admin/subsidies/{id}/update`, token-gated). API:
`GET /subsidies?level=&state=&category=&search=`, `GET /subsidies/{id}`,
`GET /subsidies/updates`. See [agrosense/subsidies.py](agrosense/subsidies.py) +
[data/subsidies.json](data/subsidies.json).
> Honest scope: both are **curated knowledge bases** (no reliable keyless live
> scheme/loan-rate feed exists). Interest rates, scheme amounts and rules are set by
> RBI/NABARD/banks and governments and change over time; **"apply" lodges an enquiry in
> AgroSense, not a bank/portal submission**. Each view carries a disclaimer to verify and
> apply through the bank or official portal.
### Land record search & documents
A **πŸ—ΊοΈ Land records** tab to find your **State's official land-record system** and take
the exact steps to view/download your record. Land is a State subject, so the tab is a
**searchable directory** (15 states + an all-India fallback) giving, per state: the local
**record name** (RTC/Pahani, 7/12 Saatbara, Khatauni, Jamabandi, Patta/Chitta, …), the
official **portal** and **cadastral-map (Bhu-Naksha)** portal, **what to search by**
(district, taluk/tehsil, village, survey/khasra/khata number), **step-by-step** search &
download instructions, what the record **contains**, and the helpline. The sidebar
**Location** is geocoded to its state (or pick a state explicitly). You can also
**download a printable guide** (Word/PDF) for that state, generated on the fly.
API: `GET /land-records?location=&state=`, `GET /land-records/guide.{pdf|docx}?location=&state=`.
See [agrosense/land_records.py](agrosense/land_records.py) +
[data/land_records.json](data/land_records.json) (PDF/Word via the shared
[scripts/docgen.py](scripts/docgen.py) renderer).
> Honest scope: AgroSense **does not fetch or store your actual land record** β€” those
> live on each State's portal, usually behind a login/OTP/fee. This feature helps you
> **find and download yours from the official source**; always rely on the State portal's
> copy.
> This is cultural, belief-based knowledge offered as **complementary to β€” not a
> replacement for β€” scientific agronomy**, soil tests and local conditions. The
> nakshatra/yoga rely on an approximate ayanamsa (see the Panchang note above).
### Decision-fusion advisories
Fuse the live signals β€” **weather forecast + satellite agroclimate (NASA POWER) +
field NDVI** β€” into **prioritized, cross-signal, actionable** advisories that no
single source can give (e.g. *"NDVI trending down while rain is forecast β†’ inspect
drainage and scout disease"*). Works by place name **or** latitude/longitude:
```powershell
python cli.py --location Belagavi --advisories "advice for my cotton field?"
```
Advisories are tagged by urgency (high/medium/low) and category (irrigation, spray,
disease, protection, monitoring), each with the **rationale** (which signals drove
it). The rule set lives in [agrosense/fusion.py](agrosense/fusion.py) as a pure
function over the fetched signals, so it is fully unit-tested.
**Crop- and stage-aware:** pass a `crop` and growth `stage`
(seedling/vegetative/flowering/maturity) and the thresholds + urgencies adapt per
[agrosense/crop_profiles.py](agrosense/crop_profiles.py) β€” e.g. tomato flags heat at
32Β°C while cotton tolerates 40Β°C, flowering/seedling stages escalate stress
advisories, and rain near *maturity* raises a harvest-quality warning.
```powershell
python cli.py --location Belagavi --advisories --stage flowering "advice for my tomato?"
```
Endpoint: `GET /advisories?location=…&crop=Tomato&stage=flowering` (or `latitude`/`longitude`).
### Planetary positions
Show the **Sun, Moon (with phase) and classical planets** (Mercury–Saturn) for the
location at the current time β€” altitude/azimuth, RA/Dec, and what's above the
horizon β€” useful for sky context and traditional/Panchang-style scheduling.
```powershell
python cli.py --location Belagavi --planets "..."
```
Computed locally with a pure-Python ephemeris (Schlyter's algorithm) β€” **keyless,
offline, no dependencies** ([agrosense/planetary.py](agrosense/planetary.py)),
validated in tests against known astronomy (solar declination β‰ˆ +23.4Β° at the June
solstice). Endpoint: `GET /planetary?location=…` or `?latitude=…&longitude=…`.
### Multilingual answers (Phase 2)
Ask in β€” or get answers in β€” the report's Phase 2 languages (Hindi, Kannada,
Telugu, Tamil, Marathi, Bengali, Malayalam, Gujarati, Punjabi). The query is
translated to English for retrieval and the grounded answer is translated back:
```powershell
python cli.py --lang hi "What fertilizer should I use for maize?"
```
Backends (auto-selected, optional): **argostranslate** (fully offline) β†’ **deep-
translator** (online, no key) β†’ identity (English passthrough). If no backend is
installed, the answer simply stays English and the UI/CLI says so. See
[agrosense/translation.py](agrosense/translation.py).
### Real-time market prices (closes the report's last pain point)
Attach live mandi (Agmarknet) prices for the crop in a question β€” min/max/modal
β‚Ή/quintal across markets, with a "compare mandis" note when prices spread widely:
```powershell
python cli.py --prices "what's the price of tomato in Karnataka?"
```
Requires a **free data.gov.in api-key** (set `AGROSENSE_DATAGOV_API_KEY`); without
it, prices degrade gracefully to "unavailable". See
[agrosense/prices.py](agrosense/prices.py).
### 🀝 Farmer trading platform (in the Market tab)
A peer-to-peer **produce marketplace** inside the Market tab: farmers post **sell**
offers and buyers post **buy** requirements (commodity, quantity/unit, price, grade,
location/state, description). Anyone can **browse/filter** by type (sell|buy), commodity
or state, **open a listing**, **express interest** (an inquiry with contact + offer +
quantity), **negotiate live** in a per-listing **video room** (Jitsi, keyless), and the
poster can **mark it sold/closed** (closed listings drop out of the default browse). Live
mandi prices and the commodity ticker sit alongside in the same tab as a pricing
reference. Seeded with demo listings on first run.
API: `GET/POST /market/listings`, `GET /market/listings/{id}`,
`POST /market/listings/{id}/inquire`, `POST /market/listings/{id}/close`. See
[agrosense/trading.py](agrosense/trading.py) (persisted to `data/market_listings.json`,
gitignored runtime state).
> Honest scope: a **POC marketplace** β€” listings and seed buyers/sellers are
> demo/user-generated; there is **no payment, escrow, KYC or logistics**. Verify the
> other party and agree terms independently before transacting (the UI carries this
> disclaimer).
### πŸ“» Internet radio
A **Radio** tab lists online radio stations for India (Vivid Bharti, Radio Mirchi,
Red FM, AIR, regional/agriculture stations…) and plays them in an in-app audio player.
Keyless via the **Radio Browser** community API. `GET /radio?country=IN&search=…`. See
[agrosense/radio.py](agrosense/radio.py).
> This is **internet radio**, not over-the-air FM tuning (a browser has no RF
> hardware). Many FM/AIR stations stream online so the local station is often present,
> but coverage of small stations varies and some streams may be temporarily offline
> (filtered with `hidebroken=true` + popularity ordering). On an HTTPS deployment,
> plain `http://` streams are blocked as mixed content β€” prefer https streams or proxy.
### Date/time header + Reuters news ticker
The UI shows a top bar with the date in the **Gregorian (English)** calendar, the
**Indian National (Saka)** calendar with a mini-**Panchang** β€” lunar day (tithi),
nakshatra shown inline (e.g. "Shukla Purnima Β· Anuradha") and the full five limbs
(vaara, tithi, nakshatra, yoga, karana) in a hover tooltip, computed from the
ephemeris β€” and the current **IST** time, plus the Google News headline ticker.
- Calendar/IST logic: [agrosense/calendars.py](agrosense/calendars.py) (pure,
unit-tested — the Gregorian→Saka conversion is exact). Endpoint `GET /datetime`.
- Headlines: [agrosense/news.py](agrosense/news.py) β€” Google News RSS, **keyless**,
graceful empty list on failure. The UI has **region** (India/US/UK/Australia/
Canada/Singapore) and **topic** (Top stories/Agriculture/Business/Technology/
Science/Health/Sports/World) selectors above the ticker.
`GET /news?region=US&query=technology&limit=15` β€” `region` selects the locale,
`query`=None gives general top stories, or pass a topic/keyword (or a
`site:reuters.com` filter for the Reuters feed).
Directly below the news scroll, a **slow-scrolling commodity ticker** shows
**Gold, Silver, Crude Oil, Coffee** (Yahoo Finance futures, **keyless**, with day
change %) and **Arecanut, Coconut** (Agmarknet via data.gov.in β€” show "n/a" until a
key is set). See [agrosense/commodities.py](agrosense/commodities.py); `GET /commodities`.
Below that, a **local weather strip** shows current conditions for the sidebar
location (temperature, humidity, today's range, rain chance, top advisory) β€” driven
by the same Open-Meteo forecast as the rest of the app.
The displayed time reflects the page render (updates on refresh/interaction).
### Evaluation harness (RAGAS-style, offline)
Measure the report's accuracy targets against a gold question→expected-source set:
```powershell
$env:AGROSENSE_EMBEDDING_BACKEND="hashing"; python scripts/evaluate.py
```
Reports context relevance, citation MRR, faithfulness, hallucination rate, answer
relevance, out-of-domain accuracy, and latency p50/p95 β€” each checked against the
report's targets (β‰₯95% relevance/faithfulness, <5% hallucination, ≀3 s). Exits
non-zero if any target is missed (CI-friendly). Metrics are pure functions
([agrosense/evaluation.py](agrosense/evaluation.py)); the gold set is
[data/eval_set.json](data/eval_set.json).
> On the offline hashing-embedder POC the current set passes all targets (context
> relevance 100%, faithfulness 100%, hallucination 0%, p95 < 1 ms). Faithfulness is
> high by construction for the extractive generator; the harness's value is catching
> regressions and re-measuring once a real embedder/LLM is plugged in.
### Runs fully offline, no API keys, no internet
Every heavy dependency is **optional**. Out of the box the app uses:
- a deterministic **hashing embedder** (no model download), and
- a **numpy** cosine-similarity vector store (no FAISS), and
- an **extractive grounded generator** that composes answers *only* from retrieved
KB fields and attaches citations β€” so it cannot hallucinate agronomic facts.
If you install the optional accelerators, the same code automatically upgrades:
- `pip install sentence-transformers` β†’ better semantic embeddings
- `pip install faiss-cpu` β†’ faster vector search
---
## Quick start
```powershell
# 1. (optional) create a venv, then install core deps
pip install -r requirements.txt
# 2a. Try it on the command line (no server needed)
python cli.py "My soil is sandy, rainfall 900 mm, I plan to grow maize. What fertilizer and pest steps?"
# 2b. Or run the interactive REPL
python cli.py
# 3. Run the API
uvicorn api.main:app --reload # http://127.0.0.1:8000/docs
# 4. Run the chat UI (in another terminal)
streamlit run ui/app.py # http://localhost:8501
```
The Streamlit UI calls the FastAPI backend if it's running, and otherwise falls
back to running the engine in-process β€” so the UI works on its own too.
### Run the tests
```powershell
python tests/test_rag.py # or: python -m pytest
```
---
## How it maps to the report
| Report concept | Where it lives |
| --- | --- |
| Data Layer / Knowledge Base (structured JSON entries) | [data/knowledge_base.json](data/knowledge_base.json), [agrosense/knowledge_base.py](agrosense/knowledge_base.py) |
| Knowledge Layer (vectorized documents) | [agrosense/embeddings.py](agrosense/embeddings.py), [agrosense/vector_store.py](agrosense/vector_store.py) |
| Cognitive Layer β€” RAG pipeline (retrieval + re-ranking + generation) | [agrosense/retriever.py](agrosense/retriever.py), [agrosense/generator.py](agrosense/generator.py), [agrosense/rag.py](agrosense/rag.py) |
| Cognitive Layer β€” decision fusion (multi-signal advisories) | [agrosense/fusion.py](agrosense/fusion.py), [agrosense/crop_profiles.py](agrosense/crop_profiles.py) |
| Cognitive Layer β€” traditional advisor (Panchang + desi practices) | [agrosense/traditional.py](agrosense/traditional.py) |
| Data Layer β€” government schemes & subsidies (central + state, updates) | [agrosense/subsidies.py](agrosense/subsidies.py), [data/subsidies.json](data/subsidies.json) |
| Application Layer β€” agri finance (bank assistance / loans + apply) | [agrosense/finance.py](agrosense/finance.py), [data/finance.json](data/finance.json) |
| Data Layer β€” land records (state RoR portal directory + generated guide) | [agrosense/land_records.py](agrosense/land_records.py), [data/land_records.json](data/land_records.json) |
| Data Layer β€” planetary positions | [agrosense/planetary.py](agrosense/planetary.py) (pure-Python ephemeris) |
| Data Layer β€” hazards & fires | [agrosense/hazards.py](agrosense/hazards.py) (NASA EONET keyless + FIRMS keyed) |
| Cognitive Layer β€” plant vision | [agrosense/vision.py](agrosense/vision.py) (disease + plant ID + pest ID; Keras backend + heuristic) |
| Cognitive Layer β€” plant telemedicine | [agrosense/telemedicine.py](agrosense/telemedicine.py) (diagnosis + grounded, cited prescription) |
| Engagement Layer β€” live agri-doctor | [agrosense/consultation.py](agrosense/consultation.py) (expert routing + Jitsi video + chat) |
| Engagement Layer β€” farmers' clubs | [agrosense/clubs.py](agrosense/clubs.py) (location/commodity communities: feed + video + sharing) |
| RAG Workflow steps 1–7 (intake β†’ preprocess β†’ retrieve β†’ re-rank β†’ generate β†’ cite) | [agrosense/rag.py](agrosense/rag.py) (`RAGEngine.answer`) |
| **CARO** β€” Context-Aware Retrieval Optimizer (metadata-weighted re-ranking) | `Retriever._rerank_score` in [agrosense/retriever.py](agrosense/retriever.py) |
| Data Layer β€” dynamic (weather) data | [agrosense/weather.py](agrosense/weather.py) (Open-Meteo, no key) |
| Data Layer β€” location environment | [agrosense/environment.py](agrosense/environment.py) (elevation, AQ, pollen, wind, groundwater proxy) |
| Data Layer β€” satellite / remote sensing | [agrosense/satellite.py](agrosense/satellite.py) (NASA GIBS + POWER, no key) |
| Data Layer β€” field-level NDVI (keyed) | [agrosense/ndvi.py](agrosense/ndvi.py) (Sentinel-2 via Google Earth Engine) |
| Data Layer β€” market prices | [agrosense/prices.py](agrosense/prices.py) (Agmarknet via data.gov.in) |
| Application Layer β€” farmer trading platform (P2P produce marketplace) | [agrosense/trading.py](agrosense/trading.py), `data/market_listings.json` |
| Engagement Layer β€” multilingual | [agrosense/translation.py](agrosense/translation.py) (argos / deep-translator) |
| Interaction Layer (conversational UI) | [ui/app.py](ui/app.py) |
| "Use only retrieved KB data. Include citations." system prompt | `SYSTEM_PROMPT` in [agrosense/generator.py](agrosense/generator.py) |
| Faithfulness / low-hallucination targets | extractive generator + relevance gate β†’ off-domain queries get a safe fallback, never fabricated advice |
| Latency ≀ 3 s target | every response reports `latency_ms` (sub-millisecond on the offline backends) |
### Sample knowledge base
Covers paddy, maize, wheat, cotton, plus fertilizer schedules for aromatic
(mint, citronella), vegetable (tomato), fruit (banana) and flower (marigold) crops,
and a general soil-health entry β€” modeled on the report's KB design and the Azure
assistant examples shown in the document.
---
## Configuration
All tunable via environment variables (see [agrosense/config.py](agrosense/config.py)):
| Variable | Default | Purpose |
| --- | --- | --- |
| `AGROSENSE_EMBEDDING_BACKEND` | `auto` | `auto` \| `sentence-transformers` \| `hashing` |
| `AGROSENSE_GENERATION_BACKEND` | `extractive` | `extractive` (offline) \| `openai` (real LLM seam) |
| `AGROSENSE_TOP_K` | `5` | candidates from vector search |
| `AGROSENSE_RERANK_K` | `3` | kept after re-ranking |
| `AGROSENSE_KB_PATH` | `data/knowledge_base.json` | knowledge base location |
| `AGROSENSE_API_URL` | `http://127.0.0.1:8000` | API URL used by the UI |
### Plugging in a real LLM (production path)
`OpenAIGenerator` in [agrosense/generator.py](agrosense/generator.py) shows the seam.
Set `AGROSENSE_GENERATION_BACKEND=openai`, `pip install openai`, and provide
`OPENAI_API_KEY`. The same pattern adapts to Azure OpenAI (the report's `gpt-5-mini`
deployment). The retrieval context and the strict "use only the provided context,
cite sources" instruction are already wired in.
---
## Project layout
```
AgroSense/
β”œβ”€β”€ data/knowledge_base.json # the agriculture KB (structured JSON)
β”œβ”€β”€ agrosense/ # RAG core (the reusable library)
β”‚ β”œβ”€β”€ config.py # env-driven configuration
β”‚ β”œβ”€β”€ embeddings.py # hashing (offline) + sentence-transformers backends
β”‚ β”œβ”€β”€ knowledge_base.py # KB loading + document construction
β”‚ β”œβ”€β”€ vector_store.py # numpy fallback + FAISS backend
β”‚ β”œβ”€β”€ retriever.py # vector search + CARO-style re-ranking + relevance gate
β”‚ β”œβ”€β”€ generator.py # extractive grounded generator (+ OpenAI seam)
β”‚ β”œβ”€β”€ weather.py # live local forecast + advisory (Open-Meteo, no key)
β”‚ β”œβ”€β”€ satellite.py # satellite imagery + agroclimate (NASA GIBS + POWER)
β”‚ β”œβ”€β”€ ndvi.py # field-level Sentinel-2 NDVI (Google Earth Engine, keyed)
β”‚ β”œβ”€β”€ translation.py # multilingual layer (argos / deep-translator / identity)
β”‚ β”œβ”€β”€ prices.py # mandi market prices (Agmarknet via data.gov.in, keyed)
β”‚ β”œβ”€β”€ fusion.py # decision-fusion advisories (weather + satellite + NDVI)
β”‚ β”œβ”€β”€ crop_profiles.py # per-crop thresholds + growth stages (crop-aware fusion)
β”‚ β”œβ”€β”€ environment.py # location environment profile (Open-Meteo, keyless)
β”‚ β”œβ”€β”€ planetary.py # Sun/Moon/planet positions (pure-Python ephemeris)
β”‚ β”œβ”€β”€ groundwater.py # real water-table depth (CGWB/data.gov.in, keyed)
β”‚ β”œβ”€β”€ evaluation.py # RAGAS-style eval metrics (pure) + evaluate()
β”‚ β”œβ”€β”€ calendars.py # Gregorian + Indian National (Saka) calendars + IST
β”‚ β”œβ”€β”€ news.py # Google News headlines (region/topic, keyless)
β”‚ β”œβ”€β”€ radio.py # internet radio stations (Radio Browser, keyless)
β”‚ β”œβ”€β”€ commodities.py # Gold/Silver/Oil/Coffee (Yahoo) + Arecanut/Coconut (Agmarknet)
β”‚ β”œβ”€β”€ hazards.py # NASA EONET events (keyless) + FIRMS fires (keyed)
β”‚ β”œβ”€β”€ vision.py # plant disease + ID + pest (Keras backend + Pillow heuristic)
β”‚ β”œβ”€β”€ telemedicine.py # plant consult: diagnosis + grounded, cited prescription
β”‚ β”œβ”€β”€ ipm.py # recognized class -> exact IPM prescription lookup
β”‚ β”œβ”€β”€ consultation.py # live agri-doctor: expert routing + video + chat
β”‚ β”œβ”€β”€ doctors.py # plant-doctor onboarding + verification registry
β”‚ β”œβ”€β”€ notifications.py # expert alerts: in-app log + webhook + email
β”‚ β”œβ”€β”€ kb_admin.py # knowledge-base CRUD store + validation (admin)
β”‚ └── rag.py # RAGEngine: end-to-end pipeline
β”œβ”€β”€ api/main.py # FastAPI: /query /weather /satellite /environment /planetary /hazards /vision/classify /telemedicine /experts /doctors/apply /doctors/{id} /doctors/{id}/rate /admin/doctors /consult/* /notifications /admin/kb /advisories /prices /news /commodities /datetime /languages
β”œβ”€β”€ scripts/evaluate.py # run the evaluation harness over data/eval_set.json
β”œβ”€β”€ scripts/train_plant_models.py # train the disease + plant-ID CNNs (needs TF + datasets)
β”œβ”€β”€ ui/app.py # Streamlit chat UI
β”œβ”€β”€ cli.py # command-line interface
β”œβ”€β”€ tests/test_rag.py # offline smoke + behavior tests
└── requirements.txt
```
---
## Limitations & next steps (toward the report's later phases)
- The offline hashing embedder is lexical-ish; install `sentence-transformers` for
true semantic retrieval.
- The extractive generator returns KB fields verbatim with citations rather than
free-form prose β€” swap in the LLM backend for natural-language synthesis.
- Phase 2+: voice/image input, multilingual responses, live weather/market data,
and IoT signals (the data layer and `RAGEngine` are structured to accept them).