Live mandi prices · 7-day AI forecasts · Sell/Wait decisions · Market discovery · Transport profit
Indian farmers lose an estimated ₹50,000 crores annually because they sell at the wrong time, at the wrong market, to the wrong buyer. A tomato farmer in Salem might sell at ₹35/kg locally while Coimbatore pays ₹42/kg — but he doesn't know that. And even if he did, he can't tell whether prices will climb further next week, or whether the transport costs will eat the profit.
AgriPrice AI puts that intelligence in his pocket. It pulls live government mandi prices, runs a 4-model AI ensemble to forecast the next 7 days, tells the farmer whether to sell now or wait, finds nearby markets ranked by profit after transport, and does it all in Tamil.
- Screenshots & Demo
- Key Features
- Architecture
- Tech Stack
- Project Structure
- Getting Started
- Environment Variables
- Running with Docker
- API Overview
- ML Pipeline
- Database
- Deployment
- How It Works End-to-End
- Future Improvements
- Contributing
- License
Pulls commodity prices from the Government of India's Open Data API (data.gov.in) every 6 hours via automated cron job. 100+ commodity name mappings across 38+ Tamil Nadu Uzhavar Sandhai APMC markets. Prices are converted from quintal rates to per-kg and stored in PostgreSQL. The mobile app caches prices locally for offline access.
Four independent ML models run on 90 days of historical price data and produce a 7-day forecast with confidence intervals:
| Model | Weight | Strength |
|---|---|---|
| Amazon Chronos | 40% | Zero-shot foundation model — handles any crop without retraining |
| Facebook Prophet | 30% | Captures weekly and seasonal price cycles |
| Linear Regression | 20% | Fast baseline for simple trends |
| Moving Average | 10% | Noise smoother and stability anchor |
If a model fails (insufficient data, timeout), its weight redistributes to the remaining models automatically.
Compares today's price against the AI-predicted peak over the next 7 days. If the peak exceeds the current price by more than 2%, it says WAIT with a human-readable explanation in English and Tamil. Otherwise, SELL NOW. The reasoning includes the predicted peak date and expected gain.
Uses the phone's GPS and PostGIS spatial queries (ST_DWithin) to find mandis within a configurable radius. Each market is ranked by net profit after transport costs — not just by distance or raw price.
Uses OpenRouteService for real road distances (not straight-line), factors in truck capacity, fuel cost per km, and loading charges.
Example:
Tomato 500kg — Salem (₹35/kg) → Coimbatore (₹42/kg, 85km)
Transport cost: ₹1.27/kg
Net Profit: ₹2,862
Set a target price for any crop at any market. An hourly cron job monitors all active alerts and fires push notifications via Firebase Cloud Messaging when thresholds are crossed.
Pulls OpenWeatherMap forecasts (temperature, rainfall, humidity) and feeds them into the ML models as features, improving prediction accuracy for weather-sensitive crops.
Full localization with ARB files. Voice-to-text search for farmers who find typing difficult. Every recommendation, alert message, and crop name is available in both languages.
Browse available trucks with capacity and rate details, book directly from the app, and track bookings.
Prices and crop data are cached on-device via SharedPreferences. Core browsing works without internet — predictions require connectivity.
┌──────────────────────────────────┐
│ Flutter Mobile App │
│ Riverpod · GoRouter · Dio │
│ 22+ screens · offline cache │
└──────────────┬───────────────────┘
│ REST / JSON
│ Firebase Bearer Token
▼
┌──────────────────────────────────┐
│ NestJS Backend API │
│ 13 modules · Firebase Auth │
│ TypeORM · PostGIS queries │
│ Swagger at /api/docs │
└──────┬──────────┬────────────────┘
│ │
▼ ▼
┌────────────┐ ┌──────────────────┐
│ PostgreSQL │ │ FastAPI ML │
│ 15+PostGIS │ │ Service │
│ 12 tables │ │ │
│ 38+markets │ │ Chronos · Prophet │
├────────────┤ │ LinReg · MovAvg │
│ Redis 7 │ │ Ensemble blend │
│ (cache) │ └──────────────────┘
└────────────┘
External APIs:
├─ data.gov.in ───── Live mandi commodity prices (6h cron)
├─ OpenWeatherMap ── Temperature, rainfall, humidity
├─ OpenRouteService Road distances & travel times
└─ Firebase ──────── Auth (Google + Email) · Cloud Messaging
The mobile app communicates with the NestJS backend over REST. The backend handles authentication (Firebase ID token verification via JWT guard), serves crop/market/price data from PostgreSQL, and proxies prediction requests to the Python ML service. Predictions are cached in the database for 24 hours. The ML service is stateless — it receives historical prices and weather context in the request body and returns a 7-day forecast.
User taps "Predict" on Tomato
│
├─ Flutter: GET /predictions/:cropId/markets/:marketId/forecast
│
├─ NestJS: Check DB for cached forecast (generated today?)
│ ├─ HIT → Return cached prediction
│ └─ MISS → Continue ↓
│
├─ Fetch 90-day historical prices from PostgreSQL
├─ Fetch weather forecast from OpenWeatherMap
│
├─ POST to ML Service /predict
│ ├─ Chronos → [36.5, 38.0, 42.0, 41.0, 39.5, 38.0, 37.0]
│ ├─ Prophet → [36.0, 37.5, 41.0, 40.5, 39.0, 37.5, 36.5]
│ ├─ LinReg → [36.8, 38.5, 43.0, 42.0, 40.0, 38.5, 37.2]
│ └─ MovAvg → [36.2, 37.5, 40.8, 40.0, 38.9, 37.8, 36.9]
│
├─ Weighted ensemble → 7-day forecast + confidence intervals
├─ Cache in DB → Return to Flutter
└─ Render chart
| Technology | Purpose |
|---|---|
| Flutter 3.x / Dart | Cross-platform mobile framework |
| Riverpod | State management |
| GoRouter | Declarative navigation |
| Dio | HTTP client with auth interceptors |
| fl_chart | Price charts and visualizations |
| Geolocator | GPS location |
| speech_to_text | Voice input for search |
| SharedPreferences | Offline price cache |
| Firebase Auth | Google Sign-In + Email/Password |
| intl + flutter_localizations | English and Tamil (ARB-based) |
| Technology | Purpose |
|---|---|
| NestJS 10.x / TypeScript | REST API framework |
| TypeORM | Database ORM with migrations |
| Passport + JWT | Authentication strategy |
| @nestjs/schedule | Cron jobs (mandi ingestion, alert monitoring) |
| Swagger / OpenAPI | Auto-generated API documentation |
| Axios | HTTP client for external APIs |
| firebase-admin | Firebase ID token verification, FCM push |
| csv-parser | Historical price data loading |
| Technology | Purpose |
|---|---|
| PostgreSQL 15 | Primary data store |
| PostGIS 3.3 | Spatial queries for market discovery |
| Redis 7 | Caching layer |
| Technology | Purpose |
|---|---|
| FastAPI 0.104 | ML service API framework |
| Amazon Chronos (transformers) | Zero-shot time-series forecasting |
| Facebook Prophet | Seasonality-aware forecasting |
| scikit-learn | Linear regression model |
| PyTorch 2.1 | Deep learning backend for Chronos |
| pandas / numpy | Data processing |
| Technology | Purpose |
|---|---|
| Docker Compose | Container orchestration (dev & prod) |
| Kubernetes | Production manifests (deployments, ingress, secrets) |
| Nginx | Reverse proxy with SSL termination (production) |
agri_app/
├── mobile/ # Flutter app
│ └── lib/
│ ├── main.dart # Firebase init, Riverpod scope, entry point
│ ├── config/ # GoRouter routes, theme, constants
│ ├── core/ # Auth service, Dio client, storage utils
│ ├── data/
│ │ ├── data_sources/
│ │ │ ├── remote/ # 10 API clients (crop, market, prediction, alert...)
│ │ │ └── local/ # SharedPreferences offline cache
│ │ ├── models/ # 12 Dart data models
│ │ └── repositories/ # Repository abstractions
│ ├── domain/ # Use cases
│ ├── presentation/
│ │ ├── screens/ # 22+ screens (home, prices, predictions, markets...)
│ │ ├── providers/ # 11 Riverpod providers
│ │ └── widgets/ # Reusable cards, charts, forms
│ └── l10n/ # ARB localization files (EN + TA)
│
├── backend/ # NestJS API
│ └── src/
│ ├── main.ts # Bootstrap, Firebase Admin, Swagger, CORS
│ ├── app.module.ts # Root module (13 feature modules)
│ ├── config/ # DB, JWT, Redis, Swagger config
│ ├── common/ # Guards, decorators, pipes, filters
│ └── modules/
│ ├── auth/ # Firebase sync, JWT guard
│ ├── crops/ # Crop catalog, prices, history
│ ├── markets/ # PostGIS nearby search, profit ranking
│ ├── predictions/ # ML client, forecast cache, sell/wait
│ ├── alerts/ # CRUD + hourly cron price monitor
│ ├── transport/ # Trucks & bookings
│ ├── routing/ # OpenRouteService road distances
│ ├── recommendations/ # Transport profit calculation
│ ├── weather/ # OpenWeatherMap integration
│ ├── mandi-data/ # data.gov.in ingestion (6h cron)
│ ├── ml-service/ # HTTP wrapper for Python ML
│ ├── seed/ # Database bootstrap seeder
│ └── notifications/ # FCM push notifications
│
├── ml-service/ # Python ML microservice
│ └── app/
│ ├── main.py # FastAPI — POST /predict, GET / (health)
│ ├── config.py # Model weights, forecast horizon
│ ├── services/ # Prediction orchestration
│ ├── models/ # Chronos, Prophet, LinReg, MovAvg, Ensemble
│ ├── schemas/ # Pydantic request/response validation
│ └── utils/ # Data cleaning, feature engineering, metrics
│
├── deployment/
│ ├── docker/ # Multi-stage Dockerfiles
│ ├── kubernetes/ # K8s manifests (deployments, ingress, secrets)
│ ├── scripts/ # DB backup, seed, setup scripts
│ ├── docker-compose.yml # Dev deployment
│ └── docker-compose.prod.yml # Prod with Nginx + SSL
│
├── docker-compose.yml # Quick-start: all 4 services
└── start.ps1 # One-click Windows launcher
- Docker Desktop — PostgreSQL, Redis, and ML service run in containers
- Node.js 18+ — NestJS backend
- Flutter SDK 3.x — Mobile app
- Firebase project — with Authentication enabled (Email/Password + Google Sign-In)
git clone https://github.com/adithyan-css/Agri_app.git
cd Agri_app
.\start.ps1This script handles everything: starts Docker Desktop if needed, brings up PostgreSQL/Redis/ML containers, waits for health checks, starts the NestJS backend, sets up ADB port forwarding, and launches the Flutter app on your connected device.
Options:
.\start.ps1 # Auto-detect Android device
.\start.ps1 -Device chrome # Run on Chrome
.\start.ps1 -SkipFlutter # Start services only1. Clone and start infrastructure:
git clone https://github.com/adithyan-css/Agri_app.git
cd Agri_app
docker-compose up -d db redis ml-service2. Set up the backend:
cd backend
npm install
cp .env.example .env
# Edit .env with your API keys (see Environment Variables below)3. Start the backend:
npx nest startBackend runs at http://localhost:3000. Swagger docs at http://localhost:3000/api/docs.
4. Set up Firebase:
- Create a project at console.firebase.google.com
- Enable Email/Password and Google Sign-In under Authentication
- Download
google-services.json→ place inmobile/android/app/ - Generate a service account key → place in
backend/asfirebase-service-account.json - Run
flutterfire configurefrom themobile/directory
5. Run the Flutter app:
cd mobile
flutter pub get
flutter runFor a physical Android device via USB:
adb reverse tcp:3000 tcp:3000 # Backend
adb reverse tcp:8000 tcp:8000 # ML Service
flutter runPort 3000 in use:
# Linux/Mac
lsof -ti:3000 | xargs kill -9
# Windows PowerShell
Get-NetTCPConnection -LocalPort 3000 | Select -Expand OwningProcess | % { Stop-Process -Id $_ -Force }Docker containers won't start:
docker-compose down -v
docker-compose up -dFlutter build errors:
flutter clean && flutter pub get && flutter run| Variable | Required | Description |
|---|---|---|
PORT |
No | Server port (default: 3000) |
DB_HOST |
Yes | PostgreSQL host (default: localhost) |
DB_PORT |
Yes | PostgreSQL port (default: 5432) |
DB_USERNAME |
Yes | Database user |
DB_PASSWORD |
Yes | Database password |
DB_DATABASE |
Yes | Database name (default: agriprice) |
DB_SYNC |
No | TypeORM schema sync — set false in production |
JWT_SECRET |
Yes | JWT signing key |
ML_SERVICE_URL |
Yes | Python ML service URL (default: http://localhost:8000) |
OPENWEATHER_API_KEY |
Yes | OpenWeatherMap API key |
DATA_GOV_API_KEY |
Yes | data.gov.in API key for mandi prices |
OPENROUTE_API_KEY |
Yes | OpenRouteService API key |
A template is provided at backend/.env.example — copy it and fill in your keys.
The root docker-compose.yml starts the full stack:
docker-compose up -d| Container | Port | Image |
|---|---|---|
| PostgreSQL 15 + PostGIS | 5432 | postgis/postgis:15-3.3 |
| Redis 7 | 6379 | redis:7-alpine |
| ML Service | 8000 | Built from ./ml-service/Dockerfile |
| Backend | 3000 | Built from ./backend/Dockerfile |
PostgreSQL data persists in a named volume (pgdata).
cd deployment
docker-compose -f docker-compose.prod.yml up -dProduction adds:
- Nginx reverse proxy with SSL termination (ports 80/443)
- Redis password authentication
restart: alwayson all services- Environment variables via
.envfile substitution NODE_ENV=production,ML_DEBUG=false
Base URL: http://localhost:3000/api/v1
Auth: All endpoints require Authorization: Bearer <firebase_token> header.
Docs: Swagger UI at http://localhost:3000/api/docs
| Method | Endpoint | Description |
|---|---|---|
| POST | /auth/sync |
Sync Firebase user to local database |
| GET | /auth/profile |
Get current user profile |
| Method | Endpoint | Description |
|---|---|---|
| GET | /crops |
All crops catalog |
| GET | /crops/market/:marketId/prices |
Latest price for every crop at a market |
| GET | /crops/:cropId/markets/:marketId/latest-price |
Latest price for one crop at one market |
| GET | /crops/:cropId/markets/:marketId/history?days=30 |
Historical price data |
| Method | Endpoint | Description |
|---|---|---|
| GET | /markets |
All active markets |
| GET | /markets/nearby?lat=&lon=&radius=&cropId= |
Nearby markets ranked by profit |
| Method | Endpoint | Description |
|---|---|---|
| GET | /predictions/:cropId/markets/:marketId/forecast |
7-day AI forecast with confidence intervals |
| GET | /predictions/:cropId?marketId= |
Sell/Wait recommendation |
| Method | Endpoint | Description |
|---|---|---|
| POST | /alerts |
Create price alert |
| GET | /alerts |
Get user's active alerts |
| PATCH | /alerts/:id |
Toggle alert status |
| DELETE | /alerts/:id |
Deactivate alert |
| Method | Endpoint | Description |
|---|---|---|
| GET | /transport/available |
Available trucks |
| POST | /transport/book |
Book a truck |
| GET | /transport/my-bookings |
User's bookings |
| Method | Endpoint | Description |
|---|---|---|
| POST | /intelligence/transport-profit |
Net profit calculator (manual distance) |
| POST | /transport-profit |
Net profit with real road distance (OpenRouteService) |
| Method | Endpoint | Description |
|---|---|---|
| GET | /weather?lat=&lon= |
Weather data for coordinates |
| Method | Endpoint | Description |
|---|---|---|
| GET | /users/me/preferred-market |
Get preferred market |
| PATCH | /users/me/preferred-market |
Set preferred market |
The Python ML service (ml-service/) runs on FastAPI and exposes a single prediction endpoint at POST /predict.
Chronos (40% weight) — Amazon's zero-shot time-series foundation model from the Hugging Face transformers library. Works on any crop without fine-tuning. Strongest contributor to the ensemble.
Prophet (30% weight) — Facebook's additive regression model. Captures weekly and yearly seasonality patterns common in agricultural commodity cycles. Requires at least 14 data points.
Linear Regression (20% weight) — scikit-learn OLS regression on engineered features (calendar, price lag, rolling stats). Fast, interpretable baseline.
Moving Average (10% weight) — Weighted moving average with exponential decay. Smooths daily noise and serves as a stability anchor.
predicted_price[day] = Σ(model_price[day] × weight) / Σ(active_weights)
If a model fails, its weight is redistributed proportionally to the remaining models.
Confidence score — Based on the average spread between upper and lower bounds relative to the predicted price. Tighter bounds = higher confidence.
Trend classification:
| Condition | Trend | Action |
|---|---|---|
| Predicted peak > current × 1.02 | UP | WAIT — prices rising |
| Predicted peak < current × 0.98 | DOWN | SELL — prices falling |
| Otherwise | STABLE | SELL — no significant movement |
The utils/feature_engineer.py module generates features for the regression model:
- Calendar features (day of week, month, quarter)
- Price features (lag values, rolling mean, rolling std, rate of change)
- Weather features (temperature, rainfall, humidity)
- Supply features (arrival volume trends)
PostgreSQL 15 with the PostGIS 3.3 extension. 12 tables:
| Table | Purpose |
|---|---|
users |
Firebase-synced accounts (firebase_uid, phone, name, role, GPS, FCM token) |
otp_verifications |
Phone OTP codes with expiry |
crops |
Crop catalog — bilingual names (EN/TA), category, shelf life |
markets |
Market locations — bilingual names, district, state, PostGIS GEOGRAPHY(Point) |
crop_prices |
Historical price records per crop × market × date, quality grade, source |
market_arrivals |
Volume of crop arrivals at each market per day |
weather_data |
Cached weather forecasts per market |
predictions |
AI forecast cache — predicted price, confidence, bounds, model |
recommendations |
Sell/Wait recommendations with bilingual reasoning |
user_preferences |
Per-user crop watchlist with target prices |
alerts |
Price alerts — crop, type, bilingual messages, read status |
notifications |
Push notification log — title, body, delivery status |
Key indexes: GIST spatial index on markets.location for fast nearby queries. Composite index on crop_prices(crop_id, market_id, record_date).
On first startup, the backend seeds:
- 50+ crops with English and Tamil names across vegetables, fruits, grains, and spices
- 38+ Tamil Nadu Uzhavar Sandhai APMC markets with verified GPS coordinates
- Historical price records per crop-market pair
- Sample trucks with capacity and rates
The mandi data cron job then ingests live prices from data.gov.in every 6 hours, automatically matching 100+ commodity names to seeded crops and converting quintal prices to per-kg.
| Source | Data | Method |
|---|---|---|
| data.gov.in | Live mandi commodity prices | 6-hour cron, 100+ TN commodity mappings, quintal→kg conversion |
| OpenWeatherMap | Temperature, rainfall, humidity | On-demand per market, fed into ML models |
| OpenRouteService | Road distances, travel times | Driving profile, used for transport profit |
| Firebase | User auth, push notifications | Google + Email auth, FCM |
Development:
docker-compose up -dProduction (with Nginx, SSL, Redis auth):
cd deployment
docker-compose -f docker-compose.prod.yml up -dKubernetes manifests are provided in deployment/kubernetes/:
| Manifest | Purpose |
|---|---|
backend-deployment.yaml |
NestJS backend pods + service |
ml-service-deployment.yaml |
ML service pods + service |
postgres-deployment.yaml |
PostgreSQL + PostGIS with PVC |
redis-deployment.yaml |
Redis with PVC |
ingress.yaml |
Ingress controller routing |
secrets.yaml |
Environment secrets (DB creds, API keys, JWT) |
cd deployment/scripts
./backup-db.shA farmer opens the app → Firebase authenticates them → the backend syncs their user record.
They browse prices → the app fetches the crop list and latest prices from the backend, which serves data from PostgreSQL (seeded data + live mandi prices ingested every 6 hours).
They tap "Predict" on a crop → the Flutter provider calls the forecast endpoint → the backend checks if today's forecast exists in the DB cache. If not, it fetches 90 days of historical prices, grabs the weather forecast from OpenWeatherMap, and POSTs everything to the Python ML service. The ML service runs all 4 models, blends their outputs, and returns a 7-day forecast with confidence intervals. The backend caches the result and returns it. The app renders a line chart.
They tap "AI Analysis" → the backend compares the current price against the forecast peak. If prices are trending up by >2%, it says WAIT with a human-readable reason in English and Tamil. Otherwise, SELL.
They tap "Nearby Markets" → the app sends GPS coordinates → the backend runs a PostGIS spatial query, fetches the latest price at each nearby market, calls OpenRouteService for real road distances, and returns markets ranked by net profit after transport.
They set a price alert → the backend stores it. An hourly cron job checks all active alerts against the latest prices and sends a push notification via Firebase Cloud Messaging when a threshold crosses.
- ML model persistence — Save trained model weights to avoid retraining on every cold start
- Redis caching layer — Cache frequently accessed price queries and crop lists beyond DB caching
- Rate limiting — Protect endpoints from abuse with request throttling
- Push notification tracking — Monitor FCM delivery success rates and retry failures
- WebSocket streaming — Real-time price updates instead of polling
- Satellite imagery — NDVI crop health monitoring via remote sensing
- On-device ML — TensorFlow Lite for fully offline predictions
- Additional languages — Hindi, Kannada, Telugu localization
- SMS fallback — Price alerts via SMS for low-connectivity areas
- Farmer marketplace — Direct farmer-to-buyer transactions
- Government MSP alerts — Notify when prices fall below Minimum Support Price
- Web dashboard — Analytics portal for market trends and historical patterns
- Fork the repo
- Create a branch:
git checkout -b feature/your-feature - Make changes and commit:
git commit -m "Add: description" - Push and open a Pull Request
| Layer | Tool | Command |
|---|---|---|
| Backend (TypeScript) | Prettier + ESLint | cd backend && npm run lint |
| Mobile (Dart) | flutter_lints | cd mobile && flutter analyze |
| ML Service (Python) | PEP 8 / Black | cd ml-service && black app/ |
- Backend follows the NestJS module pattern — controller + service + entity per module
- Mobile follows Clean Architecture — presentation → domain → data
- ML models go in
ml-service/app/models/and must return[{mean, low, high}]per forecast day - Commit messages:
Add:,Fix:,Update:,Docs:
cd backend && npm test # Backend unit tests
cd mobile && flutter test # Widget and unit tests
cd ml-service && pytest # ML service testsMIT License. See LICENSE for details.
Built for Indian farmers. Technology for social good. 🌾



