Skip to content
Limajmr8Public

About

AI-powered smart farming platform for Nagaland — crop disease detection, live market prices, planting calendar and government scheme finder

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

title Plotwise
emoji 🌾
colorFrom green
colorTo gray
sdk docker
app_port 8080
pinned false

Plotwise

Tests Android APK

Agricultural intelligence platform for Nagaland, India: on-device crop-disease detection, market prices with a live mandi feed, planting calendars, weather, and a government-scheme finder — built on the state's real 2023-24 production records. FastAPI + TensorFlow backend, framework-free HTML/JS frontends, Capacitor Android app.

Live demo: https://limajmr-plotwise.hf.space · Author: Limawapang L Jamir

I audited my own test set and found 427 images I had already trained on — how a contaminated split inflated this project's headline accuracy, why the corrected number matters less than the 43.6% it led me to measure, and what the confidence system does not protect against.


What's technically unusual here

1. Inference ships to the phone. The trained CNN (EfficientNetB0, 24 classes) is converted to a 9 MB TensorFlow.js graph model (frontend/src/tfjs-model/, conversion metadata recorded in model.json: TensorFlow.js Converter 4.22.0 from TF 2.17.0) and bundled inside the Android APK — capacitor.config.ts has no remote server.url; scripts/build_bundle.sh packs the UI, model, and reference data into the app. In the APK, leaf diagnosis therefore runs with zero connectivity, behind a bilingual English/Nagamese UI (the diagnosis and treatment text itself is currently English-only); offline-ai.js is a JS port of the server's crop-aware decision layer, and offline detections queue locally and sync to the server's surveillance heatmap when a connection returns.

In the browser, that same code path is deliberately switched off: running TensorFlow.js requires 'unsafe-eval', which this app's Content-Security-Policy (main.py CONTENT_SECURITY_POLICY) does not grant, so the web PWA sends photos to the server endpoint instead. The APK is unaffected because it serves no CSP header. The trade — a hardened header on the public web, full on-device inference in the app — is deliberate, and offline-ai.js ready() detects the disabled runtime and falls back rather than failing. Measured, with the reasoning, in CHANGELOG 2.5.2.

2. The accuracy claims are measured — including the bad ones. Models trained on lab datasets are known to collapse on real field photos. Instead of quoting the lab number, eval/ measures the deployed inference path on in-the-wild images and reports the collapse, what the decision layer recovers, and where the confidence system fails. See the table below.

3. An evaluated agent layer, not a chatbot wrapper. The assistant can run as a tool-use loop over the backend's data functions, with local-model routing (local 7B via Ollama, no API cost) and escalation to claude-opus-5 — the routing is built, though the measured numbers so far cover the local backend only. Graded by a committed 40-question eval with ground truth derived from the dataset. See below.


Generalization: lab accuracy vs. field accuracy

The same deployed inference code (imported from backend/src/main.py, not reimplemented) evaluated on held-out lab images (PlantVillage) and on real field photographs (PlantDoc):

PlantVillage held-out, clean (n=7,654)³ PlantDoc field images (n=1,642)
A — raw model argmax, top-1 87.7% 27.3%
B — + crop-aware pass, top-1 91.9%¹ 43.6%
C — + abstention: coverage 89.9% 48.4%
C — selective accuracy (when it answers) 96.4% 45.7%
OOD images routed to "uncertain"² — 75.7% same-crop · 90.6% foreign-species

¹ n=7,588 (66 images with no crop label excluded from the crop-aware arm), so the lab delta below compares across the two denominators. ² Computed on the 936 unmapped OOD images (305 same-crop, 631 foreign-species), not the 1,642 in the column header. ³ A 2026-08 content-hash audit found 427 of the 8,081 test images byte-identical to training files (residue of an earlier dataset prep); they are excluded from every number here, the runner re-excludes them on every run, and the leaked subset's 98.7% score is reported in eval/RESULTS.md §1a as the memorization signature it is.

python eval/plantvillage/run_baseline.py   # left column
python eval/plantdoc/download.py           # fetch PlantDoc (CC BY 4.0)
python eval/plantdoc/run_eval.py           # right column

Honest reading: the crop-aware pass genuinely helps everywhere (+4.2 pts lab, +16.3 pts field), but field accuracy is 43.6%, not 91.9% — and under domain shift the confidence system stops working as a safety net (on answered field images the error rate is 54.3%; in-domain it is 3.6%). The part that does survive is OOD routing: photos of untrained diseases and foreign species are mostly sent to "uncertain" instead of answered confidently. Full analysis, per-class breakdowns, risk–coverage curves, and dataset caveats: eval/RESULTS.md.


Architecture

flowchart TB
    subgraph train["Model pipeline (offline, GPU)"]
        PV["PlantVillage dataset"] --> TRAIN["ml/train_disease_model.py<br/>EfficientNetB0 · 24 classes"]
        TRAIN --> H5["disease_model.h5"]
        H5 -->|"tensorflowjs_converter 4.22.0"| TFJS["frontend/src/tfjs-model/<br/>9 MB graph model"]
    end

    subgraph server["FastAPI backend (backend/src/main.py)"]
        CSV["576-record CSV<br/>Director of Agriculture, Nagaland 2023-24"] --> API["REST API · PDF/CSV export · chatbot"]
        MANDI["data.gov.in Agmarknet feed<br/>12 h cache · 7-day stale guard"] --> API
        METEO["Open-Meteo weather"] --> API
        API --- AGENT["backend/src/agent.py<br/>tool-use loop (PLOTWISE_AGENT=1)"]
        AGENT -->|"simple lookups"| OLLAMA["qwen2.5:7b via Ollama<br/>(local, $0)"]
        AGENT -->|"multi-step escalation"| CLAUDE["claude-opus-5"]
    end

    subgraph clients["Clients"]
        WEB["Desktop SPA<br/>index.html"]
        PWA["Mobile PWA<br/>mobile.html + sw.js app-shell cache"]
        APK["Android APK (Capacitor)<br/>UI + model + data bundled"]
    end

    H5 --> API
    API <--> WEB
    API <--> PWA
    TFJS -->|"scripts/build_bundle.sh"| APK
    APK -.->|"offline queue → sync on reconnect"| API
Loading

Data provenance

  • Crop records — 576 records: "District-wise Area, Production and Yield (Achievement) 2023-24", Director of Agriculture, Nagaland, Kohima (verified 09-May-2024, checked 30-Jul-2024). 16 districts, 44 crops. This is the ground truth for the dashboard, the yield API, and most of the agent-eval questions.
  • Market prices — live daily mandi rates for Nagaland APMCs from the official data.gov.in Agmarknet feed (12-hour cache, 7-day stale guard) where mandis report; MSP 2023-24 (CACP) + Agmarknet anchors as clearly-labelled indicative fallback. A live rate is never invented — no key, no feed, or stale data means the row says "Indicative".
  • Planting calendar — sow/harvest windows checked against the official Nagaland Crop Calendar (Department of Agriculture, Government of Nagaland, web-published Jan 2025); zone lists derived from the 2023-24 CSV by scripts/audit_calendar_vs_csv.py and drift-guarded by the test suite.
  • Weather — Open-Meteo (no API key), GPS coordinates for all 16 district HQs: Kohima, Tseminyu, Phek, Mokokchung, Tuensang, Noklak, Shamator, Mon, Dimapur, Niuland, Chumoukedima, Wokha, Zunheboto, Peren, Kiphire, Longleng.
  • Disease model — PlantVillage dataset (Penn State). Field eval: PlantDoc — Singh et al., CoDS-COMAD 2020, DOI 10.1145/3371158.3371196, CC BY 4.0.

Agent layer

backend/src/agent.py replaces keyword intent-detection with a model-driven tool-use loop over six backend functions (get_yield, get_price, get_weather, compare_districts, get_planting_calendar, find_schemes). Feature-flagged (PLOTWISE_AGENT=1); the legacy intent path stays as the default and as the fallback when no backend is reachable. A rule-based router sends simple lookups to a local model and escalates comparisons and multi-step questions to claude-opus-5; every turn is logged as JSONL (tools, arguments, latency, token cost). Numeric answers must trace to tool results — no data means a refusal, not a guess.

Graded by a 40-question eval: 25 answerable, with ground truth derived from committed sources — the 576-record CSV plus the backend's price, calendar, and scheme tables (one live-weather question is graded on tool selection only, hence 24 graded below); 10 unanswerable, where refusal is correct; and 5 ambiguous, where a clarifying question is correct:

Metric local backend (qwen2.5:7b)
Tool-selection accuracy 100% (25/25)
Answer correctness (24 graded) 70.8%
Refusal accuracy (10 unanswerable) 90%
Clarification rate (5 ambiguous) 20%
Mean latency 1.7 s
API cost $0
python eval/agent/run_eval.py --backend local

The local 7B model picks the right tools and refuses well, but tends to answer one interpretation of an ambiguous question instead of asking, and fumbles multi-step arithmetic — exactly the traffic the router escalates. Claude and routed columns are pending an ANTHROPIC_API_KEY. Grader design, iteration history (recorded honestly, including the bugs that inflated early numbers), and per-question outputs: eval/README.md.


What it does

  • Disease detection — photograph a leaf → prediction with three-tier confidence (confident ≥70% / low 55–70% / uncertain — the app says "not sure" instead of guessing) and treatment guidance; works offline on the phone. Crops outside the model fall back to a curated knowledge base.
  • Market prices — live vs. indicative labelling on every surface (UI, CSV export, PDF report, chatbot).
  • Planting calendar — statewide sow/harvest windows checked against the official Nagaland Crop Calendar, filtered per district to the crops its 2023-24 records support, with live seasonal status.
  • Scheme finder — crop → matching government schemes with eligibility notes.
  • Weather — current + 7-day forecast with farming advisories, all 16 district HQs.
  • Analytics dashboard — district-wise area/production/yield, disease surveillance heatmap with audit trail, one-click district PDF report.
  • Assistant — English replies behind a bilingual EN/Nagamese chat UI; agent mode behind a flag.

Quick start (local)

Requires Python 3.11 — TensorFlow 2.17 has no wheels for newer Pythons.

git clone https://github.com/Limajmr8/plotwise.git
cd plotwise
python3.11 -m venv venv
source venv/bin/activate          # Windows: venv\Scripts\activate
pip install -r requirements.txt
uvicorn backend.src.main:app --port 8000

Open http://127.0.0.1:8000 (desktop UI) or /mobile (mobile UI).

⚠️ Do not use --reload on Windows — it crashes the TensorFlow subprocess. Keep the pinned versions in requirements.txt (TF 2.17.0 / Keras 3.10.0) — newer versions cannot load the model.

Optional configuration via .env (see .env.example): database path, CORS origins, live-price API key, agent flag and backends.

Docker

docker build -t plotwise .
docker run -p 8080:8080 -e PLOTWISE_SEED_ON_EMPTY=1 plotwise

API endpoints (selected)

Method Endpoint Description
GET /health Health check
GET /api/status App status, version, data summary
GET /districts · /crops Reference data (16 districts, 44 crops)
GET /prices Market prices (filters: crop, district)
GET /calendar Planting calendar with live status (filters: district, crop)
POST /schemes Scheme matching by crop
POST /disease/detect Leaf image upload → ML prediction (multipart)
GET /api/weather Live weather + 7-day forecast per district
POST /api/chat Assistant — agent loop when PLOTWISE_AGENT=1, keyword intents otherwise
GET /dashboard/yield · /dashboard/disease-heatmap Analytics
GET /api/export/report District PDF report
GET /api/export/prices · /api/export/yield CSV exports

Interactive docs at /docs when running locally.

curl -X POST http://localhost:8000/disease/detect \
  -F "file=@leaf.jpg" \
  -F "crop=Potato" -F "district=Kohima"

Android app

Capacitor bundles the mobile UI, the TF.js model, and the reference data into the APK (npx cap sync android after scripts/build_bundle.sh), so detection and the data tools work with no network; live features call the hosted backend. GitHub Actions builds a debug APK on every push to main.


Tests

pytest tests/ -q     # also runs in CI on every push

Covers every endpoint, the ML confidence tiers, the live-mandi cache (hit/miss/stale/failure-backoff), the weather proxy (mocked Open-Meteo), the agent loop (scripted fake backend — no network), a security-regression suite (XSS sanitisation, CSV-injection guards, filename injection, input validation), exports, edge cases, and data-integrity guards (the offline bundle must match the backend constants; calendar zones must match the CSV). Tests run against an isolated temporary database with the live feed disabled.

The backend is security-hardened from a whitebox audit with live exploitation: server-side input sanitisation + output escaping, a Content-Security-Policy, and injection guards — all under regression tests — plus per-client rate limiting and CVE-patched dependency pins.


Known limitations

  • Field accuracy is 43.6%, and abstention is not a reliable safety net under domain shift — on field images the system still answers 48% of the time with a 54.3% error rate on those answers. The eval exists precisely to keep this number visible. Mitigations that would actually move it (fine-tuning on field imagery, adding the missing healthy/mosaic classes, confidence calibration on field data, background-robustness augmentation or leaf segmentation) are discussed in eval/RESULTS.md.
  • Same-crop OOD is the dangerous case: a photo of an untrained disease on a covered crop is routed to "uncertain" only 75.7% of the time (worst: tomato mosaic virus, 13% routed — it usually gets a confident wrong answer).
  • Class coverage: 24 classes over 9 crops. Nagaland staples such as paddy and ginger have no model coverage and fall back to a knowledge base.
  • Mandi coverage is sparse: Nagaland APMCs report irregularly and mostly horticulture/perishables, so many price rows remain MSP-anchored "Indicative" even with a live key configured.
  • Single data year: all yield data is 2023-24; no trends across years.
  • Planting windows are statewide simplifications: the official Nagaland Crop Calendar documents different windows per district and farming system (jhum / terrace / plains); the app carries one modal [start, end] window per crop. Zone lists are derived from the 2023-24 CSV and drift-guarded by tests, but documented per-district exceptions (plains potato sown Oct–Nov, Tuensang's autumn potato, Mon's Aug–Sep rabi-maize cycle) are not modelled — see CHANGELOG 2.3.1 for the full audit trail.
  • PlantDoc caveats: label noise, a known apple train/test inconsistency, and some very small classes — documented per-decision in eval/plantdoc/class_map.yaml.
  • Agent eval grading is heuristic (deterministic keyword/numeric matching, no LLM judge) — cheap and reproducible, but crude; audit any grade from the committed per-question JSONL.

Author

Limawapang Jamir | B.Tech CSE, Bennett University (2020–2024) From Mokokchung, Nagaland 📧 limawapang8@gmail.com | LinkedIn | GitHub

About

AI-powered smart farming platform for Nagaland — crop disease detection, live market prices, planting calendar and government scheme finder

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages