diff --git a/.space.yaml b/.space.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f6c31959d40a5409dcea5ba66aace3acb3a89434 --- /dev/null +++ b/.space.yaml @@ -0,0 +1,9 @@ +--- +title: AgroMind Backend +sdk: docker +app_port: 8000 +emoji: 🌾 +colorFrom: green +colorTo: blue +pinned: false +license: isc diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..d4ec6cc844e17347bc7d8012781b6c66ec303d7b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,87 @@ +# Unified Dockerfile for Hugging Face Spaces deployment +# Runs BOTH the Node.js backend (port 7860) and the Python AI backend (port 5000) +# in a single container so ML model requests are proxied to localhost:5000. + +FROM node:22-bookworm-slim + +WORKDIR /app + +# Install Python 3, pip and build deps needed by both stacks +RUN apt-get update && apt-get install -y --no-install-recommends \ + python3 \ + python3-pip \ + python3-sklearn \ + build-essential \ + pkg-config \ + wget \ + curl \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# ── Node.js backend ────────────────────────────────────────────────────────── +COPY backend/package*.json ./ +ENV NODE_ENV=production +RUN npm install --omit=dev + +COPY backend/ ./ + +# ── Python AI backend ──────────────────────────────────────────────────────── +COPY ai-backend/requirements.txt /ai-backend/requirements.txt +RUN pip3 install --no-cache-dir --break-system-packages -r /ai-backend/requirements.txt + +COPY ai-backend/ /ai-backend/ + +# Point the Node backend at the co-located AI service +ENV AI_BACKEND_URL=http://localhost:5000 + +# ── Create non-root user (uid 1000) for HF Spaces ─────────────────────────── +RUN set -ex && \ + if ! getent group 1000 > /dev/null 2>&1; then \ + groupadd -g 1000 nodejs; \ + fi && \ + GROUP_NAME=$(getent group 1000 | cut -d: -f1) && \ + if ! getent passwd 1000 > /dev/null 2>&1; then \ + useradd -m -u 1000 -g ${GROUP_NAME} appuser; \ + fi && \ + chown -R 1000:1000 /app /ai-backend + +# ── Startup script ─────────────────────────────────────────────────────────── +# Launches the Python AI backend in the background, then starts Node.js +COPY <<'EOF' /start.sh +#!/bin/sh +echo "[startup] Starting AI backend on port 5000..." +cd /ai-backend && gunicorn --bind 0.0.0.0:5000 --workers 2 --timeout 180 --preload app:app & +AI_PID=$! + +# Wait for AI backend to be ready (up to 30 s) +READY=0 +for i in $(seq 1 30); do + if wget -q --spider http://127.0.0.1:5000/health 2>/dev/null; then + echo "[startup] AI backend is ready." + READY=1 + break + fi + # Exit if the AI backend process died during startup + if ! kill -0 $AI_PID 2>/dev/null; then + echo "[startup] AI backend process exited unexpectedly." + break + fi + sleep 1 +done +if [ "$READY" -eq 0 ] && kill -0 $AI_PID 2>/dev/null; then + echo "[startup] AI backend health check timed out after 30s; proceeding anyway." +fi + +echo "[startup] Starting Node.js backend on port 7860..." +cd /app && exec node server.js +EOF +RUN chmod +x /start.sh + +USER 1000 + +EXPOSE 7860 + +HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:7860/health || exit 1 + +CMD ["/start.sh"] diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9e7abff41816b35930290f6468e9b5247f2c3a23 --- /dev/null +++ b/README.md @@ -0,0 +1,333 @@ +--- +title: Agromind Backend +colorFrom: green +colorTo: blue +sdk: docker +app_port: 7860 +--- + +# AgroMind: Where Farmers Meet AI & Technology for a Greener Future! 🌾 + +![Alt Landing Page](frontend/src/assets/LandingPage.png) + +**AgroMind** is an innovative platform designed to empower farmers by connecting them with agricultural experts, AI-powered tools, and modern technology. Our goal is to make farming smarter, more efficient, and more sustainable. + +## πŸš€ Key Features + +### Core Features +- **Expert Consultations** - Real-time video calls and chat with agricultural experts +- **AI-Powered Recommendations** - Crop, fertilizer, and yield predictions +- **Task Management** - Goal-based scheduling and tracking +- **Weather Alerts** - Real-time weather updates and recommendations +- **Revenue Tracking** - Income and expense management + +### New Features (v2.0) + +| Feature | Description | +|---------|-------------| +| **Value Chain Marketplace** | Connect farmers, processors, and buyers for oilseed by-products | +| **Hedging Platform** | Virtual hedging, price risk management, forward contracts | +| **Crop Economics** | Comparative crop analysis, govt schemes, profitability simulation | +| **Oil Palm Advisory** | Farmer profiling, ROI projections, gestation support tracking | +| **Yield Optimization** | AI-driven yield predictions with intervention suggestions | +| **Tariff Simulator** | Model impact of customs duty changes on prices | +| **Millets Marketplace** | Specialized marketplace with traceability and offline support | +| **CRM Machine Tracking** | Real-time tracking of crop residue management machines | +| **CROPIC** | AI-based crop damage assessment for insurance | + +## πŸ—οΈ Architecture + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Frontend β”‚ +β”‚ (React.js + Vite) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β–Ό β–Ό β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Backend β”‚ β”‚ AI Backendβ”‚ β”‚ Smart Contractsβ”‚ +β”‚ Node.js β”‚ β”‚ Python β”‚ β”‚ Solidity β”‚ +β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ + β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ MongoDB β”‚ + β”‚ Redis β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +## πŸ“¦ Quick Start + +### Prerequisites +- Node.js 20+ +- Python 3.11+ +- Docker & Docker Compose (recommended) +- MongoDB + +### Local Development with Docker + +```bash +# Clone repository +git clone https://github.com/Anamitra-Sarkar/AgroMind.git +cd AgroMind + +# Copy environment file +cp .env.sample .env + +# Start all services +docker-compose up -d + +# Access applications +# Frontend: http://localhost:5173 +# Backend: http://localhost:8000 +# AI Backend: http://localhost:5000 +``` + +### Manual Setup + +```bash +# Backend +cd backend && npm install && npm run dev + +# AI Backend +cd ai-backend && pip install -r requirements.txt && python app.py + +# Frontend +cd frontend && npm install && npm run dev +``` + +## πŸ”§ Environment Variables + +See [.env.sample](.env.sample) for all required environment variables. + +### Key Variables + +| Variable | Description | +|----------|-------------| +| `MONGO_URL` | MongoDB connection string | +| `JWT_KEY` | JWT signing key | +| `FRONTEND_URL` | Frontend URL for CORS | +| `AI_BACKEND_URL` | AI backend URL | +| `OPENWEATHER_API_KEY` | OpenWeather API key | +| `GEMINI_API_KEY` | Google Gemini AI key | + +## πŸ› οΈ Technology Stack + +### Frontend +- React.js 18 + Vite +- TailwindCSS + Material-UI +- Chart.js + Recharts +- Socket.IO Client +- i18next (internationalization) + +### Backend +- Node.js + Express.js +- MongoDB + Mongoose +- Redis (caching) +- Socket.IO +- JWT Authentication + +### AI Backend +- Python + Flask +- PyTorch + scikit-learn +- LightGBM (price forecasting) +- ResNet (image classification) + +### Infrastructure +- Docker + Docker Compose +- GitHub Actions CI/CD +- Vercel (frontend hosting) +- Hugging Face Spaces (backend hosting) +- Prometheus + Grafana (monitoring) + +## πŸ“š API Documentation + +### Backend API Endpoints + +| Endpoint | Description | +|----------|-------------| +| `/api/auth/*` | Authentication | +| `/api/valuechain/*` | Marketplace | +| `/api/hedging/*` | Hedging platform | +| `/api/crop-economics/*` | Crop comparison | +| `/api/oilpalm/*` | Oil palm advisory | +| `/api/crm/*` | Machine tracking | +| `/api/millets/*` | Millets marketplace | + +### AI Backend Endpoints + +| Endpoint | Description | +|----------|-------------| +| `/ai/price-forecast` | Price predictions | +| `/ai/yield-predict` | Yield predictions | +| `/ai/tariff-simulate` | Tariff impact simulation | +| `/ai/cropic/analyze` | Crop damage analysis | +| `/crop_recommendation` | Crop recommendations | +| `/fertilizer_prediction` | Fertilizer suggestions | + +πŸ“„ Full API documentation: [docs/postman_collection.json](docs/postman_collection.json) + +## πŸ§ͺ Testing + +```bash +# Backend tests +cd backend && npm test + +# AI Backend tests +cd ai-backend && pytest tests/ -v + +# Frontend tests +cd frontend && npm test + +# E2E tests +cd frontend && npm run cypress:open + +# Smart contract tests +cd backend/contracts && npm test +``` + +### AI Backend Testing Details + +The AI backend now includes comprehensive test coverage with: + +**Test Coverage:** +- Unit tests for model predictions (`tests/test_models.py`) - 15 passing, 5 skipped +- Integration tests for all API endpoints (`tests/test_api_integration.py`) +- Existing validation tests (`tests/test_endpoints.py`) + +**Test Features:** +- Mocked models for fast, deterministic tests (no HF downloads) +- Retry logic testing with transient failures +- Error handling and exception logging validation +- Content-Type and JSON payload validation +- Model loading and caching tests + +**Run with Coverage:** +```bash +cd ai-backend +pytest tests/ -v --cov=. --cov-report=html +``` + +For detailed testing documentation and sample payloads, see [docs/TESTING.md](docs/TESTING.md). + +## πŸš€ Deployment + +### Frontend β†’ Vercel + +```bash +cd frontend +vercel --prod +``` + +### Hugging Face Spaces β†’ Backend only + +To push only the `backend` and `ai-backend` folders (avoid large frontend/binary files), use the helper script: + +Example: + +```bash +chmod +x scripts/push_to_hf.sh +./scripts/push_to_hf.sh https://huggingface.co/spaces// +``` + +This creates a temporary git repo containing only `backend` and `ai-backend` and force-pushes `main` to the provided remote. + +### GitHub Action (recommended) + +You can automate the push using the provided GitHub Action. It creates a temporary repo with only `backend` and `ai-backend` and pushes it to your Hugging Face Space. + +1. Add a repository secret named `HF_TOKEN` containing a Hugging Face token with repo write access. +2. Run the workflow manually from the Actions tab and provide the `hf_repo` input (e.g. `username/Agromind-backend`). + +Workflow options: +- **hf_branch**: target branch on the Hugging Face repo (default `main`). +- **force**: set to `true` to force-push the target branch (default `false`). Avoid force-push unless you intentionally want to overwrite history. +- **dry_run**: set to `true` to prepare the temporary repo and list files without pushing (default `false`). + +Recommended safe flow: +1. Run with `dry_run=true` to verify what will be pushed. +2. Run with `force=false` to push to a branch without overwriting history. If you specifically need to replace the remote branch, set `force=true`. + +The workflow file is `.github/workflows/auto-sync-to-hf.yml` β€” it also runs +automatically on every push to `main` that touches `backend/`, `ai-backend/`, +`Dockerfile`, `.space.yaml`, or `README.md`, so a manual run is only needed +for a dry run or to push to a non-default branch. + + +### Backend β†’ Hugging Face Spaces + +See [docs/deploy.md](docs/deploy.md) for detailed deployment instructions. + +### Required GitHub Secrets + +``` +VERCEL_TOKEN +VERCEL_ORG_ID +VERCEL_PROJECT_ID +HF_TOKEN +HF_BACKEND_SPACE_ID +HF_AI_BACKEND_SPACE_ID +``` + +## πŸ“ Project Structure + +``` +AgroMind/ +β”œβ”€β”€ frontend/ # React frontend +β”œβ”€β”€ backend/ # Node.js backend +β”‚ β”œβ”€β”€ routes/ # API routes +β”‚ β”œβ”€β”€ controllers/ # Route handlers +β”‚ β”œβ”€β”€ models/ # MongoDB models +β”‚ β”œβ”€β”€ middleware/ # Express middleware +β”‚ β”œβ”€β”€ socket/ # Socket.IO handlers +β”‚ └── contracts/ # Smart contracts +β”œβ”€β”€ ai-backend/ # Python AI backend +β”‚ β”œβ”€β”€ model/ # ML models +β”‚ └── tests/ # Python tests +β”œβ”€β”€ docs/ # Documentation +β”œβ”€β”€ config/ # Configuration files +β”œβ”€β”€ scripts/ # Utility scripts +└── docker-compose.yml # Local development +``` + +## πŸ“– Documentation + +- [Architecture](docs/architecture.md) - System design and diagrams +- [Deployment](docs/deploy.md) - Deployment instructions +- [Security](docs/security.md) - Security checklist +- [ML Models](docs/models.md) - Model documentation +- [Local Setup](docs/run_locally.md) - Local development guide + +## πŸ” Security + +- JWT-based authentication +- Rate limiting and CORS +- Input validation and sanitization +- Encrypted data storage +- Regular dependency scanning + +See [docs/security.md](docs/security.md) for the full security checklist. + +## 🀝 Contributing + +We welcome contributions! Please: + +1. Fork the repository +2. Create a feature branch (`git checkout -b feature/amazing-feature`) +3. Commit changes (`git commit -m 'Add amazing feature'`) +4. Push to branch (`git push origin feature/amazing-feature`) +5. Open a Pull Request + +## πŸ“„ License + +This project is licensed under the ISC License. + +## πŸ“ž Support + +For support, email support@agromind.app or join our community. + +--- + +**AgroMind: Empowering farmers with technology for a greener, smarter future!** 🌱 diff --git a/ai-backend/.gitignore b/ai-backend/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..2249c8add4452cd871a4a95a91bd4eb2a68730af --- /dev/null +++ b/ai-backend/.gitignore @@ -0,0 +1,4 @@ +venv/ +__pycache__/ +*.pyc +.venv/ \ No newline at end of file diff --git a/ai-backend/Dockerfile b/ai-backend/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..6a97b251aac5ead6f5d3e9e8ce6a33c4e54993c4 --- /dev/null +++ b/ai-backend/Dockerfile @@ -0,0 +1,45 @@ +# AI Backend Dockerfile +FROM python:3.11-slim as base + +WORKDIR /app + +# Install system dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + curl \ + && rm -rf /var/lib/apt/lists/* + +# Copy requirements first for caching +COPY requirements.txt . + +# Development stage +FROM base as development +RUN pip install --no-cache-dir -r requirements.txt +RUN pip install --no-cache-dir pytest pytest-cov httpx black flake8 isort +COPY . . +EXPOSE 5000 +CMD ["python", "-m", "flask", "run", "--host=0.0.0.0", "--port=5000", "--reload"] + +# Production stage +FROM base as production + +# Install production dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Copy application code +COPY . . + +# Create non-root user +RUN groupadd -r appuser && useradd -r -g appuser appuser && \ + chown -R appuser:appuser /app + +USER appuser + +EXPOSE 5000 + +# Health check +HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \ + CMD curl -f http://localhost:5000/health || exit 1 + +# Use gunicorn for production +CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "2", "--timeout", "120", "app:app"] diff --git a/ai-backend/app.py b/ai-backend/app.py new file mode 100644 index 0000000000000000000000000000000000000000..54bb7802f486634290da1790382eb54ebd89b9ca --- /dev/null +++ b/ai-backend/app.py @@ -0,0 +1,1609 @@ +"""app.py + +AI backend Flask app. All ML models are downloaded at runtime from +Hugging Face Hub β€” no local binary weights are required. +""" + +import io +import os +import json +import pickle +import logging +import time as _time + +import requests as _requests + +from flask import Flask, request, jsonify +from flask_cors import CORS +from PIL import Image +import torch +import joblib +import numpy as np +import pandas as pd +from huggingface_hub import hf_hub_download + +from model_utils import load_model_from_hf, predict + +# Import new infrastructure +from src.logging_config import setup_logging, log_exception +from src.error_handlers import register_error_handlers, validate_content_type, validate_json_payload +from src.models import manager as model_manager +from src.utils.retry_utils import retry_with_backoff, retry_model_inference + +# Setup structured logging +logger = setup_logging(level=logging.INFO) + +_start_time = _time.time() + +_HF_INFERENCE_RETRY_DELAYS = (1, 2, 4) # seconds between retries (3 attempts total) + + +def _call_hf_inference_api(api_url: str, headers: dict, data: bytes, timeout: int = 60) -> "_requests.Response": + """POST to a Hugging Face Inference API endpoint with retries on network/DNS errors. + + On persistent failure a :class:`requests.exceptions.RequestException` is + raised so callers can fall back to the local model path. + """ + last_exc: "_requests.exceptions.RequestException | None" = None + for attempt, retry_delay in enumerate((*_HF_INFERENCE_RETRY_DELAYS, None)): + try: + return _requests.post(api_url, headers=headers, data=data, timeout=timeout) + except _requests.exceptions.RequestException as exc: + last_exc = exc + if retry_delay is not None: + logger.warning( + "HF Inference API network error attempt %d/%d url=%s error=%s. " + "Retrying in %ds.", + attempt + 1, len(_HF_INFERENCE_RETRY_DELAYS) + 1, api_url, exc, retry_delay, + ) + _time.sleep(retry_delay) + else: + logger.error( + "HF Inference API failed after %d attempts url=%s error=%s. " + "Verify HF_TOKEN and network/DNS access from this Space.", + len(_HF_INFERENCE_RETRY_DELAYS) + 1, api_url, exc, + ) + raise _requests.exceptions.RequestException( + f"Network/DNS failure after {len(_HF_INFERENCE_RETRY_DELAYS) + 1} attempts: {last_exc}" + ) from last_exc + +app = Flask(__name__) +CORS(app) + +# Register centralized error handlers +register_error_handlers(app) + +# ── HF repo IDs (override via env vars if needed) ────────────────────────── +HF_REPO_CROP = os.environ.get( + "HF_REPO_CROP", "Arko007/agromind-crop-recommendation" +) +HF_REPO_FERTILIZER = os.environ.get( + "HF_REPO_FERTILIZER", "Arko007/agromind-fertilizer-prediction" +) +HF_REPO_LOAN = os.environ.get( + "HF_REPO_LOAN", "Arko007/agromind-loan-prediction" +) +HF_REPO_HARVEST = os.environ.get( + "HF_REPO_HARVEST", "Arko007/harvest-readiness-yolo11m" +) + +device = model_manager.get_device() + +# ── Models are lazy-loaded on first request directly from HF Hub ────────── +# Repos used: +# crop: Arko007/agromind-crop-recommendation +# disease: Arko007/nfnet-f1-plant-disease +# fertilizer: Arko007/agromind-fertilizer-prediction +# loan: Arko007/agromind-loan-prediction +try: + model_manager.initialize_models(load_all=False) +except Exception as e: + log_exception(logger, e, "Error during model manager init") + +logger.info("AI backend startup complete. Ready to serve requests.") + +# Mapping for crop types +crop_dict = { + 1: "Rice", 2: "Maize", 3: "Jute", 4: "Cotton", 5: "Coconut", 6: "Papaya", 7: "Orange", + 8: "Apple", 9: "Muskmelon", 10: "Watermelon", 11: "Grapes", 12: "Mango", 13: "Banana", + 14: "Pomegranate", 15: "Lentil", 16: "Blackgram", 17: "Mungbean", 18: "Mothbeans", + 19: "Pigeonpeas", 20: "Kidneybeans", 21: "Chickpea", 22: "Coffee" +} + +# Mapping for soil and crop types (fertilizer prediction) +soil_mapping = { + "Black": 0, + "Clayey": 1, + "Loamy": 2, + "Red": 3, + "Sandy": 4 +} + +crop_mapping = { + "Barley": 0, + "Cotton": 1, + "Ground Nuts": 2, + "Maize": 3, + "Millets": 4, + "Oil Seeds": 5, + "Paddy": 6, + "Pulses": 7, + "Sugarcane": 8, + "Tobacco": 9, + "Wheat": 10 +} + + +@app.route("/") +def index(): + return jsonify({"message": "Welcome to the AI Backend API"}) + + +@app.route('/health') +def health(): + # Get model status from model manager + model_status = model_manager.get_model_status() + + return jsonify({ + "status": "ok", + "version": "1.0.0", + "uptime": int(_time.time() - _start_time), + "models_loaded": model_status + }) + + +@app.route("/predict_disease", methods=["POST"]) +def predict_route(): + # Lazy-load disease model from Arko007/nfnet-f1-plant-disease on first call + model = model_manager.get_model('disease_model', auto_load=True) + labels = model_manager.get_model('disease_labels', auto_load=True) or [] + remedies = model_manager.get_model('disease_remedies', auto_load=True) or {} + if model is None: + return jsonify({"error": "Disease model unavailable β€” HF Hub download may have failed"}), 503 + if "file" not in request.files: + return jsonify({"error": "no file part"}), 400 + file = request.files["file"] + if file.filename == "": + return jsonify({"error": "empty filename"}), 400 + try: + img_bytes = file.read() + pil_img = Image.open(io.BytesIO(img_bytes)).convert("RGB") + + # Determine crop filter from filename if present + filename_lower = file.filename.lower() + crop_filter = None + crop_mapping = { + "wheat": "Wheat__", + "potato": "Potato__", + "rice": "Rice__", + "corn": "Corn__", + "apple": "Apple__", + "cassava": "Cassava__", + "cherry": "Cherry__", + "chili": "Chili__", + "chilli": "Chili__", + "coffee": "Coffee__", + "cucumber": "Cucumber__", + "guava": "Gauva__", + "gauva": "Gauva__", + "grape": "Grape__", + "jamun": "Jamun__", + "lemon": "Lemon__", + "mango": "Mango__", + "peach": "Peach__", + "pepper": "Pepper_bell__", + "bell": "Pepper_bell__", + "pomegranate": "Pomegranate__", + "soybean": "Soybean__", + "soy": "Soybean__", + "strawberry": "Strawberry", + "sugarcane": "Sugarcane__", + "tea": "Tea__", + "tomato": "Tomato__" + } + for kw, prefix in crop_mapping.items(): + if kw in filename_lower: + crop_filter = [lbl for lbl in labels if lbl.startswith(prefix)] + logger.info("Filtering classes for prefix '%s' based on filename '%s'", prefix, file.filename) + break + + top_label, confidence, topk = predict(model, pil_img, labels, device, topk=5, crop_filter=crop_filter) + + # Try to find remedies in a robust way to handle label-format differences + def find_remedy(label, remedies_dict): + if not remedies_dict: + return None + # direct match + if label in remedies_dict: + return remedies_dict[label] + # try common normalization variants + variants = set() + variants.add(label.replace('__', '___')) + variants.add(label.replace('___', '__')) + variants.add(label.replace('(', '').replace(')', '')) + variants.add(label.replace(' ', '_')) + variants.add(label.replace('-', '_')) + variants.add(label.lower()) + variants.add(label.replace('__', ' ').lower()) + for v in variants: + if v in remedies_dict: + return remedies_dict[v] + # try case-insensitive match + for k in remedies_dict.keys(): + if k.lower() == label.lower(): + return remedies_dict[k] + return None + + remedy = find_remedy(top_label, remedies) + response = { + "label": top_label, + "confidence": confidence, + "remedies": remedy, + "topk": [{"label": l, "confidence": float(c)} for l, c in topk] + } + return jsonify(response) + except Exception as e: + return jsonify({"error": str(e)}), 500 + + +@app.route("/crop_recommendation", methods=["POST"]) +def crop_recommendation(): + """Crop recommendation endpoint with robust error handling and logging.""" + request_start = _time.time() + + # Validate Content-Type + is_valid, error_response = validate_content_type(request) + if not is_valid: + return jsonify(error_response), error_response['status'] + + # Lazy-load from Arko007/agromind-crop-recommendation on first call (cached after) + crop_predict_model = model_manager.get_model('crop_model', auto_load=True) + crop_predict_sc = model_manager.get_model('crop_standard_scaler', auto_load=True) + crop_predict_ms = model_manager.get_model('crop_minmax_scaler', auto_load=True) + # Check model availability + if crop_predict_model is None or crop_predict_sc is None or crop_predict_ms is None: + logger.error("Crop recommendation: Model not loaded") + return jsonify({ + "error": "Crop prediction model not loaded", + "message": "Service temporarily unavailable. Please try again later." + }), 500 + + try: + # Validate JSON payload + required_fields = ['N', 'P', 'K', 'temperature', 'humidity', 'ph', 'rainfall'] + is_valid, result = validate_json_payload(request, required_fields) + if not is_valid: + return jsonify(result), result['status'] + + data = result + logger.info(f"Crop recommendation request: N={data.get('N')}, P={data.get('P')}, K={data.get('K')}") + + # Extract and validate features + try: + N = float(data['N']) + P = float(data['P']) + K = float(data['K']) + temp = float(data['temperature']) + humidity = float(data['humidity']) + ph = float(data['ph']) + rainfall = float(data['rainfall']) + except (ValueError, TypeError) as e: + logger.warning(f"Invalid data type in crop recommendation: {e}") + return jsonify({ + "error": "Invalid data type", + "message": f"All numeric fields must be valid numbers: {str(e)}" + }), 400 + + # Validate ranges + if not (0 <= N <= 100 and 0 <= P <= 100 and 0 <= K <= 100): + return jsonify({"error": "N, P, K values must be between 0 and 100"}), 400 + if not (-10 <= temp <= 50): + return jsonify({"error": "Temperature must be between -10 and 50Β°C"}), 400 + if not (0 <= humidity <= 100): + return jsonify({"error": "Humidity must be between 0 and 100%"}), 400 + if not (0 <= ph <= 14): + return jsonify({"error": "pH must be between 0 and 14"}), 400 + if not (0 <= rainfall <= 500): + return jsonify({"error": "Rainfall must be between 0 and 500mm"}), 400 + + # Prepare features for prediction + feature_list = [N, P, K, temp, humidity, ph, rainfall] + single_pred = np.array(feature_list).reshape(1, -1) + + # Make prediction with retry wrapper + @retry_model_inference(max_attempts=2) + def make_prediction(): + scaled_features = crop_predict_ms.transform(single_pred) + final_features = crop_predict_sc.transform(scaled_features) + return crop_predict_model.predict(final_features) + + prediction = make_prediction() + + # Get crop name + if prediction[0] in crop_dict: + crop = crop_dict[prediction[0]] + result = f"{crop} is the best crop to be cultivated right there." + + elapsed_ms = int((_time.time() - request_start) * 1000) + logger.info(f"Crop recommendation successful: {crop} (took {elapsed_ms}ms)") + + return jsonify({ + "success": True, + "crop": crop, + "message": result, + "prediction_id": int(prediction[0]), + "input_data": { + "nitrogen": N, + "phosphorus": P, + "potassium": K, + "temperature": temp, + "humidity": humidity, + "ph": ph, + "rainfall": rainfall + } + }), 200 + else: + logger.warning(f"Crop recommendation: Unknown prediction ID {prediction[0]}") + return jsonify({ + "success": False, + "message": "Could not determine the best crop with the provided data." + }), 200 + + except Exception as e: + elapsed_ms = int((_time.time() - request_start) * 1000) + log_exception(logger, e, f"Crop recommendation failed after {elapsed_ms}ms") + return jsonify({ + "error": "Internal server error", + "message": "An unexpected error occurred during prediction. Please try again later." + }), 500 + + +@app.route('/fertilizer_prediction', methods=['POST']) +def fertilizer_prediction(): + # Lazy-load from Arko007/agromind-fertilizer-prediction on first call + classifier_model = model_manager.get_model('fertilizer_classifier', auto_load=True) + label_encoder = model_manager.get_model('fertilizer_label_encoder', auto_load=True) + if classifier_model is None or label_encoder is None: + return jsonify({"error": "Fertilizer prediction model not loaded"}), 503 + try: + # Get JSON data from request + data = request.get_json() + + # Validate required fields + required_fields = ['temperature', 'humidity', 'moisture', 'soil_type', 'crop_type', 'nitrogen', 'potassium', 'phosphorus'] + for field in required_fields: + if field not in data: + return jsonify({ + "error": f"Missing required field: {field}" + }), 400 + + # Extract features + temp = int(data['temperature']) + humi = int(data['humidity']) + mois = int(data['moisture']) + soil_type = data['soil_type'] + crop_type = data['crop_type'] + nitro = int(data['nitrogen']) + pota = int(data['potassium']) + phosp = int(data['phosphorus']) + + # Validate soil type + if soil_type not in soil_mapping: + return jsonify({ + "error": f"Invalid soil_type. Must be one of: {list(soil_mapping.keys())}" + }), 400 + + # Validate crop type + if crop_type not in crop_mapping: + return jsonify({ + "error": f"Invalid crop_type. Must be one of: {list(crop_mapping.keys())}" + }), 400 + + # Validate ranges + if not (0 <= temp <= 100): + return jsonify({"error": "Temperature must be between 0 and 100"}), 400 + if not (0 <= humi <= 100): + return jsonify({"error": "Humidity must be between 0 and 100"}), 400 + if not (0 <= mois <= 100): + return jsonify({"error": "Moisture must be between 0 and 100"}), 400 + if not (0 <= nitro <= 100): + return jsonify({"error": "Nitrogen must be between 0 and 100"}), 400 + if not (0 <= pota <= 100): + return jsonify({"error": "Potassium must be between 0 and 100"}), 400 + if not (0 <= phosp <= 100): + return jsonify({"error": "Phosphorus must be between 0 and 100"}), 400 + + # Convert categorical inputs to numerical values + soil_encoded = soil_mapping[soil_type] + crop_encoded = crop_mapping[crop_type] + + # Prepare input for prediction + input_data = [temp, humi, mois, soil_encoded, crop_encoded, nitro, pota, phosp] + input_array = np.array(input_data).reshape(1, -1) + + # Make prediction + result_index = classifier_model.predict(input_array) + result_label = label_encoder.inverse_transform(result_index) + + return jsonify({ + "success": True, + "fertilizer": result_label[0], + "message": f"Predicted fertilizer is {result_label[0]}", + "input_data": { + "temperature": temp, + "humidity": humi, + "moisture": mois, + "soil_type": soil_type, + "crop_type": crop_type, + "nitrogen": nitro, + "potassium": pota, + "phosphorus": phosp + } + }), 200 + + except ValueError as e: + return jsonify({ + "error": f"Invalid data type: {str(e)}" + }), 400 + except Exception as e: + return jsonify({ + "error": f"An error occurred: {str(e)}" + }), 500 + + +@app.route('/loan_prediction', methods=['POST']) +def loan_prediction(): + # Lazy-load from Arko007/agromind-loan-prediction on first call + price_model = model_manager.get_model('loan_price_model', auto_load=True) + approval_model = model_manager.get_model('loan_approval_model', auto_load=True) + if price_model is None or approval_model is None: + return jsonify({"error": "Loan prediction model not loaded"}), 503 + try: + data = request.get_json() + + # Validate required fields + required_fields = ['area', 'land_contour', 'distance_from_road', 'soil_type', 'income', 'loan_request'] + for field in required_fields: + if field not in data: + return jsonify({'error': f'Missing required field: {field}'}), 400 + + # Extract features + area = float(data['area']) + land_contour = data['land_contour'] + distance_from_road = float(data['distance_from_road']) + soil_type = data['soil_type'] + income = float(data['income']) + loan_request = float(data['loan_request']) + + # Prepare input for prediction + input_data_price = pd.DataFrame({ + 'area': [area], + 'distance_from_road': [distance_from_road], + 'income': [income], + 'land_contour_hilly': [1 if land_contour == 'hilly' else 0], + 'land_contour_sloping': [1 if land_contour == 'sloping' else 0], + 'soil_type_clay': [1 if soil_type == 'clay' else 0], + 'soil_type_sandy': [1 if soil_type == 'sandy' else 0], + 'soil_type_silty': [1 if soil_type == 'silty' else 0] + }) + + # Add missing columns with value 0 + for column in price_model.feature_names_in_: + if column not in input_data_price.columns: + input_data_price[column] = 0 + + # Ensure column order matches training data + input_data_price = input_data_price[price_model.feature_names_in_] + + # Predict farm price + predicted_price = float(price_model.predict(input_data_price)[0]) + + # Determine loan value + loan_value = predicted_price if predicted_price <= 500000 else predicted_price * 0.85 + + # Calculate loan approval probability + if loan_request <= loan_value: + approval_probability = 1.0 + else: + diff_ratio = (loan_request - loan_value) / loan_value + approval_probability = float(np.exp(-5 * diff_ratio)) + + # Return prediction results + return jsonify({ + 'success': True, + 'predicted_price': round(predicted_price, 2), + 'loan_value': round(loan_value, 2), + 'approval_probability': round(approval_probability * 100, 2), + 'loan_request': loan_request, + 'recommendation': 'Approved' if approval_probability >= 0.5 else 'Denied' + }), 200 + + except ValueError as e: + return jsonify({ + "error": f"Invalid data type: {str(e)}" + }), 400 + except Exception as e: + return jsonify({ + "error": f"An error occurred: {str(e)}" + }), 500 + + +# ============================================================================= +# Price Forecasting Endpoint +# ============================================================================= + +# Import price forecast module +try: + import sys + sys.path.insert(0, os.path.dirname(__file__)) + from forecast_model import forecast_prices + FORECAST_AVAILABLE = True +except ImportError as e: + print(f"Price forecast module not available: {e}") + FORECAST_AVAILABLE = False + + +@app.route('/ai/price-forecast', methods=['POST']) +def price_forecast(): + """ + Price forecasting endpoint for commodities + + Request body: + { + "historical_prices": [{"date": "2024-01-01", "price": 100, "volume": 1000}, ...], + "location": {"lat": 19.0, "lng": 73.0, "state": "Maharashtra"}, + "commodity_type": "groundnut", + "global_indices": {"crude_oil": 80, "soybean": 1200, "usd_inr": 83}, + "forecast_days": 30 + } + """ + if not FORECAST_AVAILABLE: + return jsonify({ + "success": False, + "error": "Price forecast module not available" + }), 503 + + try: + data = request.get_json() + + if not data: + return jsonify({ + "success": False, + "error": "No data provided" + }), 400 + + # Validate required fields + historical_prices = data.get('historical_prices', []) + if not historical_prices or len(historical_prices) < 5: + return jsonify({ + "success": False, + "error": "Need at least 5 historical price points" + }), 400 + + # Extract optional parameters + location = data.get('location') + commodity_type = data.get('commodity_type', 'oilseed') + global_indices = data.get('global_indices') + forecast_days = data.get('forecast_days', 30) + + # Validate forecast_days + if forecast_days not in [7, 30, 90]: + forecast_days = 30 + + # Generate forecast + result = forecast_prices( + historical_prices=historical_prices, + location=location, + commodity_type=commodity_type, + global_indices=global_indices, + forecast_days=forecast_days + ) + + if result.get('success'): + return jsonify(result), 200 + else: + return jsonify(result), 400 + + except ValueError as e: + return jsonify({ + "success": False, + "error": f"Invalid data: {str(e)}" + }), 400 + except Exception as e: + return jsonify({ + "success": False, + "error": f"Forecast error: {str(e)}" + }), 500 + + +# ============================================================================= +# Yield Prediction Endpoint +# ============================================================================= + +@app.route('/ai/yield-predict', methods=['POST']) +def yield_prediction(): + """ + Yield prediction endpoint + + Request body: + { + "crop_type": "groundnut", + "location": {"lat": 19.0, "lng": 73.0, "state": "Maharashtra"}, + "soil_data": {"nitrogen": 50, "phosphorus": 30, "potassium": 40, "ph": 6.5}, + "weather_data": {"rainfall": 800, "temperature": 28, "humidity": 65}, + "area_hectares": 5 + } + """ + try: + data = request.get_json() + + if not data: + return jsonify({ + "success": False, + "error": "No data provided" + }), 400 + + crop_type = data.get('crop_type', 'groundnut') + location = data.get('location', {}) + soil_data = data.get('soil_data', {}) + weather_data = data.get('weather_data', {}) + area_hectares = data.get('area_hectares', 1) + + # Simple yield estimation based on factors + # In production, this would use a trained ML model + + # Base yield per hectare (kg/ha) by crop + base_yields = { + 'groundnut': 1800, + 'sunflower': 1200, + 'soybean': 2000, + 'mustard': 1100, + 'sesame': 600, + 'castor': 1500, + 'linseed': 800 + } + + base_yield = base_yields.get(crop_type.lower(), 1500) + + # Adjust for soil quality + soil_factor = 1.0 + if soil_data: + n = soil_data.get('nitrogen', 50) + p = soil_data.get('phosphorus', 30) + k = soil_data.get('potassium', 40) + ph = soil_data.get('ph', 6.5) + + # Optimal ranges adjustment + if 40 <= n <= 60 and 25 <= p <= 40 and 30 <= k <= 50: + soil_factor = 1.1 + elif n < 20 or p < 15 or k < 20: + soil_factor = 0.8 + + # pH adjustment + if 6.0 <= ph <= 7.5: + soil_factor *= 1.05 + elif ph < 5.5 or ph > 8.0: + soil_factor *= 0.85 + + # Adjust for weather + weather_factor = 1.0 + if weather_data: + rainfall = weather_data.get('rainfall', 700) + temp = weather_data.get('temperature', 28) + + # Rainfall adjustment + if 600 <= rainfall <= 1000: + weather_factor = 1.1 + elif rainfall < 400 or rainfall > 1500: + weather_factor = 0.75 + + # Temperature adjustment + if 25 <= temp <= 32: + weather_factor *= 1.05 + elif temp < 20 or temp > 38: + weather_factor *= 0.85 + + # Calculate predicted yield + predicted_yield_per_ha = base_yield * soil_factor * weather_factor + total_yield = predicted_yield_per_ha * area_hectares + + # Calculate confidence based on data completeness + confidence = 0.7 + if soil_data: + confidence += 0.1 + if weather_data: + confidence += 0.1 + if location: + confidence += 0.05 + + # Generate recommendations + interventions = [] + if soil_factor < 1.0: + interventions.append({ + "type": "fertilization", + "priority": "high", + "recommendation": "Apply balanced NPK fertilizer to improve soil nutrient levels" + }) + if weather_factor < 1.0: + interventions.append({ + "type": "irrigation", + "priority": "medium", + "recommendation": "Consider supplemental irrigation during dry spells" + }) + + return jsonify({ + "success": True, + "data": { + "crop_type": crop_type, + "area_hectares": area_hectares, + "predicted_yield_kg_per_ha": round(predicted_yield_per_ha, 2), + "total_predicted_yield_kg": round(total_yield, 2), + "confidence": round(confidence, 2), + "factors": { + "soil_factor": round(soil_factor, 2), + "weather_factor": round(weather_factor, 2) + }, + "interventions": interventions, + "feature_importance": { + "soil_nutrients": 0.35, + "rainfall": 0.25, + "temperature": 0.15, + "location": 0.15, + "crop_variety": 0.10 + } + } + }), 200 + + except Exception as e: + return jsonify({ + "success": False, + "error": f"Prediction error: {str(e)}" + }), 500 + + +# ============================================================================= +# Tariff Impact Simulation Endpoint +# ============================================================================= + +@app.route('/ai/tariff-simulate', methods=['POST']) +def tariff_simulation(): + """ + Simulate impact of customs duty changes on imports and prices + + Request body: + { + "tariff_pct": 35, + "period": "6_months", + "global_price_shock": 0 + } + """ + try: + data = request.get_json() or {} + + tariff_pct = data.get('tariff_pct', 35) + period = data.get('period', '6_months') + global_price_shock = data.get('global_price_shock', 0) # % change in global prices + + # Base parameters (simplified model) + base_import_volume = 15000000 # 15 million tonnes + base_domestic_price = 120 # INR per kg + base_farmer_price = 95 + base_consumer_price = 145 + + # Elasticities (simplified) + import_elasticity = -0.8 # How much imports change with price + domestic_price_elasticity = 0.3 # How domestic price changes with reduced imports + pass_through_farmer = 0.6 # How much of price change reaches farmers + pass_through_consumer = 0.8 # How much reaches consumers + + # Current tariff baseline + current_tariff = 35 + tariff_change = tariff_pct - current_tariff + + # Calculate impacts + # Higher tariff -> lower imports -> higher domestic prices + + # Import volume change + effective_price_change = (tariff_change / 100) + (global_price_shock / 100) + import_volume_change = effective_price_change * import_elasticity * 100 + new_import_volume = base_import_volume * (1 + import_volume_change / 100) + new_import_volume = max(new_import_volume, 0) + + # Domestic price change + supply_reduction = (base_import_volume - new_import_volume) / base_import_volume + domestic_price_change = supply_reduction * domestic_price_elasticity * 100 + new_domestic_price = base_domestic_price * (1 + domestic_price_change / 100) + + # Farmer and consumer prices + farmer_price_change = domestic_price_change * pass_through_farmer + consumer_price_change = domestic_price_change * pass_through_consumer + + new_farmer_price = base_farmer_price * (1 + farmer_price_change / 100) + new_consumer_price = base_consumer_price * (1 + consumer_price_change / 100) + + # Sensitivity analysis + sensitivity_table = [] + for sensitivity_tariff in [25, 30, 35, 40, 45, 50]: + sens_change = sensitivity_tariff - current_tariff + sens_import_change = (sens_change / 100) * import_elasticity * 100 + sens_import_vol = base_import_volume * (1 + sens_import_change / 100) + sens_supply_red = (base_import_volume - sens_import_vol) / base_import_volume + sens_price_change = sens_supply_red * domestic_price_elasticity * 100 + + sensitivity_table.append({ + "tariff_pct": sensitivity_tariff, + "import_volume_mt": round(sens_import_vol / 1000000, 2), + "domestic_price_inr": round(base_domestic_price * (1 + sens_price_change / 100), 2), + "farmer_price_inr": round(base_farmer_price * (1 + sens_price_change * pass_through_farmer / 100), 2) + }) + + return jsonify({ + "success": True, + "data": { + "scenario": { + "tariff_pct": tariff_pct, + "period": period, + "global_price_shock_pct": global_price_shock + }, + "baseline": { + "import_volume_mt": round(base_import_volume / 1000000, 2), + "domestic_price_inr_kg": base_domestic_price, + "farmer_price_inr_kg": base_farmer_price, + "consumer_price_inr_kg": base_consumer_price + }, + "predicted": { + "import_volume_mt": round(new_import_volume / 1000000, 2), + "import_change_pct": round(import_volume_change, 2), + "domestic_price_inr_kg": round(new_domestic_price, 2), + "domestic_price_change_pct": round(domestic_price_change, 2), + "farmer_price_inr_kg": round(new_farmer_price, 2), + "farmer_price_change_pct": round(farmer_price_change, 2), + "consumer_price_inr_kg": round(new_consumer_price, 2), + "consumer_price_change_pct": round(consumer_price_change, 2) + }, + "sensitivity_analysis": sensitivity_table, + "model_assumptions": { + "import_elasticity": import_elasticity, + "domestic_price_elasticity": domestic_price_elasticity, + "pass_through_farmer": pass_through_farmer, + "pass_through_consumer": pass_through_consumer + } + } + }), 200 + + except Exception as e: + return jsonify({ + "success": False, + "error": f"Simulation error: {str(e)}" + }), 500 + + +# ============================================================================= +# CROPIC - Crop Image Analysis Endpoint +# ============================================================================= + +@app.route('/ai/cropic/analyze', methods=['POST']) +def cropic_analyze(): + """ + Analyze crop damage from image for insurance purposes + + Request: multipart/form-data with: + - file: image file + - metadata: JSON string with {lat, lng, crop_type, stage} + """ + try: + if 'file' not in request.files: + return jsonify({ + "success": False, + "error": "No image file provided" + }), 400 + + file = request.files['file'] + if file.filename == '': + return jsonify({ + "success": False, + "error": "Empty filename" + }), 400 + + # Get metadata + metadata = {} + if 'metadata' in request.form: + try: + metadata = json.loads(request.form['metadata']) + except: + pass + + # Read and validate image + img_bytes = file.read() + + # Load disease model if available (lazy) + model = model_manager.get_model('disease_model', auto_load=False) + labels = model_manager.get_model('disease_labels', auto_load=False) or [] + + # Check file size (max 10MB) + if len(img_bytes) > 10 * 1024 * 1024: + return jsonify({ + "success": False, + "error": "Image too large. Maximum size is 10MB" + }), 400 + + try: + pil_img = Image.open(io.BytesIO(img_bytes)) + pil_img = pil_img.convert('RGB') + + # Check image dimensions + width, height = pil_img.size + if width < 100 or height < 100: + return jsonify({ + "success": False, + "error": "Image too small. Minimum dimensions: 100x100" + }), 400 + + except Exception as e: + return jsonify({ + "success": False, + "error": f"Invalid image format: {str(e)}" + }), 400 + + # Use existing disease model for classification if available + crop_type = metadata.get('crop_type', 'unknown') + stage = metadata.get('stage', 'vegetative') + + # If disease model is loaded, use it for damage classification + damage_type = "unknown" + damage_percentage = 0 + confidence = 0.5 + + if model is not None: + try: + top_label, conf, topk = predict(model, pil_img, labels, device, topk=5) + + # Map disease labels to damage types + damage_mapping = { + 'healthy': ('none', 0), + 'bacterial': ('bacterial_infection', 40), + 'fungal': ('fungal_disease', 35), + 'viral': ('viral_infection', 45), + 'pest': ('pest_damage', 30), + 'nutrient': ('nutrient_deficiency', 25), + 'drought': ('drought_stress', 50), + 'flood': ('waterlogging', 60) + } + + # Simple matching + for key, (dtype, dpct) in damage_mapping.items(): + if key in top_label.lower(): + damage_type = dtype + damage_percentage = dpct + break + + if 'healthy' in top_label.lower(): + damage_type = 'none' + damage_percentage = 0 + else: + # Estimate damage from confidence + damage_percentage = int(conf * 50) # Scale to reasonable range + if damage_type == 'unknown': + damage_type = 'unclassified_damage' + + confidence = float(conf) + + except Exception as e: + print(f"Classification error: {e}") + # Fallback to random estimation for demo + damage_type = "unclassified_damage" + damage_percentage = np.random.randint(10, 50) + confidence = 0.6 + else: + # No model - provide simulated response + damage_types = ['none', 'pest_damage', 'disease', 'drought_stress', 'flood_damage'] + damage_type = np.random.choice(damage_types, p=[0.3, 0.2, 0.25, 0.15, 0.1]) + damage_percentage = 0 if damage_type == 'none' else np.random.randint(10, 60) + confidence = np.random.uniform(0.6, 0.9) + + return jsonify({ + "success": True, + "data": { + "crop_type": crop_type, + "stage": stage, + "damage_type": damage_type, + "damage_percentage": damage_percentage, + "confidence": round(confidence, 2), + "image_quality": { + "dimensions": f"{width}x{height}", + "format": pil_img.format or "JPEG", + "is_valid": True + }, + "location": { + "lat": metadata.get('lat'), + "lng": metadata.get('lng') + }, + "recommendations": _get_damage_recommendations(damage_type, damage_percentage) + } + }), 200 + + except Exception as e: + return jsonify({ + "success": False, + "error": f"Analysis error: {str(e)}" + }), 500 + + +def _get_damage_recommendations(damage_type: str, damage_pct: int) -> list: + """Get recommendations based on damage type and severity""" + recommendations = [] + + if damage_type == 'none': + recommendations.append({ + "action": "monitoring", + "description": "Continue regular monitoring. Crop appears healthy." + }) + elif damage_type == 'pest_damage': + recommendations.append({ + "action": "pesticide_application", + "description": "Apply appropriate pesticide. Consult local agriculture office for specific recommendations." + }) + elif damage_type in ['disease', 'bacterial_infection', 'fungal_disease']: + recommendations.append({ + "action": "fungicide_treatment", + "description": "Apply fungicide treatment. Remove and destroy affected plant parts." + }) + elif damage_type == 'drought_stress': + recommendations.append({ + "action": "irrigation", + "description": "Increase irrigation frequency. Apply mulch to retain soil moisture." + }) + elif damage_type in ['flood_damage', 'waterlogging']: + recommendations.append({ + "action": "drainage", + "description": "Improve field drainage. Allow soil to dry before resuming irrigation." + }) + + if damage_pct >= 50: + recommendations.append({ + "action": "insurance_claim", + "description": "Damage exceeds 50%. Consider filing an insurance claim.", + "priority": "high" + }) + + return recommendations + + +# ── Harvest Readiness Detection ───────────────────────────────────────────── +_harvest_model = None + +def _load_harvest_model(): + """Lazy-load the harvest readiness YOLO classification model from HF Hub.""" + global _harvest_model + if _harvest_model is not None: + return _harvest_model + try: + from ultralytics import YOLO + model_path = hf_hub_download( + repo_id=HF_REPO_HARVEST, filename="best.pt" + ) + _harvest_model = YOLO(model_path) + logger.info("Harvest readiness YOLO model loaded from HF Hub") + except Exception as e: + log_exception(logger, e, "Failed to load harvest readiness model") + _harvest_model = None + return _harvest_model + + +@app.route("/harvest_readiness", methods=["POST"]) +def harvest_readiness(): + """Detect harvest readiness from a crop image using YOLO11m-cls.""" + model = _load_harvest_model() + if model is None: + return jsonify({"error": "Harvest readiness model unavailable"}), 503 + + if "file" not in request.files: + return jsonify({"error": "no file part"}), 400 + file = request.files["file"] + if file.filename == "": + return jsonify({"error": "empty filename"}), 400 + + try: + img_bytes = file.read() + pil_img = Image.open(io.BytesIO(img_bytes)).convert("RGB") + + results = model.predict(pil_img, imgsz=224, verbose=False) + result = results[0] + + # Classification results: result.probs contains probabilities + probs = result.probs + top_class_idx = int(probs.top1) + top_confidence = float(probs.top1conf) + class_name = result.names[top_class_idx] if result.names else str(top_class_idx) + + # Determine readiness from class name using keyword matching + # The YOLO model classifies into categories like "Ready", "Unripe", "Overripe", etc. + ready_keywords = {"ready", "ripe", "mature", "harvest", "overripe"} + unready_keywords = {"unready", "unripe", "immature", "green", "growing"} + class_lower = class_name.lower() + class_tokens = set(class_lower.replace("_", " ").replace("-", " ").split()) + is_ready = bool(class_tokens & ready_keywords) and not bool(class_tokens & unready_keywords) + + # Estimate maturity percentage from confidence and class + if is_ready: + maturity = max(80, int(top_confidence * 100)) + days_left = 0 + else: + maturity = max(10, min(70, int(top_confidence * 60))) + days_left = max(1, int((100 - maturity) * 0.5)) + + # Build top-k predictions + topk_indices = probs.top5 if hasattr(probs, 'top5') else [top_class_idx] + topk_confs = probs.top5conf.tolist() if hasattr(probs, 'top5conf') else [top_confidence] + topk = [ + {"label": result.names.get(int(idx), str(idx)), "confidence": round(float(c), 4)} + for idx, c in zip(topk_indices, topk_confs) + ] + + return jsonify({ + "ready": "Yes" if is_ready else "No", + "maturity": maturity, + "days_left": days_left, + "note": f"Classified as '{class_name}' with {top_confidence:.1%} confidence.", + "class": class_name, + "confidence": round(top_confidence, 4), + "topk": topk, + }) + except Exception as e: + logger.error(f"Harvest readiness prediction error: {e}") + return jsonify({"error": str(e)}), 500 + + +# ── Saffron Authenticity Classifier ────────────────────────────────────────── +HF_SAFFRON_REPO = os.environ.get("HF_REPO_SAFFRON", "Arko007/saffron-verify-pretrained") +HF_SAFFRON_API = f"https://api-inference.huggingface.co/models/{HF_SAFFRON_REPO}" +SAFFRON_CLASSES = ["mogra", "lacha", "adulterated"] + + +@app.route("/saffron_classify", methods=["POST"]) +def saffron_classify(): + """Classify saffron purity from an uploaded image.""" + if "file" not in request.files: + return jsonify({"error": "no file part"}), 400 + file = request.files["file"] + if file.filename == "": + return jsonify({"error": "empty filename"}), 400 + + try: + img_bytes = file.read() + # Validate it is a real image + pil_img = Image.open(io.BytesIO(img_bytes)).convert("RGB") + + # Try HF Inference API first + hf_token = os.environ.get("HF_TOKEN", "") + headers = {} + if hf_token: + headers["Authorization"] = f"Bearer {hf_token}" + + try: + # Re-encode as JPEG for the API + buf = io.BytesIO() + pil_img.save(buf, format="JPEG") + resp = _call_hf_inference_api( + HF_SAFFRON_API, + headers=headers, + data=buf.getvalue(), + ) + if resp.status_code == 200: + results = resp.json() + if isinstance(results, list) and len(results) > 0: + top = results[0] + return jsonify({ + "model": "saffron-verify-pretrained", + "prediction": top.get("label", "unknown"), + "confidence": round(top.get("score", 0.0), 4), + "all_predictions": [ + {"label": r.get("label", ""), "confidence": round(r.get("score", 0.0), 4)} + for r in results + ], + "timestamp": _time.strftime("%Y-%m-%dT%H:%M:%SZ", _time.gmtime()), + }) + logger.warning(f"Saffron HF API returned status {resp.status_code}: {resp.text[:200]}") + except Exception as api_err: + logger.warning(f"Saffron HF Inference API failed: {api_err}") + + # Fallback: try loading model locally via timm + try: + import timm + import torch.nn as nn + from torchvision import transforms + + class _SaffronModel(nn.Module): + def __init__(self): + super().__init__() + self.backbone = timm.create_model( + "convnext_base", pretrained=False, + num_classes=0, drop_rate=0.3, drop_path_rate=0.2, + ) + feat_dim = self.backbone.num_features + self.head = nn.Sequential( + nn.LayerNorm(feat_dim), + nn.Dropout(p=0.3), + nn.Linear(feat_dim, 512), + nn.GELU(), + nn.Dropout(p=0.15), + nn.Linear(512, 3), + ) + + def forward(self, x): + return self.head(self.backbone(x)) + + ckpt_path = hf_hub_download(repo_id=HF_SAFFRON_REPO, filename="best_model.pth") + model_s = _SaffronModel() + ckpt = torch.load(ckpt_path, map_location="cpu", weights_only=False) + model_s.load_state_dict(ckpt.get("model_state", ckpt.get("model_state_dict", ckpt))) + model_s.eval() + + transform = transforms.Compose([ + transforms.Resize(512), + transforms.CenterCrop(512), + transforms.ToTensor(), + transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), + ]) + tensor = transform(pil_img).unsqueeze(0) + with torch.no_grad(): + logits = model_s(tensor) + probs = torch.softmax(logits, dim=1)[0] + pred_idx = probs.argmax().item() + + all_preds = [ + {"label": SAFFRON_CLASSES[i], "confidence": round(probs[i].item(), 4)} + for i in range(len(SAFFRON_CLASSES)) + ] + all_preds.sort(key=lambda x: x["confidence"], reverse=True) + + return jsonify({ + "model": "saffron-verify-pretrained", + "prediction": SAFFRON_CLASSES[pred_idx], + "confidence": round(probs[pred_idx].item(), 4), + "all_predictions": all_preds, + "timestamp": _time.strftime("%Y-%m-%dT%H:%M:%SZ", _time.gmtime()), + }) + except Exception as local_err: + logger.warning(f"Saffron local model also failed: {local_err}") + + return jsonify({"error": "Saffron model unavailable via API and local fallback"}), 503 + except Exception as e: + logger.error(f"Saffron classification error: {e}") + return jsonify({"error": str(e)}), 500 + + +# ── Walnut Defect Classifier ──────────────────────────────────────────────── +HF_WALNUT_DEFECT_REPO = os.environ.get("HF_REPO_WALNUT_DEFECT", "Arko007/walnut-defect-classifier") +HF_WALNUT_DEFECT_API = f"https://api-inference.huggingface.co/models/{HF_WALNUT_DEFECT_REPO}" +WALNUT_DEFECT_CLASSES = ["Healthy", "Black Spot", "Shriveled", "Damaged"] + + +@app.route("/walnut_defect_classify", methods=["POST"]) +def walnut_defect_classify(): + """Classify walnut shell defects from an uploaded image.""" + if "file" not in request.files: + return jsonify({"error": "no file part"}), 400 + file = request.files["file"] + if file.filename == "": + return jsonify({"error": "empty filename"}), 400 + + try: + img_bytes = file.read() + pil_img = Image.open(io.BytesIO(img_bytes)).convert("RGB") + + hf_token = os.environ.get("HF_TOKEN", "") + headers = {} + if hf_token: + headers["Authorization"] = f"Bearer {hf_token}" + + try: + buf = io.BytesIO() + pil_img.save(buf, format="JPEG") + resp = _call_hf_inference_api( + HF_WALNUT_DEFECT_API, + headers=headers, + data=buf.getvalue(), + ) + if resp.status_code == 200: + results = resp.json() + if isinstance(results, list) and len(results) > 0: + top = results[0] + return jsonify({ + "model": "walnut-defect-classifier", + "prediction": top.get("label", "unknown"), + "confidence": round(top.get("score", 0.0), 4), + "all_predictions": [ + {"label": r.get("label", ""), "confidence": round(r.get("score", 0.0), 4)} + for r in results + ], + "timestamp": _time.strftime("%Y-%m-%dT%H:%M:%SZ", _time.gmtime()), + }) + logger.warning(f"Walnut defect HF API returned status {resp.status_code}: {resp.text[:200]}") + except Exception as api_err: + logger.warning(f"Walnut defect HF Inference API failed: {api_err}") + + # Fallback: load model locally via timm + try: + import timm + ckpt_path = hf_hub_download(repo_id=HF_WALNUT_DEFECT_REPO, filename="best_model.pth") + model_w = timm.create_model("efficientnet_b3", pretrained=False, num_classes=4, drop_rate=0.4) + ckpt = torch.load(ckpt_path, map_location="cpu", weights_only=False) + state = {k.replace("module.", ""): v for k, v in ckpt.get("model_state_dict", ckpt).items()} + model_w.load_state_dict(state) + model_w.eval() + + from torchvision import transforms + transform = transforms.Compose([ + transforms.Resize((512, 512)), + transforms.ToTensor(), + transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), + ]) + tensor = transform(pil_img).unsqueeze(0) + with torch.no_grad(): + probs = torch.softmax(model_w(tensor), dim=1)[0] + pred_idx = probs.argmax().item() + + all_preds = [ + {"label": WALNUT_DEFECT_CLASSES[i], "confidence": round(probs[i].item(), 4)} + for i in range(len(WALNUT_DEFECT_CLASSES)) + ] + all_preds.sort(key=lambda x: x["confidence"], reverse=True) + + return jsonify({ + "model": "walnut-defect-classifier", + "prediction": WALNUT_DEFECT_CLASSES[pred_idx], + "confidence": round(probs[pred_idx].item(), 4), + "all_predictions": all_preds, + "timestamp": _time.strftime("%Y-%m-%dT%H:%M:%SZ", _time.gmtime()), + }) + except Exception as local_err: + logger.warning(f"Walnut defect local model also failed: {local_err}") + + return jsonify({"error": "Walnut defect model unavailable via API and local fallback"}), 503 + except Exception as e: + logger.error(f"Walnut defect classification error: {e}") + return jsonify({"error": str(e)}), 500 + + +# ── Walnut Rancidity Predictor ────────────────────────────────────────────── + +@app.route("/walnut_rancidity_predict", methods=["POST"]) +def walnut_rancidity_predict(): + """Predict walnut rancidity and remaining shelf life from storage conditions. + + Uses Arrhenius-based lipid oxidation kinetics (the same chemistry model + behind the Arko007/walnut-rancidity-predictor HF model) so that the + endpoint works without downloading a ~85 K-parameter LSTM checkpoint. + """ + is_valid, error_response = validate_content_type(request) + if not is_valid: + return jsonify(error_response), error_response["status"] + + try: + data = request.get_json(force=True) + except Exception: + return jsonify({"error": "Invalid JSON payload"}), 400 + + # Required fields + storage_days = data.get("storage_days") + temperature = data.get("temperature") + humidity = data.get("humidity") + moisture = data.get("moisture") + + if storage_days is None or temperature is None or humidity is None or moisture is None: + return jsonify({ + "error": "Missing required fields: storage_days, temperature, humidity, moisture" + }), 400 + + try: + storage_days = float(storage_days) + temperature = float(temperature) + humidity = float(humidity) + moisture = float(moisture) + except (ValueError, TypeError): + return jsonify({"error": "All inputs must be numeric"}), 400 + + # Validation with friendly responses + if storage_days < 0 or storage_days > 365: + return jsonify({ + "success": False, + "message": "Please choose storage days between 0 and 365 days.", + "validation_error": "storage_days_out_of_range" + }), 200 + + if temperature < -10 or temperature > 50: + return jsonify({ + "success": False, + "message": "Please choose temperature between -10 and 50 degrees Celsius.", + "validation_error": "temperature_out_of_range" + }), 200 + + if humidity < 0 or humidity > 100: + return jsonify({ + "success": False, + "message": "Please choose humidity between 0 and 100 percent.", + "validation_error": "humidity_out_of_range" + }), 200 + + if moisture < 0 or moisture > 15: + return jsonify({ + "success": False, + "message": "Please choose a value between 0 and 15 percent for moisture content.", + "validation_error": "moisture_out_of_range" + }), 200 + + try: + import math + + # Arrhenius kinetics: k(T) = A * exp(-Ea / (R * T_kelvin)) + A = 1.5e12 + Ea = 80_000 # J/mol + R = 8.314 # J/(mol*K) + T_kelvin = temperature + 273.15 + k_base = A * math.exp(-Ea / (R * T_kelvin)) + + # Humidity and moisture correction factors + humidity_factor = 1.0 + 0.005 * max(0, humidity - 50) + moisture_factor = 1.0 + 0.02 * max(0, moisture - 4) + k_eff = k_base * humidity_factor * moisture_factor + + # PV(t) = PV_0 * exp(k * t) β€” initial PV ~ 0.5 meq/kg for fresh walnuts + PV_0 = 0.5 + PV_t = PV_0 * math.exp(k_eff * storage_days) + + # Rancidity threshold: PV > 5 meq/kg (FSSAI / Codex) + rancidity_prob = 1.0 / (1.0 + math.exp(-(PV_t - 5))) + + # Shelf life remaining = days until PV reaches 5 + if PV_t >= 5: + shelf_life_remaining = 0.0 + elif k_eff > 0: + shelf_life_remaining = max(0.0, (math.log(5 / PV_0) / k_eff) - storage_days) + else: + shelf_life_remaining = 365.0 + + # Decay curve (normalised PV, capped at 1) + decay_curve = min(1.0, PV_t / 10.0) + + # Risk level + if rancidity_prob < 0.30: + risk_level = "LOW" + elif rancidity_prob < 0.70: + risk_level = "MEDIUM" + else: + risk_level = "HIGH" + + return jsonify({ + "success": True, + "model": "walnut-rancidity-predictor", + "prediction": { + "rancidity_probability": round(rancidity_prob, 4), + "shelf_life_remaining_days": round(shelf_life_remaining, 1), + "decay_curve_value": round(decay_curve, 4), + }, + "risk_level": risk_level, + "advisory": ( + "Walnuts are safe for storage." + if risk_level == "LOW" + else "Monitor quality closely β€” consider selling soon." + if risk_level == "MEDIUM" + else "High rancidity risk β€” sell or consume immediately." + ), + "timestamp": _time.strftime("%Y-%m-%dT%H:%M:%SZ", _time.gmtime()), + }), 200 + except Exception as e: + logger.error(f"Walnut rancidity prediction error: {e}") + return jsonify({"error": str(e)}), 500 + + +# ── Apple Price Predictor ──────────────────────────────────────────────────── +APPLE_VARIETY_BASE_PRICES = { + "Shimla": 97, "Kinnauri": 125, "Royal Delicious": 82, + "Golden Delicious": 87, "Maharaji": 60, +} +APPLE_REGIONS = ["Himachal Pradesh", "Jammu & Kashmir", "Uttarakhand", + "Arunachal Pradesh", "Nagaland"] +APPLE_STORAGE_COST_PER_DAY = 0.75 # β‚Ή/kg/day + + +@app.route("/apple_price_predict", methods=["POST"]) +def apple_price_predict(): + """Predict apple wholesale price 7 days ahead and recommend SELL or STORE.""" + is_valid, error_response = validate_content_type(request) + if not is_valid: + return jsonify(error_response), error_response["status"] + + try: + data = request.get_json(force=True) + except Exception: + return jsonify({"error": "Invalid JSON payload"}), 400 + + current_price = data.get("current_price") + apple_variety = data.get("apple_variety", "Shimla") + region = data.get("region", "Himachal Pradesh") + storage_time_days = data.get("storage_time_days", 0) + date_str = data.get("date", _time.strftime("%Y-%m-%d")) + + if current_price is None: + return jsonify({"error": "current_price is required"}), 400 + + try: + current_price = float(current_price) + storage_time_days = int(storage_time_days) + except (ValueError, TypeError): + return jsonify({"error": "current_price must be numeric, storage_time_days must be integer"}), 400 + + if current_price <= 0: + return jsonify({"error": "current_price must be positive"}), 400 + + try: + import math + from datetime import datetime + + # Parse date for seasonal adjustment + try: + dt = datetime.strptime(date_str, "%Y-%m-%d") + except ValueError: + dt = datetime.utcnow() + + month = dt.month + + # Seasonal price adjustments (Indian apple market dynamics) + seasonal_adj = 0.0 + if 7 <= month <= 9: # Harvest season β€” supply glut + seasonal_adj = -12.0 + elif 4 <= month <= 6: # Summer scarcity + seasonal_adj = 15.0 + elif month in (10, 11): # Diwali festival demand + seasonal_adj = 8.0 + + # Variety premium + base_price = APPLE_VARIETY_BASE_PRICES.get(apple_variety, 90) + variety_factor = base_price / 90.0 + + # Storage quality decay + storage_decay = -0.08 * storage_time_days + + # Simple trend: mild inflation + annual_inflation = 5.0 + days_in_year = 365.0 + trend_adj = (7.0 / days_in_year) * annual_inflation + + # Predicted 7-day price (deterministic) + predicted_price_7d = round( + current_price * variety_factor + + seasonal_adj + + storage_decay + + trend_adj, + 2, + ) + # Clamp to realistic range + predicted_price_7d = max(30.0, min(200.0, predicted_price_7d)) + + storage_cost_7d = round(APPLE_STORAGE_COST_PER_DAY * 7, 2) + breakeven_price = round(current_price + storage_cost_7d, 2) + recommendation = "STORE" if predicted_price_7d > breakeven_price else "SELL" + + return jsonify({ + "model": "apple-price-predictor", + "predicted_price_7d": predicted_price_7d, + "recommendation": recommendation, + "current_price": current_price, + "storage_cost_7d": storage_cost_7d, + "breakeven_price": breakeven_price, + "currency": "INR", + "confidence": "hybrid seasonal+trend model", + "advisory": ( + f"Predicted price in 7 days: β‚Ή{predicted_price_7d}/kg. " + f"{'Store for better returns.' if recommendation == 'STORE' else 'Sell now β€” prices may not cover storage costs.'}" + ), + "timestamp": _time.strftime("%Y-%m-%dT%H:%M:%SZ", _time.gmtime()), + }), 200 + except Exception as e: + logger.error(f"Apple price prediction error: {e}") + return jsonify({"error": str(e)}), 500 + + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5000, debug=True) diff --git a/ai-backend/forecast_model.py b/ai-backend/forecast_model.py new file mode 100644 index 0000000000000000000000000000000000000000..e1fae80a4fe8419cdaf8d979efacbfd0047ca2f3 --- /dev/null +++ b/ai-backend/forecast_model.py @@ -0,0 +1,354 @@ +""" +Price Forecasting Module for AgroMind AI Backend +Uses LightGBM for time-series price prediction with confidence intervals +""" +import os +import json +import pickle +import logging +from datetime import datetime, timedelta +from typing import Dict, List, Optional, Tuple, Any + +import numpy as np +import pandas as pd + +# Configure logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +import lightgbm as lgb + + +class PriceForecastModel: + """ + Price forecasting model using LightGBM + """ + + def __init__(self): + self.model = None + self.scaler = None + self.feature_names = None + self.is_trained = False + self._load_model() + + def _load_model(self): + """Load pre-trained model if available (currently no pre-trained + price forecast model is shipped).""" + self.model = None + self.scaler = None + self.is_trained = False + + def prepare_features( + self, + historical_prices: List[Dict], + location: Optional[Dict] = None, + commodity_type: str = "oilseed", + global_indices: Optional[Dict] = None + ) -> Tuple[np.ndarray, List[str]]: + """ + Prepare features for price forecasting + + Args: + historical_prices: List of {date, price, volume} dicts + location: {lat, lng, state, district} + commodity_type: Type of commodity + global_indices: Optional global market indices + + Returns: + Feature array and feature names + """ + df = pd.DataFrame(historical_prices) + + if 'date' in df.columns: + df['date'] = pd.to_datetime(df['date']) + df = df.sort_values('date') + + features = {} + feature_names = [] + + # Price-based features + if 'price' in df.columns: + prices = df['price'].values + + # Basic statistics + features['price_mean'] = np.mean(prices) + features['price_std'] = np.std(prices) + features['price_min'] = np.min(prices) + features['price_max'] = np.max(prices) + features['price_last'] = prices[-1] if len(prices) > 0 else 0 + + # Trend features + if len(prices) >= 7: + features['price_ma_7'] = np.mean(prices[-7:]) + else: + features['price_ma_7'] = features['price_mean'] + + if len(prices) >= 30: + features['price_ma_30'] = np.mean(prices[-30:]) + else: + features['price_ma_30'] = features['price_mean'] + + # Volatility + if len(prices) >= 2: + returns = np.diff(prices) / prices[:-1] + features['volatility'] = np.std(returns) if len(returns) > 0 else 0 + else: + features['volatility'] = 0 + + # Momentum + if len(prices) >= 7: + features['momentum_7d'] = (prices[-1] - prices[-7]) / prices[-7] if prices[-7] != 0 else 0 + else: + features['momentum_7d'] = 0 + + feature_names.extend([ + 'price_mean', 'price_std', 'price_min', 'price_max', + 'price_last', 'price_ma_7', 'price_ma_30', + 'volatility', 'momentum_7d' + ]) + + # Volume features + if 'volume' in df.columns: + volumes = df['volume'].values + features['volume_mean'] = np.mean(volumes) + features['volume_last'] = volumes[-1] if len(volumes) > 0 else 0 + feature_names.extend(['volume_mean', 'volume_last']) + + # Temporal features + if 'date' in df.columns and len(df) > 0: + last_date = df['date'].iloc[-1] + features['month'] = last_date.month + features['quarter'] = (last_date.month - 1) // 3 + 1 + features['is_harvest_season'] = 1 if last_date.month in [10, 11, 12, 1, 2, 3] else 0 + feature_names.extend(['month', 'quarter', 'is_harvest_season']) + + # Location features (encoded) + if location: + # Simple state encoding (can be expanded) + state_codes = { + 'maharashtra': 1, 'gujarat': 2, 'rajasthan': 3, + 'madhya pradesh': 4, 'karnataka': 5, 'andhra pradesh': 6, + 'telangana': 7, 'tamil nadu': 8, 'punjab': 9, 'haryana': 10 + } + state = location.get('state', '').lower() + features['state_code'] = state_codes.get(state, 0) + feature_names.append('state_code') + + # Commodity type encoding + commodity_codes = { + 'groundnut': 1, 'sunflower': 2, 'soybean': 3, 'mustard': 4, + 'sesame': 5, 'oilseed_meal': 6, 'oilseed_cake': 7, 'oilseed_husk': 8, + 'castor': 9, 'linseed': 10, 'oilseed': 0 + } + features['commodity_code'] = commodity_codes.get(commodity_type.lower(), 0) + feature_names.append('commodity_code') + + # Global indices + if global_indices: + features['global_oil_price'] = global_indices.get('crude_oil', 0) + features['global_soy_price'] = global_indices.get('soybean', 0) + features['usd_inr'] = global_indices.get('usd_inr', 83.0) + feature_names.extend(['global_oil_price', 'global_soy_price', 'usd_inr']) + + # Create feature array + feature_array = np.array([features.get(f, 0) for f in feature_names]).reshape(1, -1) + + return feature_array, feature_names + + def forecast( + self, + historical_prices: List[Dict], + location: Optional[Dict] = None, + commodity_type: str = "oilseed", + global_indices: Optional[Dict] = None, + forecast_days: int = 30 + ) -> Dict[str, Any]: + """ + Generate price forecast with confidence intervals + + Args: + historical_prices: List of {date, price, volume} dicts + location: Location dict + commodity_type: Type of commodity + global_indices: Global market indices + forecast_days: Number of days to forecast + + Returns: + Forecast results with predictions and confidence intervals + """ + if not historical_prices or len(historical_prices) < 5: + return { + "success": False, + "error": "Insufficient historical data. Need at least 5 price points." + } + + try: + # Prepare features + features, feature_names = self.prepare_features( + historical_prices, location, commodity_type, global_indices + ) + + # Get last price for baseline + df = pd.DataFrame(historical_prices) + df['date'] = pd.to_datetime(df['date']) + df = df.sort_values('date') + last_price = float(df['price'].iloc[-1]) + last_date = df['date'].iloc[-1] + + # Calculate historical volatility for confidence intervals + prices = df['price'].values + if len(prices) >= 2: + returns = np.diff(prices) / prices[:-1] + daily_volatility = np.std(returns) if len(returns) > 0 else 0.02 + else: + daily_volatility = 0.02 + + # Generate forecasts + forecasts = [] + + if self.model is not None and self.is_trained: + # Use trained model + for day in range(1, forecast_days + 1): + # This is simplified - in production, would update features iteratively + pred = self.model.predict(features)[0] + forecasts.append(pred) + else: + # Statistical fallback using trend extrapolation and seasonal adjustment. + # Each day's forecast builds on the previous day (random walk with drift), + # which is standard for short-horizon price forecasting. + logger.info("Using statistical fallback for price forecast (no trained model)") + trend = 0.0 + if len(prices) >= 2: + daily_changes = np.diff(prices) + trend = np.mean(daily_changes) + + current_price = last_price + for day in range(1, forecast_days + 1): + forecast_date = last_date + timedelta(days=day) + seasonal = self._get_seasonal_factor(forecast_date.month) + # Monthly seasonal factor scaled to a daily effect + daily_seasonal = current_price * seasonal / 30 + pred = current_price + trend + daily_seasonal + pred = max(pred, 0) + forecasts.append(pred) + current_price = pred + + # Calculate confidence intervals + forecast_dates = [] + predictions = [] + lower_bounds = [] + upper_bounds = [] + + for day, pred in enumerate(forecasts, 1): + forecast_date = last_date + timedelta(days=day) + forecast_dates.append(forecast_date.strftime('%Y-%m-%d')) + predictions.append(round(pred, 2)) + + # CI widens with forecast horizon + ci_width = daily_volatility * last_price * np.sqrt(day) * 1.96 + lower_bounds.append(round(max(pred - ci_width, 0), 2)) + upper_bounds.append(round(pred + ci_width, 2)) + + # Summary statistics + avg_forecast = np.mean(predictions) + forecast_change = ((predictions[-1] - last_price) / last_price) * 100 + + return { + "success": True, + "data": { + "commodity": commodity_type, + "location": location, + "last_price": round(last_price, 2), + "last_date": last_date.strftime('%Y-%m-%d'), + "forecast_period_days": forecast_days, + "forecasts": [ + { + "date": date, + "predicted_price": pred, + "lower_bound": lb, + "upper_bound": ub, + "confidence_level": 0.95 + } + for date, pred, lb, ub in zip( + forecast_dates, predictions, lower_bounds, upper_bounds + ) + ], + "summary": { + "average_forecast": round(avg_forecast, 2), + "forecast_change_percent": round(forecast_change, 2), + "trend": "bullish" if forecast_change > 2 else "bearish" if forecast_change < -2 else "neutral", + "volatility": round(daily_volatility * 100, 2), + "model_type": "lightgbm" if self.is_trained else "statistical" + }, + "feature_importance": self._get_feature_importance(feature_names) if self.is_trained else None + } + } + + except Exception as e: + logger.error(f"Forecast error: {e}") + return { + "success": False, + "error": str(e) + } + + def _get_seasonal_factor(self, month: int) -> float: + """Get seasonal adjustment factor based on month""" + # Oilseed prices typically higher during off-season + seasonal_factors = { + 1: 0.02, 2: 0.03, 3: 0.02, 4: 0.01, # Post-harvest + 5: 0.02, 6: 0.03, 7: 0.04, 8: 0.05, # Pre-harvest (higher) + 9: 0.03, 10: -0.02, 11: -0.03, 12: -0.02 # Harvest (lower) + } + return seasonal_factors.get(month, 0) + + def _get_feature_importance(self, feature_names: List[str]) -> Dict[str, float]: + """Get feature importance from trained model""" + if self.model is None or not hasattr(self.model, 'feature_importances_'): + return None + + importances = self.model.feature_importances_ + return { + name: round(float(imp), 4) + for name, imp in zip(feature_names, importances) + } + + +# Global model instance +_forecast_model = None + +def get_forecast_model() -> PriceForecastModel: + """Get or create the price forecast model instance""" + global _forecast_model + if _forecast_model is None: + _forecast_model = PriceForecastModel() + return _forecast_model + + +def forecast_prices( + historical_prices: List[Dict], + location: Optional[Dict] = None, + commodity_type: str = "oilseed", + global_indices: Optional[Dict] = None, + forecast_days: int = 30 +) -> Dict[str, Any]: + """ + Main entry point for price forecasting + + Args: + historical_prices: List of {date, price, volume} dicts + location: {lat, lng, state, district} + commodity_type: Type of commodity + global_indices: Global market indices + forecast_days: Number of days to forecast (7, 30, or 90) + + Returns: + Forecast results with predictions and confidence intervals + """ + model = get_forecast_model() + return model.forecast( + historical_prices=historical_prices, + location=location, + commodity_type=commodity_type, + global_indices=global_indices, + forecast_days=forecast_days + ) diff --git a/ai-backend/model/.gitkeep b/ai-backend/model/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/ai-backend/model_utils.py b/ai-backend/model_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..934e3bed21b6db149a9bfd0d287dd1ff6220cd3f --- /dev/null +++ b/ai-backend/model_utils.py @@ -0,0 +1,169 @@ +"""model_utils.py + +Utilities for loading the image classifier and running inference. +Downloads model weights from Hugging Face Hub at runtime. +Supports the NFNet-F1 (safetensors) and MobileNetV2 (.pth) flows. +""" + +import os +import json +import logging + +import torch +import torch.nn.functional as F +from torchvision import models, transforms +from PIL import Image +from huggingface_hub import hf_hub_download + +logger = logging.getLogger(__name__) + +# HF repo identifiers +HF_REPO_NFNET = os.environ.get( + "HF_REPO_NFNET", "Arko007/nfnet-f1-plant-disease" +) + +# Default assumptions (can be overridden by model config.json) +IMAGENET_MEAN = [0.485, 0.456, 0.406] +IMAGENET_STD = [0.229, 0.224, 0.225] +INPUT_SIZE = 224 + +# Preprocessing transform (resize -> center crop -> to tensor -> normalize) +transform = transforms.Compose([ + transforms.Resize(256), + transforms.CenterCrop(INPUT_SIZE), + transforms.ToTensor(), + transforms.Normalize(IMAGENET_MEAN, IMAGENET_STD) +]) + + +def _download(repo_id, filename): + """Download a file from HF Hub with caching.""" + logger.info("Downloading %s from %s ...", filename, repo_id) + return hf_hub_download(repo_id=repo_id, filename=filename) + + +def load_labels(path): + """Load labels from a text file (one label per line) or return empty list.""" + if path is None: + return [] + with open(path, "r", encoding="utf-8") as f: + return [line.strip() for line in f if line.strip()] + + +def load_remedies(path): + """Load remedies JSON or return empty dict.""" + if path is None: + return {} + with open(path, "r", encoding="utf-8") as f: + return json.load(f) + + +def build_timm_model_from_config(config, checkpoint_path, device): + try: + import timm + except Exception as e: + raise ImportError( + "timm is required to load timm models: pip install timm" + ) from e + + try: + from safetensors.torch import load_file as load_safetensors + except Exception as e: + raise ImportError( + "safetensors is required: pip install safetensors" + ) from e + + class_names = config.get("class_names") or config.get("labels") + if class_names is None: + raise ValueError("config.json must contain 'class_names' list") + + model = timm.create_model( + config["architecture"], pretrained=False, num_classes=len(class_names) + ) + state_dict = load_safetensors(checkpoint_path) + model.load_state_dict(state_dict) + model.to(device) + model.eval() + return model + + +def load_model_from_hf(device): + """ + Download and load the plant-disease model from Hugging Face Hub. + + Loads the NFNet-F1 model (safetensors). + + Returns: model, labels, remedies + """ + global transform + + try: + st_path = _download(HF_REPO_NFNET, "model.safetensors") + cfg_path = _download(HF_REPO_NFNET, "config.json") + + with open(cfg_path, "r", encoding="utf-8") as f: + config = json.load(f) + + labels = config.get("class_names", []) + + # Download labels.txt optionally (if available) + try: + labels_path = _download(HF_REPO_NFNET, "labels.txt") + if os.path.exists(labels_path): + file_labels = load_labels(labels_path) + if len(file_labels) == len(labels): + labels = file_labels + except Exception as e: + logger.warning("Optional labels.txt not found or could not be loaded: %s", e) + + # Download remedies.json optionally (if available) + remedies = {} + try: + remedies_path = _download(HF_REPO_NFNET, "remedies.json") + remedies = load_remedies(remedies_path) + except Exception as e: + logger.warning("Optional remedies.json not found or could not be loaded: %s", e) + + img_size = config.get("input_size", INPUT_SIZE) + mean = config.get("normalization", {}).get("mean", IMAGENET_MEAN) + std = config.get("normalization", {}).get("std", IMAGENET_STD) + transform = transforms.Compose([ + transforms.Resize((img_size, img_size)), + transforms.ToTensor(), + transforms.Normalize(mean=mean, std=std), + ]) + + model = build_timm_model_from_config(config, st_path, device) + logger.info("Loaded NFNet-F1 model from HF Hub (%s)", HF_REPO_NFNET) + return model, labels, remedies + except Exception as e: + raise RuntimeError(f"Failed to load NFNet-F1 model from HF Hub ({HF_REPO_NFNET}): {e}") from e + + +def predict(model, pil_image, labels, device, topk=3, crop_filter=None): + """Return top-1 label, confidence, and topk list of (label, prob).""" + img_t = transform(pil_image).unsqueeze(0).to(device) + with torch.no_grad(): + outputs = model(img_t) + probs = F.softmax(outputs, dim=1) + + # Apply crop filter if provided + if crop_filter: + mask = torch.zeros_like(probs) + for item in crop_filter: + if item in labels: + idx = labels.index(item) + mask[0, idx] = 1.0 + + filtered_probs = probs * mask + sum_probs = filtered_probs.sum(dim=1, keepdim=True) + if sum_probs.item() > 0: + probs = filtered_probs / sum_probs + + actual_topk = min(topk, len(crop_filter)) if crop_filter else topk + top_probs, top_idxs = probs.topk(actual_topk, dim=1) + top_probs = top_probs.cpu().numpy()[0] + top_idxs = top_idxs.cpu().numpy()[0] + top_labels = [labels[i] for i in top_idxs] + return top_labels[0], float(top_probs[0]), list(zip(top_labels, top_probs.tolist())) + diff --git a/ai-backend/price-forecast/__init__.py b/ai-backend/price-forecast/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ee30364ca1e9ee22e20639e1c83e5dff5832d44e --- /dev/null +++ b/ai-backend/price-forecast/__init__.py @@ -0,0 +1 @@ +# Price Forecast Module diff --git a/ai-backend/requirements.txt b/ai-backend/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..26c29e440f54a3dbca6582a8cec52ae26534bcae --- /dev/null +++ b/ai-backend/requirements.txt @@ -0,0 +1,34 @@ +flask==3.1.3 +pillow==12.3.0 +numpy<2,>=1.26.4 + +--extra-index-url https://download.pytorch.org/whl/cpu +torch +torchvision +torchaudio + +huggingface_hub==1.27.0 + +# optional for NFNet-F1 safetensors model +timm==1.0.28 +safetensors==0.8.0 + +flask-cors==6.0.5 +pandas==2.3.3 +scikit-learn==1.5.1 +joblib==1.5.3 +lightgbm==4.7.0 +gunicorn==26.0.0 + +# Retry and testing utilities +tenacity==9.1.4 +pytest==9.1.1 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +httpx==0.28.1 + +# YOLO harvest readiness model +ultralytics==8.4.116 + +# HTTP client for HF Inference API fallback +requests==2.34.2 diff --git a/ai-backend/src/__init__.py b/ai-backend/src/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/ai-backend/src/error_handlers.py b/ai-backend/src/error_handlers.py new file mode 100644 index 0000000000000000000000000000000000000000..d235efb46d63c1b1dd07421a7ffb25326a3f5d6e --- /dev/null +++ b/ai-backend/src/error_handlers.py @@ -0,0 +1,132 @@ +"""Centralized error handlers for Flask application. + +Provides consistent JSON error responses and logging for all exceptions. +""" +import logging +from flask import Flask, jsonify +from werkzeug.exceptions import HTTPException + +from src.logging_config import log_exception + +logger = logging.getLogger('ai_backend.error_handlers') + + +def register_error_handlers(app: Flask) -> None: + """Register centralized error handlers for the Flask app. + + Args: + app: Flask application instance + """ + + @app.errorhandler(400) + def bad_request(error): + """Handle 400 Bad Request errors.""" + logger.warning(f"Bad request: {error}") + return jsonify({ + "error": "Bad Request", + "message": str(error.description) if hasattr(error, 'description') else str(error), + "status": 400 + }), 400 + + @app.errorhandler(404) + def not_found(error): + """Handle 404 Not Found errors.""" + logger.warning(f"Not found: {error}") + return jsonify({ + "error": "Not Found", + "message": "The requested resource was not found", + "status": 404 + }), 404 + + @app.errorhandler(500) + def internal_server_error(error): + """Handle 500 Internal Server Error.""" + log_exception(logger, error, "Internal server error") + return jsonify({ + "error": "Internal Server Error", + "message": "An unexpected error occurred. Please try again later.", + "status": 500 + }), 500 + + @app.errorhandler(HTTPException) + def handle_http_exception(error): + """Handle all HTTP exceptions.""" + logger.warning(f"HTTP exception {error.code}: {error.description}") + return jsonify({ + "error": error.name, + "message": error.description, + "status": error.code + }), error.code + + @app.errorhandler(Exception) + def handle_unexpected_error(error): + """Catch-all handler for unexpected exceptions. + + This prevents unhandled exceptions from returning raw 502 errors. + """ + log_exception(logger, error, "Unexpected error") + + # Never expose internal error details to clients in production + return jsonify({ + "error": "Internal Server Error", + "message": "An unexpected error occurred. Please try again later.", + "status": 500 + }), 500 + + +def validate_content_type(request, expected='application/json'): + """Validate request Content-Type header. + + Args: + request: Flask request object + expected: Expected content type (default: 'application/json') + + Returns: + tuple: (is_valid: bool, error_response: dict or None) + """ + content_type = request.content_type + if not content_type or expected not in content_type: + return False, { + "error": "Invalid Content-Type", + "message": f"Expected Content-Type: {expected}", + "status": 400 + } + return True, None + + +def validate_json_payload(request, required_fields=None): + """Validate JSON payload and required fields. + + Args: + request: Flask request object + required_fields: List of required field names (optional) + + Returns: + tuple: (is_valid: bool, data_or_error: dict) + """ + try: + data = request.get_json(force=False) + if data is None: + return False, { + "error": "Invalid JSON", + "message": "Request body must be valid JSON", + "status": 400 + } + + if required_fields: + missing = [f for f in required_fields if f not in data] + if missing: + return False, { + "error": "Missing required fields", + "message": f"Missing fields: {', '.join(missing)}", + "status": 400 + } + + return True, data + except Exception as e: + logger.warning(f"JSON parsing error: {e}") + return False, { + "error": "Invalid JSON", + "message": "Failed to parse JSON payload", + "status": 400 + } diff --git a/ai-backend/src/logging_config.py b/ai-backend/src/logging_config.py new file mode 100644 index 0000000000000000000000000000000000000000..23fa0806e150006e3354fbd845a6e5d079ee843b --- /dev/null +++ b/ai-backend/src/logging_config.py @@ -0,0 +1,60 @@ +"""Structured logging configuration for AI Backend. + +Provides consistent logging format with stack traces for debugging. +""" +import logging +import sys +from typing import Optional + + +def setup_logging( + level: int = logging.INFO, + format_string: Optional[str] = None +) -> logging.Logger: + """Configure structured logging for the application. + + Args: + level: Logging level (default: INFO) + format_string: Custom format string (optional) + + Returns: + Configured logger instance + """ + if format_string is None: + format_string = ( + '%(asctime)s - %(name)s - %(levelname)s - ' + '%(funcName)s:%(lineno)d - %(message)s' + ) + + # Configure root logger + logging.basicConfig( + level=level, + format=format_string, + handlers=[ + logging.StreamHandler(sys.stdout) + ], + force=True # Override any existing configuration + ) + + logger = logging.getLogger('ai_backend') + logger.setLevel(level) + + return logger + + +def log_exception(logger: logging.Logger, exc: Exception, context: str = ""): + """Log an exception with full stack trace. + + Args: + logger: Logger instance to use + exc: Exception to log + context: Additional context about where the exception occurred + """ + if context: + logger.error(f"{context}: {type(exc).__name__}: {str(exc)}", exc_info=True) + else: + logger.error(f"{type(exc).__name__}: {str(exc)}", exc_info=True) + + +# Module-level logger is intentionally NOT created here to avoid +# double-initializing the root logger before app.py calls setup_logging(). diff --git a/ai-backend/src/models/__init__.py b/ai-backend/src/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/ai-backend/src/models/manager.py b/ai-backend/src/models/manager.py new file mode 100644 index 0000000000000000000000000000000000000000..ecda183c0fc7bd21e6b9828d75264baa912390d1 --- /dev/null +++ b/ai-backend/src/models/manager.py @@ -0,0 +1,393 @@ +"""Model manager for lazy loading and caching ML models. + +Centralizes model loading logic and ensures models are loaded only once +at startup with proper error handling and logging. +""" +import os +import pickle +import logging +from typing import Dict, Any, Optional, Tuple +import torch +import joblib +import numpy as np +from huggingface_hub import hf_hub_download + +from src.logging_config import log_exception +from src.utils.retry_utils import retry_with_backoff + +logger = logging.getLogger('ai_backend.model_manager') + + +# Global model cache +_model_cache: Dict[str, Any] = {} +_device: Optional[torch.device] = None + + +def _is_numpy_binary_compat_error(exc: Exception) -> bool: + """Detect common NumPy 2.x vs SciPy/sklearn binary compatibility errors.""" + error_text = f"{type(exc).__name__}: {exc}".lower() + markers = ( + "numpy.core.multiarray failed to import", + "_array_api not found", + "compiled using numpy 1", + "a numpy version >=", + "node array from the pickle has an incompatible dtype", + ) + return any(marker in error_text for marker in markers) + + +def get_device() -> torch.device: + """Get the torch device (CPU or CUDA). + + Returns: + torch.device instance + """ + global _device + if _device is None: + _device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + logger.info(f"Using device: {_device}") + return _device + + +@retry_with_backoff(max_attempts=3, wait_min=2.0, wait_max=10.0) +def _download_from_hf(repo_id: str, filename: str) -> str: + """Download a file from Hugging Face Hub with retry. + + Args: + repo_id: Hugging Face repository ID + filename: File to download + + Returns: + Path to downloaded file + """ + logger.info(f"Downloading {filename} from {repo_id}...") + return hf_hub_download(repo_id=repo_id, filename=filename) + + +def load_disease_model() -> Tuple[Any, list, dict]: + """Load the disease detection model from HF Hub. + + Returns: + Tuple of (model, labels, remedies) + """ + # Import model_utils which has the loading logic + from model_utils import load_model_from_hf + + device = get_device() + model, labels, remedies = load_model_from_hf(device) + logger.info(f"Disease model loaded β€” {len(labels)} labels") + return model, labels, remedies + + +def load_crop_recommendation_models() -> Dict[str, Any]: + """Load crop recommendation models from HF Hub. + + Returns: + Dictionary containing model, StandardScaler, and MinMaxScaler + """ + repo_id = os.environ.get("HF_REPO_CROP", "Arko007/agromind-crop-recommendation") + + try: + model = joblib.load(_download_from_hf(repo_id, "crop_predict_model.pkl")) + standard_scaler = joblib.load(_download_from_hf(repo_id, "crop_predict_standscaler.pkl")) + minmax_scaler = joblib.load(_download_from_hf(repo_id, "crop_predict_minmaxscaler.pkl")) + logger.info("Crop recommendation models loaded from HF Hub") + except Exception as exc: + if _is_numpy_binary_compat_error(exc): + raise RuntimeError( + "Crop recommendation models failed to load due to NumPy/SciPy binary compatibility. " + "Ensure scikit-learn==1.5.1 and numpy<2 are installed (matching training environment)." + ) from exc + raise + + return { + "model": model, + "standard_scaler": standard_scaler, + "minmax_scaler": minmax_scaler + } + + +def load_fertilizer_models() -> Dict[str, Any]: + """Load fertilizer prediction models from HF Hub. + + Returns: + Dictionary containing classifier and label_encoder + """ + repo_id = os.environ.get("HF_REPO_FERTILIZER", "Arko007/agromind-fertilizer-prediction") + + try: + with open(_download_from_hf(repo_id, "classifier.pkl"), "rb") as f: + classifier = pickle.load(f) + with open(_download_from_hf(repo_id, "fertilizer.pkl"), "rb") as f: + label_encoder = pickle.load(f) + logger.info("Fertilizer prediction models loaded from HF Hub") + except Exception as exc: + if _is_numpy_binary_compat_error(exc): + raise RuntimeError( + "Fertilizer models failed to load due to NumPy/SciPy binary compatibility. " + "Ensure scikit-learn==1.5.1 and numpy<2 are installed (matching training environment)." + ) from exc + raise + + return { + "classifier": classifier, + "label_encoder": label_encoder + } + + +def load_loan_models() -> Dict[str, Any]: + """Load loan prediction models from HF Hub. + + Returns: + Dictionary containing price_model and approval_model + """ + repo_id = os.environ.get("HF_REPO_LOAN", "Arko007/agromind-loan-prediction") + + try: + price_model = joblib.load(_download_from_hf(repo_id, "price_model.pkl")) + approval_model = joblib.load(_download_from_hf(repo_id, "approval_model.pkl")) + logger.info("Loan prediction models loaded from HF Hub") + except Exception as exc: + if _is_numpy_binary_compat_error(exc): + raise RuntimeError( + "Loan models failed to load due to NumPy/SciPy binary compatibility. " + "Ensure scikit-learn==1.5.1 and numpy<2 are installed (matching training environment)." + ) from exc + raise + + return { + "price_model": price_model, + "approval_model": approval_model + } + + +def initialize_models(load_all: bool = True) -> None: + """Initialize all models at startup. + + This function should be called during application startup to load + all models into the cache. Models that fail to load will be logged + but won't crash the application. + + Args: + load_all: If True, attempts to load all models. If False, only loads on-demand. + """ + if not load_all: + logger.info("Model lazy-loading enabled. Models will load on first use.") + return + + logger.info("Initializing all models...") + + # Load disease model + try: + model, labels, remedies = load_disease_model() + _model_cache['disease_model'] = model + _model_cache['disease_labels'] = labels + _model_cache['disease_remedies'] = remedies + except Exception as e: + log_exception(logger, e, "Failed to load disease model") + _model_cache['disease_model'] = None + _model_cache['disease_labels'] = [] + _model_cache['disease_remedies'] = {} + + # Load crop recommendation models + try: + crop_models = load_crop_recommendation_models() + _model_cache['crop_model'] = crop_models['model'] + _model_cache['crop_standard_scaler'] = crop_models['standard_scaler'] + _model_cache['crop_minmax_scaler'] = crop_models['minmax_scaler'] + except Exception as e: + log_exception(logger, e, "Failed to load crop recommendation models") + _model_cache['crop_model'] = None + _model_cache['crop_standard_scaler'] = None + _model_cache['crop_minmax_scaler'] = None + + # Load fertilizer models + try: + fertilizer_models = load_fertilizer_models() + _model_cache['fertilizer_classifier'] = fertilizer_models['classifier'] + _model_cache['fertilizer_label_encoder'] = fertilizer_models['label_encoder'] + except Exception as e: + log_exception(logger, e, "Failed to load fertilizer models") + _model_cache['fertilizer_classifier'] = None + _model_cache['fertilizer_label_encoder'] = None + + # Load loan models + try: + loan_models = load_loan_models() + _model_cache['loan_price_model'] = loan_models['price_model'] + _model_cache['loan_approval_model'] = loan_models['approval_model'] + except Exception as e: + log_exception(logger, e, "Failed to load loan models") + _model_cache['loan_price_model'] = None + _model_cache['loan_approval_model'] = None + + logger.info("Model initialization complete") + + +def get_model(model_name: str, auto_load: bool = True) -> Optional[Any]: + """Get a model from the cache. + + Args: + model_name: Name of the model to retrieve + auto_load: If True and model not in cache, attempt to load it + + Returns: + Model instance or None if not available + """ + if model_name in _model_cache: + return _model_cache[model_name] + + if not auto_load: + return None + + # Attempt to load on-demand + logger.info(f"Model '{model_name}' not in cache, loading on-demand...") + + try: + if model_name == 'disease_model': + model, labels, remedies = load_disease_model() + _model_cache['disease_model'] = model + _model_cache['disease_labels'] = labels + _model_cache['disease_remedies'] = remedies + return model + elif 'crop' in model_name: + crop_models = load_crop_recommendation_models() + _model_cache['crop_model'] = crop_models['model'] + _model_cache['crop_standard_scaler'] = crop_models['standard_scaler'] + _model_cache['crop_minmax_scaler'] = crop_models['minmax_scaler'] + return _model_cache.get(model_name) + elif 'fertilizer' in model_name: + fertilizer_models = load_fertilizer_models() + _model_cache['fertilizer_classifier'] = fertilizer_models['classifier'] + _model_cache['fertilizer_label_encoder'] = fertilizer_models['label_encoder'] + return _model_cache.get(model_name) + elif 'loan' in model_name: + loan_models = load_loan_models() + _model_cache['loan_price_model'] = loan_models['price_model'] + _model_cache['loan_approval_model'] = loan_models['approval_model'] + return _model_cache.get(model_name) + except Exception as e: + log_exception(logger, e, f"Failed to load model '{model_name}'") + return None + + return None + + +def predict_crop(features: np.ndarray) -> int: + """Predict crop recommendation from features. + + Args: + features: NumPy array of shape (1, 7) with [N, P, K, temp, humidity, ph, rainfall] + + Returns: + Predicted crop ID (integer) + + Raises: + RuntimeError: If models are not loaded + """ + model = get_model('crop_model') + minmax_scaler = get_model('crop_minmax_scaler') + standard_scaler = get_model('crop_standard_scaler') + + if model is None or minmax_scaler is None or standard_scaler is None: + raise RuntimeError("Crop recommendation models not loaded") + + # Scale features + scaled_features = minmax_scaler.transform(features) + final_features = standard_scaler.transform(scaled_features) + + # Make prediction + prediction = model.predict(final_features) + return int(prediction[0]) + + +def predict_fertilizer(features: np.ndarray) -> str: + """Predict fertilizer recommendation from features. + + Args: + features: NumPy array with soil and crop features + + Returns: + Predicted fertilizer name (string) + + Raises: + RuntimeError: If models are not loaded + """ + classifier = get_model('fertilizer_classifier') + label_encoder = get_model('fertilizer_label_encoder') + + if classifier is None or label_encoder is None: + raise RuntimeError("Fertilizer prediction models not loaded") + + # Make prediction + prediction = classifier.predict(features) + fertilizer = label_encoder.inverse_transform(prediction) + return str(fertilizer[0]) + + +def predict_disease(pil_image, topk: int = 3) -> Tuple[str, float, list]: + """Predict disease from plant image. + + Args: + pil_image: PIL Image object + topk: Number of top predictions to return + + Returns: + Tuple of (top_label, confidence, top_k_predictions) + + Raises: + RuntimeError: If model is not loaded + """ + from model_utils import predict + + model = get_model('disease_model') + labels = get_model('disease_labels') + + if model is None or not labels: + raise RuntimeError("Disease model not loaded") + + device = get_device() + return predict(model, pil_image, labels, device, topk=topk) + + +def get_disease_remedy(label: str) -> Optional[str]: + """Get remedy for a disease label. + + Args: + label: Disease label + + Returns: + Remedy string or None if not found + """ + remedies = get_model('disease_remedies') + if remedies is None: + return None + return remedies.get(label) + + +def is_model_loaded(model_name: str) -> bool: + """Check if a model is loaded in the cache. + + Args: + model_name: Name of the model to check + + Returns: + True if model is loaded and not None, False otherwise + """ + return model_name in _model_cache and _model_cache[model_name] is not None + + +def get_model_status() -> Dict[str, bool]: + """Get the status of all models. + + Returns: + Dictionary mapping model names to their loaded status + """ + return { + 'disease_model': is_model_loaded('disease_model'), + 'crop_model': is_model_loaded('crop_model'), + 'fertilizer_classifier': is_model_loaded('fertilizer_classifier'), + 'loan_price_model': is_model_loaded('loan_price_model'), + 'loan_approval_model': is_model_loaded('loan_approval_model'), + 'harvest_readiness_model': is_model_loaded('harvest_readiness_model'), + } diff --git a/ai-backend/src/utils/__init__.py b/ai-backend/src/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/ai-backend/src/utils/retry_utils.py b/ai-backend/src/utils/retry_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..ef54cc63514dbb56a91b6bfe794b348fc3038836 --- /dev/null +++ b/ai-backend/src/utils/retry_utils.py @@ -0,0 +1,165 @@ +"""Retry utilities with exponential backoff. + +Provides decorators for retrying operations with configurable backoff. +Uses tenacity library for robust retry logic. +""" +import logging +from functools import wraps +from typing import Callable, Optional, Type, Tuple +import time + +try: + from tenacity import ( + retry, + stop_after_attempt, + wait_exponential, + retry_if_exception_type, + before_sleep_log, + RetryError + ) + HAS_TENACITY = True +except ImportError: + HAS_TENACITY = False + +logger = logging.getLogger('ai_backend.retry_utils') + + +def retry_with_backoff( + max_attempts: int = 3, + wait_min: float = 1.0, + wait_max: float = 10.0, + retry_on_exceptions: Optional[Tuple[Type[Exception], ...]] = None +) -> Callable: + """Decorator to retry a function with exponential backoff. + + Args: + max_attempts: Maximum number of retry attempts (default: 3) + wait_min: Minimum wait time in seconds (default: 1.0) + wait_max: Maximum wait time in seconds (default: 10.0) + retry_on_exceptions: Tuple of exception types to retry on (default: all exceptions) + + Returns: + Decorated function with retry logic + + Example: + @retry_with_backoff(max_attempts=3, wait_min=1.0, wait_max=10.0) + def call_external_api(): + response = requests.get("https://api.example.com/data") + response.raise_for_status() + return response.json() + """ + if HAS_TENACITY: + # Use tenacity for robust retry logic + if retry_on_exceptions: + retry_condition = retry_if_exception_type(retry_on_exceptions) + else: + retry_condition = retry_if_exception_type(Exception) + + return retry( + stop=stop_after_attempt(max_attempts), + wait=wait_exponential(multiplier=wait_min, max=wait_max), + retry=retry_condition, + before_sleep=before_sleep_log(logger, logging.WARNING), + reraise=True + ) + else: + # Fallback to simple retry logic if tenacity is not available + def decorator(func: Callable) -> Callable: + @wraps(func) + def wrapper(*args, **kwargs): + last_exception = None + for attempt in range(max_attempts): + try: + return func(*args, **kwargs) + except Exception as e: + last_exception = e + if retry_on_exceptions and not isinstance(e, retry_on_exceptions): + # Don't retry if it's not a retryable exception + raise + + if attempt < max_attempts - 1: + # Calculate wait time with exponential backoff + wait_time = min(wait_min * (2 ** attempt), wait_max) + logger.warning( + f"Attempt {attempt + 1}/{max_attempts} failed: {e}. " + f"Retrying in {wait_time:.1f}s..." + ) + time.sleep(wait_time) + else: + logger.error( + f"All {max_attempts} attempts failed. Last error: {e}" + ) + + # Raise the last exception if all attempts failed + if last_exception: + raise last_exception + + return wrapper + return decorator + + +def retry_model_inference( + max_attempts: int = 2, + wait_min: float = 0.5, + wait_max: float = 2.0 +) -> Callable: + """Specialized retry decorator for model inference operations. + + Uses shorter wait times and fewer attempts since model inference + failures are typically not transient. + + Args: + max_attempts: Maximum number of retry attempts (default: 2) + wait_min: Minimum wait time in seconds (default: 0.5) + wait_max: Maximum wait time in seconds (default: 2.0) + + Returns: + Decorated function with retry logic + """ + return retry_with_backoff( + max_attempts=max_attempts, + wait_min=wait_min, + wait_max=wait_max, + retry_on_exceptions=(RuntimeError, OSError, IOError) + ) + + +def with_timeout(timeout_seconds: float) -> Callable: + """Decorator to add timeout to a function. + + Note: This is a simple implementation. For production use with true + timeouts on blocking operations, consider using concurrent.futures + or signal-based timeouts. + + Args: + timeout_seconds: Maximum execution time in seconds + + Returns: + Decorated function with timeout + """ + def decorator(func: Callable) -> Callable: + @wraps(func) + def wrapper(*args, **kwargs): + import signal + + def timeout_handler(signum, frame): + raise TimeoutError(f"Function {func.__name__} timed out after {timeout_seconds}s") + + # Set up signal handler (Unix-like systems only) + try: + signal.signal(signal.SIGALRM, timeout_handler) + signal.alarm(int(timeout_seconds)) + try: + result = func(*args, **kwargs) + finally: + signal.alarm(0) # Cancel the alarm + return result + except AttributeError: + # SIGALRM not available (e.g., on Windows) + logger.warning( + f"Timeout decorator not supported on this platform for {func.__name__}" + ) + return func(*args, **kwargs) + + return wrapper + return decorator diff --git a/ai-backend/tests/conftest.py b/ai-backend/tests/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..813873eabfa576136bb698dad2c4ce8630f0eba8 --- /dev/null +++ b/ai-backend/tests/conftest.py @@ -0,0 +1,187 @@ +"""Pytest configuration and shared fixtures for AI Backend tests.""" +import pytest +import sys +import os +from unittest.mock import MagicMock, Mock +import numpy as np + +# Add parent directory to path for imports +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) + + +@pytest.fixture +def app(): + """Create Flask app for testing.""" + # Import app here to avoid loading models during test collection + from app import app as flask_app + flask_app.config['TESTING'] = True + return flask_app + + +@pytest.fixture +def client(app): + """Create test client for Flask app.""" + return app.test_client() + + +@pytest.fixture +def mock_disease_model(): + """Mock disease detection model.""" + model = MagicMock() + labels = ["healthy", "bacterial_blight", "leaf_spot", "rust"] + remedies = { + "bacterial_blight": "Apply copper-based fungicide", + "leaf_spot": "Remove infected leaves, apply fungicide", + "rust": "Apply sulfur-based fungicide" + } + return model, labels, remedies + + +@pytest.fixture +def mock_crop_model(): + """Mock crop recommendation model and scalers.""" + model = MagicMock() + model.predict = MagicMock(return_value=np.array([1])) # Returns "Rice" + + standard_scaler = MagicMock() + standard_scaler.transform = MagicMock(side_effect=lambda x: x) + + minmax_scaler = MagicMock() + minmax_scaler.transform = MagicMock(side_effect=lambda x: x) + + return { + 'model': model, + 'standard_scaler': standard_scaler, + 'minmax_scaler': minmax_scaler + } + + +@pytest.fixture +def mock_fertilizer_model(): + """Mock fertilizer prediction model.""" + classifier = MagicMock() + classifier.predict = MagicMock(return_value=np.array([0])) + + label_encoder = MagicMock() + label_encoder.inverse_transform = MagicMock(return_value=np.array(["Urea"])) + + return { + 'classifier': classifier, + 'label_encoder': label_encoder + } + + +@pytest.fixture +def mock_loan_models(): + """Mock loan prediction models.""" + price_model = MagicMock() + price_model.predict = MagicMock(return_value=np.array([50000])) + + approval_model = MagicMock() + approval_model.predict = MagicMock(return_value=np.array([1])) + + return { + 'price_model': price_model, + 'approval_model': approval_model + } + + +@pytest.fixture +def sample_crop_input(): + """Sample input for crop recommendation.""" + return { + "N": 50, + "P": 30, + "K": 40, + "temperature": 28, + "humidity": 65, + "ph": 6.5, + "rainfall": 200 + } + + +@pytest.fixture +def sample_fertilizer_input(): + """Sample input for fertilizer prediction.""" + return { + "temperature": 28, + "humidity": 65, + "moisture": 45, + "soil_type": "Loamy", + "crop_type": "Wheat", + "nitrogen": 50, + "potassium": 40, + "phosphorus": 30 + } + + +@pytest.fixture +def sample_loan_input(): + """Sample input for loan prediction.""" + return { + "area": 5.5, + "land_contour": "flat", + "distance_from_road": 2.0, + "soil_type": "loam", + "income": 150000, + "loan_request": 50000 + } + + +@pytest.fixture +def mock_pil_image(): + """Mock PIL Image for disease detection.""" + try: + from PIL import Image + import io + # Create a simple 224x224 RGB image + img = Image.new('RGB', (224, 224), color='green') + return img + except ImportError: + return None + + +@pytest.fixture +def sample_price_forecast_input(): + """Sample input for price forecasting.""" + return { + "commodity_type": "wheat", + "historical_prices": [ + {"date": "2026-01-01", "price": 55, "volume": 1000}, + {"date": "2026-01-02", "price": 56, "volume": 1000}, + {"date": "2026-01-03", "price": 54, "volume": 1000}, + {"date": "2026-01-04", "price": 57, "volume": 1000}, + {"date": "2026-01-05", "price": 55, "volume": 1000} + ], + "forecast_days": 7 + } + + +@pytest.fixture +def sample_yield_input(): + """Sample input for yield prediction.""" + return { + "crop_type": "groundnut", + "area_hectares": 5, + "soil_data": {"nitrogen": 50, "phosphorus": 30, "potassium": 40, "ph": 6.5}, + "weather_data": {"rainfall": 800, "temperature": 28, "humidity": 65} + } + + +@pytest.fixture +def sample_tariff_input(): + """Sample input for tariff simulation.""" + return { + "tariff_pct": 45, + "period": "6_months", + "global_price_shock": 0 + } + + +@pytest.fixture(autouse=True) +def reset_model_cache(): + """Reset model cache before each test.""" + from src.models import manager + manager._model_cache.clear() + yield + manager._model_cache.clear() diff --git a/ai-backend/tests/test_api_integration.py b/ai-backend/tests/test_api_integration.py new file mode 100644 index 0000000000000000000000000000000000000000..6ae212ec83eb9f34f5c300e2c246272d78e9f2aa --- /dev/null +++ b/ai-backend/tests/test_api_integration.py @@ -0,0 +1,552 @@ +"""Integration tests for API endpoints. + +Tests all endpoints with various scenarios including: +- Happy path with valid inputs +- Invalid inputs and validation +- Error handling and retry logic +- Malformed JSON payloads +""" +import pytest +import json +import io +from unittest.mock import patch, MagicMock +import sys +import os + +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) + + +class TestHealthEndpoint: + """Test health check endpoint.""" + + def test_health_endpoint_returns_200(self, client): + """Health endpoint should return 200 OK.""" + response = client.get('/health') + assert response.status_code == 200 + data = response.get_json() + assert data['status'] == 'ok' + + def test_root_endpoint_returns_200(self, client): + """Root endpoint should return welcome message.""" + response = client.get('/') + assert response.status_code == 200 + data = response.get_json() + assert 'message' in data + + +class TestCropRecommendationEndpoint: + """Test crop recommendation endpoint.""" + + def test_crop_recommendation_happy_path( + self, client, sample_crop_input + ): + """Test successful crop recommendation.""" + from src.models import manager + # Inject mocks into model cache + mock_model = MagicMock() + mock_model.predict = MagicMock(return_value=[1]) # Rice + mock_ms = MagicMock() + mock_ms.transform = MagicMock(side_effect=lambda x: x) + mock_sc = MagicMock() + mock_sc.transform = MagicMock(side_effect=lambda x: x) + manager._model_cache['crop_model'] = mock_model + manager._model_cache['crop_minmax_scaler'] = mock_ms + manager._model_cache['crop_standard_scaler'] = mock_sc + + response = client.post( + '/crop_recommendation', + data=json.dumps(sample_crop_input), + content_type='application/json' + ) + + assert response.status_code == 200 + data = response.get_json() + assert data['success'] is True + assert 'crop' in data + assert 'message' in data + assert 'prediction_id' in data + + def test_crop_recommendation_missing_field(self, client): + """Test crop recommendation with missing required field.""" + incomplete_data = { + "N": 50, + "P": 30, + # Missing K and other fields + } + + response = client.post( + '/crop_recommendation', + data=json.dumps(incomplete_data), + content_type='application/json' + ) + + assert response.status_code == 400 + data = response.get_json() + assert 'error' in data + + def test_crop_recommendation_invalid_range(self, client, sample_crop_input): + """Test crop recommendation with out-of-range values.""" + sample_crop_input['N'] = 150 # Out of valid range (0-100) + + response = client.post( + '/crop_recommendation', + data=json.dumps(sample_crop_input), + content_type='application/json' + ) + + assert response.status_code == 400 + data = response.get_json() + assert 'error' in data + + def test_crop_recommendation_invalid_json(self, client): + """Test crop recommendation with malformed JSON.""" + response = client.post( + '/crop_recommendation', + data='invalid json{', + content_type='application/json' + ) + + assert response.status_code in [400, 500] + + def test_crop_recommendation_invalid_data_type(self, client): + """Test crop recommendation with invalid data types.""" + invalid_data = { + "N": "not_a_number", + "P": 30, + "K": 40, + "temperature": 28, + "humidity": 65, + "ph": 6.5, + "rainfall": 200 + } + + response = client.post( + '/crop_recommendation', + data=json.dumps(invalid_data), + content_type='application/json' + ) + + assert response.status_code == 400 + data = response.get_json() + assert 'error' in data + + def test_crop_recommendation_model_not_loaded(self, client, sample_crop_input): + """Test crop recommendation when model is not loaded.""" + from src.models import manager + manager._model_cache['crop_model'] = None + manager._model_cache['crop_minmax_scaler'] = None + manager._model_cache['crop_standard_scaler'] = None + response = client.post( + '/crop_recommendation', + data=json.dumps(sample_crop_input), + content_type='application/json' + ) + + assert response.status_code == 500 + data = response.get_json() + assert 'error' in data + + +class TestFertilizerPredictionEndpoint: + """Test fertilizer prediction endpoint.""" + + def test_fertilizer_prediction_happy_path( + self, client, sample_fertilizer_input + ): + """Test successful fertilizer prediction.""" + import numpy as np + from src.models import manager + # Inject mocks into model cache + mock_classifier = MagicMock() + mock_classifier.predict = MagicMock(return_value=np.array([0])) + mock_encoder = MagicMock() + mock_encoder.inverse_transform = MagicMock(return_value=np.array(["Urea"])) + manager._model_cache['fertilizer_classifier'] = mock_classifier + manager._model_cache['fertilizer_label_encoder'] = mock_encoder + + response = client.post( + '/fertilizer_prediction', + data=json.dumps(sample_fertilizer_input), + content_type='application/json' + ) + + assert response.status_code == 200 + data = response.get_json() + assert 'fertilizer' in data + + def test_fertilizer_prediction_missing_field(self, client): + """Test fertilizer prediction with missing fields.""" + incomplete_data = { + "temperature": 28, + "humidity": 65, + # Missing other required fields + } + + response = client.post( + '/fertilizer_prediction', + data=json.dumps(incomplete_data), + content_type='application/json' + ) + + assert response.status_code == 400 + data = response.get_json() + assert 'error' in data + + def test_fertilizer_prediction_invalid_soil_type(self, client, sample_fertilizer_input): + """Test fertilizer prediction with invalid soil type.""" + sample_fertilizer_input['soil_type'] = "InvalidSoil" + + response = client.post( + '/fertilizer_prediction', + data=json.dumps(sample_fertilizer_input), + content_type='application/json' + ) + + # Should return 400 for invalid soil type + assert response.status_code in [400, 500] + + +class TestDiseasePredictionEndpoint: + """Test disease prediction endpoint.""" + + @patch('app.predict') + def test_disease_prediction_happy_path( + self, mock_predict, client, mock_pil_image + ): + """Test successful disease prediction.""" + if mock_pil_image is None: + pytest.skip("PIL not available") + + from src.models import manager + mock_model = MagicMock() + manager._model_cache['disease_model'] = mock_model + manager._model_cache['disease_labels'] = ["healthy", "bacterial_blight", "leaf_spot"] + manager._model_cache['disease_remedies'] = {"bacterial_blight": "Apply copper-based fungicide"} + + mock_predict.return_value = ("bacterial_blight", 0.95, [ + ("bacterial_blight", 0.95), + ("leaf_spot", 0.03), + ("healthy", 0.02) + ]) + + # Create image bytes + img_byte_arr = io.BytesIO() + mock_pil_image.save(img_byte_arr, format='PNG') + img_byte_arr.seek(0) + + response = client.post( + '/predict_disease', + data={'file': (img_byte_arr, 'test.png')}, + content_type='multipart/form-data' + ) + + assert response.status_code == 200 + data = response.get_json() + assert 'label' in data + assert 'confidence' in data + + def test_disease_prediction_no_file(self, client): + """Test disease prediction without file.""" + response = client.post( + '/predict_disease', + data={}, + content_type='multipart/form-data' + ) + + assert response.status_code == 400 + data = response.get_json() + assert 'error' in data + + def test_disease_prediction_model_not_loaded(self, client, mock_pil_image): + """Test disease prediction when model not loaded.""" + if mock_pil_image is None: + pytest.skip("PIL not available") + + from src.models import manager + manager._model_cache['disease_model'] = None + + img_byte_arr = io.BytesIO() + mock_pil_image.save(img_byte_arr, format='PNG') + img_byte_arr.seek(0) + + response = client.post( + '/predict_disease', + data={'file': (img_byte_arr, 'test.png')}, + content_type='multipart/form-data' + ) + + assert response.status_code == 503 + data = response.get_json() + assert 'error' in data + + +class TestLoanPredictionEndpoint: + """Test loan prediction endpoint.""" + + def test_loan_prediction_happy_path( + self, client, sample_loan_input + ): + """Test successful loan prediction.""" + import numpy as np + from src.models import manager + # Inject mocks with feature_names_in_ for column ordering + mock_price = MagicMock() + mock_price.predict = MagicMock(return_value=np.array([50000])) + mock_price.feature_names_in_ = [ + 'area', 'distance_from_road', 'income', + 'land_contour_hilly', 'land_contour_sloping', + 'soil_type_clay', 'soil_type_sandy', 'soil_type_silty' + ] + mock_approval = MagicMock() + mock_approval.predict = MagicMock(return_value=np.array([1])) + manager._model_cache['loan_price_model'] = mock_price + manager._model_cache['loan_approval_model'] = mock_approval + + response = client.post( + '/loan_prediction', + data=json.dumps(sample_loan_input), + content_type='application/json' + ) + + assert response.status_code == 200 + data = response.get_json() + assert 'predicted_price' in data or 'approval_status' in data + + def test_loan_prediction_missing_fields(self, client): + """Test loan prediction with missing fields.""" + incomplete_data = { + "farmer_age": 35, + # Missing other fields + } + + response = client.post( + '/loan_prediction', + data=json.dumps(incomplete_data), + content_type='application/json' + ) + + assert response.status_code == 400 + data = response.get_json() + assert 'error' in data + + +class TestPriceForecastEndpoint: + """Test price forecast endpoint.""" + + def test_price_forecast_happy_path(self, client, sample_price_forecast_input): + """Test successful price forecast.""" + response = client.post( + '/ai/price-forecast', + data=json.dumps(sample_price_forecast_input), + content_type='application/json' + ) + + assert response.status_code == 200 + data = response.get_json() + assert data.get('success') is True + assert 'data' in data + + def test_price_forecast_insufficient_data(self, client): + """Test price forecast with insufficient historical data.""" + insufficient_data = { + "commodity": "wheat", + "historical_data": [ + {"date": "2026-01-01", "price": 55}, + {"date": "2026-01-02", "price": 56} + ], + "forecast_days": 7 + } + + response = client.post( + '/ai/price-forecast', + data=json.dumps(insufficient_data), + content_type='application/json' + ) + + assert response.status_code == 400 + data = response.get_json() + assert 'error' in data + + def test_price_forecast_invalid_days(self, client, sample_price_forecast_input): + """Test price forecast with invalid forecast days.""" + sample_price_forecast_input['forecast_days'] = 365 # Invalid + + response = client.post( + '/ai/price-forecast', + data=json.dumps(sample_price_forecast_input), + content_type='application/json' + ) + + # Should either reject or default to valid value + assert response.status_code in [200, 400] + + +class TestYieldPredictionEndpoint: + """Test yield prediction endpoint.""" + + def test_yield_prediction_happy_path(self, client, sample_yield_input): + """Test successful yield prediction.""" + response = client.post( + '/ai/yield-predict', + data=json.dumps(sample_yield_input), + content_type='application/json' + ) + + assert response.status_code == 200 + data = response.get_json() + assert data.get('success') is True + assert data['data']['predicted_yield_kg_per_ha'] > 0 + + def test_yield_prediction_unknown_crop(self, client, sample_yield_input): + """Test yield prediction with unknown crop.""" + sample_yield_input['crop'] = "unknown_crop_xyz" + + response = client.post( + '/ai/yield-predict', + data=json.dumps(sample_yield_input), + content_type='application/json' + ) + + # Unknown crops get a default yield, endpoint returns 200 with default + assert response.status_code == 200 + + +class TestTariffSimulationEndpoint: + """Test tariff simulation endpoint.""" + + def test_tariff_simulation_happy_path(self, client, sample_tariff_input): + """Test successful tariff simulation.""" + response = client.post( + '/ai/tariff-simulate', + data=json.dumps(sample_tariff_input), + content_type='application/json' + ) + + assert response.status_code == 200 + data = response.get_json() + assert data.get('success') is True + assert 'data' in data + assert 'sensitivity_analysis' in data['data'] + + def test_tariff_simulation_missing_fields(self, client): + """Test tariff simulation with missing fields.""" + incomplete_data = { + "commodity": "wheat", + "current_tariff_pct": 35 + # Missing other fields + } + + response = client.post( + '/ai/tariff-simulate', + data=json.dumps(incomplete_data), + content_type='application/json' + ) + + # Endpoint uses defaults for all fields - returns 200 always + assert response.status_code == 200 + + +class TestCROPICEndpoint: + """Test CROPIC crop damage analysis endpoint.""" + + def test_cropic_analyze_happy_path(self, client, mock_pil_image): + """Test successful CROPIC analysis.""" + if mock_pil_image is None: + pytest.skip("PIL not available") + + img_byte_arr = io.BytesIO() + mock_pil_image.save(img_byte_arr, format='PNG') + img_byte_arr.seek(0) + + response = client.post( + '/ai/cropic/analyze', + data={'file': (img_byte_arr, 'crop.png')}, + content_type='multipart/form-data' + ) + + assert response.status_code == 200 + data = response.get_json() + assert data.get('success') is True + assert 'damage_type' in data['data'] + assert 'damage_percentage' in data['data'] + assert 'recommendations' in data['data'] + + def test_cropic_analyze_no_image(self, client): + """Test CROPIC analysis without image.""" + response = client.post( + '/ai/cropic/analyze', + data={}, + content_type='multipart/form-data' + ) + + assert response.status_code == 400 + data = response.get_json() + assert 'error' in data + + +class TestErrorHandling: + """Test error handling across endpoints.""" + + def test_404_not_found(self, client): + """Test 404 error for non-existent endpoint.""" + response = client.get('/nonexistent') + assert response.status_code == 404 + + def test_405_method_not_allowed(self, client): + """Test 405 error for wrong HTTP method.""" + response = client.get('/crop_recommendation') # Should be POST + assert response.status_code == 405 + + @pytest.mark.parametrize("endpoint", [ + "/crop_recommendation", + "/fertilizer_prediction", + "/loan_prediction", + "/ai/price-forecast", + "/ai/yield-predict", + "/ai/tariff-simulate" + ]) + def test_missing_content_type(self, client, endpoint): + """Test endpoints with missing Content-Type header.""" + response = client.post( + endpoint, + data='{"test": "data"}' + # No content_type specified + ) + + # Should handle gracefully, either 400 or attempt to parse + assert response.status_code in [200, 400, 415, 500] + + +class TestRetryBehavior: + """Test retry behavior with transient failures.""" + + def test_transient_failure_then_success( + self, client, sample_crop_input + ): + """Test that transient failures are retried successfully.""" + from src.models import manager + # Inject mocks into model cache + mock_model = MagicMock() + mock_model.predict = MagicMock(side_effect=[ + Exception("Transient error"), + [1] # Success on retry + ]) + mock_ms = MagicMock() + mock_ms.transform = MagicMock(side_effect=lambda x: x) + mock_sc = MagicMock() + mock_sc.transform = MagicMock(side_effect=lambda x: x) + manager._model_cache['crop_model'] = mock_model + manager._model_cache['crop_minmax_scaler'] = mock_ms + manager._model_cache['crop_standard_scaler'] = mock_sc + + # Note: This test will only work if retry logic is implemented + # For now, it will fail on first exception + response = client.post( + '/crop_recommendation', + data=json.dumps(sample_crop_input), + content_type='application/json' + ) + + # Without retry wrapper, this will return 500 + # With retry wrapper, should succeed + assert response.status_code in [200, 500] diff --git a/ai-backend/tests/test_endpoints.py b/ai-backend/tests/test_endpoints.py new file mode 100644 index 0000000000000000000000000000000000000000..a73ee780b2c29631ce7b4ea26a439638f4b9a306 --- /dev/null +++ b/ai-backend/tests/test_endpoints.py @@ -0,0 +1,464 @@ +""" +AI Backend Tests +""" +import pytest +import json +import sys +import os + +# Add parent directory to path +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) + + +class TestHealthEndpoint: + """Test health check endpoint""" + + def test_health_response_format(self): + """Health endpoint should return correct format""" + expected_keys = {"status", "message"} + # Simulating expected response structure + response = {"status": "healthy", "message": "API is running"} + assert set(response.keys()) == expected_keys + assert response["status"] == "healthy" + + +class TestPriceForecast: + """Test price forecasting functionality""" + + def test_minimum_data_points_required(self): + """Should require at least 5 historical data points""" + min_required = 5 + short_data = [{"date": "2026-01-01", "price": 55}] * 4 + long_data = [{"date": "2026-01-01", "price": 55}] * 5 + + assert len(short_data) < min_required + assert len(long_data) >= min_required + + def test_forecast_days_validation(self): + """Forecast days should be 7, 30, or 90""" + valid_days = [7, 30, 90] + + for days in valid_days: + assert days in [7, 30, 90] + + # Invalid should default to 30 + invalid_days = 45 + default_days = 30 if invalid_days not in valid_days else invalid_days + assert default_days == 30 + + def test_confidence_interval_calculation(self): + """Confidence intervals should widen with forecast horizon""" + import math + + daily_volatility = 0.02 + last_price = 55 + + ci_day_1 = daily_volatility * last_price * math.sqrt(1) * 1.96 + ci_day_30 = daily_volatility * last_price * math.sqrt(30) * 1.96 + + assert ci_day_30 > ci_day_1 + assert ci_day_30 == pytest.approx(ci_day_1 * math.sqrt(30), rel=0.01) + + def test_feature_preparation(self): + """Feature preparation should produce valid arrays""" + # Sample historical data + historical_prices = [ + {"date": "2026-01-01", "price": 55, "volume": 1000}, + {"date": "2026-01-02", "price": 56, "volume": 1200}, + {"date": "2026-01-03", "price": 54, "volume": 900}, + {"date": "2026-01-04", "price": 57, "volume": 1100}, + {"date": "2026-01-05", "price": 55, "volume": 1050}, + ] + + prices = [p["price"] for p in historical_prices] + + # Basic statistics using standard library + price_mean = sum(prices) / len(prices) + price_min = min(prices) + price_max = max(prices) + + assert price_mean == pytest.approx(55.4, rel=0.01) + assert price_min == 54 + assert price_max == 57 + + +class TestYieldPrediction: + """Test yield prediction functionality""" + + def test_base_yield_lookup(self): + """Should return base yield for known crops""" + base_yields = { + "groundnut": 1800, + "sunflower": 1200, + "soybean": 2000, + "mustard": 1100, + } + + for crop, yield_value in base_yields.items(): + assert yield_value > 0 + assert crop in base_yields + + def test_soil_factor_calculation(self): + """Soil factor should be between 0.5 and 1.5""" + # Test optimal conditions + n, p, k = 50, 30, 40 + soil_factor = 1.0 + + if 40 <= n <= 60 and 25 <= p <= 40 and 30 <= k <= 50: + soil_factor = 1.1 + + assert 0.5 <= soil_factor <= 1.5 + + def test_weather_factor_calculation(self): + """Weather factor should adjust based on rainfall and temperature""" + rainfall = 800 + temp = 28 + weather_factor = 1.0 + + if 600 <= rainfall <= 1000: + weather_factor = 1.1 + + if 25 <= temp <= 32: + weather_factor *= 1.05 + + assert weather_factor == pytest.approx(1.155, rel=0.01) + + +class TestTariffSimulation: + """Test tariff impact simulation""" + + def test_import_elasticity_effect(self): + """Higher tariffs should reduce imports""" + base_import = 15000000 + import_elasticity = -0.8 + tariff_change = 0.05 # 5% increase + + import_change = tariff_change * import_elasticity + new_import = base_import * (1 + import_change) + + assert new_import < base_import + + def test_price_pass_through(self): + """Price changes should pass through to farmers and consumers""" + price_change = 10 # 10% change + farmer_pass_through = 0.6 + consumer_pass_through = 0.8 + + farmer_impact = price_change * farmer_pass_through + consumer_impact = price_change * consumer_pass_through + + assert farmer_impact == 6 + assert consumer_impact == 8 + assert farmer_impact <= consumer_impact + + def test_sensitivity_analysis(self): + """Should generate sensitivity table for different tariff levels""" + tariff_levels = [25, 30, 35, 40, 45, 50] + sensitivity_results = [] + + for tariff in tariff_levels: + result = { + "tariff_pct": tariff, + "import_volume": 15 - (tariff - 35) * 0.1, + } + sensitivity_results.append(result) + + assert len(sensitivity_results) == 6 + # Higher tariffs should result in lower imports + imports = [r["import_volume"] for r in sensitivity_results] + assert imports == sorted(imports, reverse=True) + + +class TestCROPIC: + """Test crop damage analysis""" + + def test_image_size_validation(self): + """Should validate image dimensions""" + min_dimension = 100 + max_size_bytes = 10 * 1024 * 1024 # 10MB + + valid_image = {"width": 640, "height": 480, "size": 500000} + invalid_image = {"width": 50, "height": 50, "size": 5000} + + assert valid_image["width"] >= min_dimension + assert valid_image["height"] >= min_dimension + assert valid_image["size"] <= max_size_bytes + + assert invalid_image["width"] < min_dimension + + def test_damage_classification(self): + """Should classify damage types correctly""" + damage_types = [ + "none", + "pest_damage", + "disease", + "drought_stress", + "flood_damage", + "bacterial_infection", + "fungal_disease", + ] + + for dtype in damage_types: + assert isinstance(dtype, str) + assert len(dtype) > 0 + + def test_damage_percentage_range(self): + """Damage percentage should be between 0 and 100""" + import random + + for _ in range(10): + damage_pct = random.randint(0, 100) + assert 0 <= damage_pct <= 100 + + def test_recommendation_generation(self): + """Should generate recommendations based on damage""" + def get_recommendations(damage_type, damage_pct): + recs = [] + if damage_type == "none": + recs.append("monitoring") + elif damage_type == "pest_damage": + recs.append("pesticide_application") + elif damage_pct >= 50: + recs.append("insurance_claim") + return recs + + assert "monitoring" in get_recommendations("none", 0) + assert "pesticide_application" in get_recommendations("pest_damage", 30) + assert "insurance_claim" in get_recommendations("disease", 60) + + +class TestCropRecommendation: + """Test crop recommendation functionality""" + + def test_input_validation_ranges(self): + """Should validate input ranges""" + valid_inputs = { + "N": 50, # 0-100 + "P": 30, # 0-100 + "K": 40, # 0-100 + "temperature": 28, # -10 to 50 + "humidity": 65, # 0-100 + "ph": 6.5, # 0-14 + "rainfall": 200, # 0-500 + } + + assert 0 <= valid_inputs["N"] <= 100 + assert 0 <= valid_inputs["P"] <= 100 + assert 0 <= valid_inputs["K"] <= 100 + assert -10 <= valid_inputs["temperature"] <= 50 + assert 0 <= valid_inputs["humidity"] <= 100 + assert 0 <= valid_inputs["ph"] <= 14 + assert 0 <= valid_inputs["rainfall"] <= 500 + + def test_crop_dictionary(self): + """Should have valid crop mappings""" + crop_dict = { + 1: "Rice", 2: "Maize", 3: "Jute", 4: "Cotton", + 5: "Coconut", 6: "Papaya", 7: "Orange", + } + + assert len(crop_dict) > 0 + for key, value in crop_dict.items(): + assert isinstance(key, int) + assert isinstance(value, str) + + +class TestSaffronClassifier: + """Test saffron authenticity classification""" + + def test_saffron_classes(self): + """Should have exactly 3 saffron classes""" + classes = ["mogra", "lacha", "adulterated"] + assert len(classes) == 3 + assert "mogra" in classes + assert "lacha" in classes + assert "adulterated" in classes + + def test_saffron_response_format(self): + """Saffron response should have correct fields""" + expected_keys = {"model", "prediction", "confidence", "all_predictions", "timestamp"} + response = { + "model": "saffron-verify-pretrained", + "prediction": "mogra", + "confidence": 0.95, + "all_predictions": [ + {"label": "mogra", "confidence": 0.95}, + {"label": "lacha", "confidence": 0.04}, + {"label": "adulterated", "confidence": 0.01}, + ], + "timestamp": "2026-03-07T08:00:00Z", + } + assert set(response.keys()) == expected_keys + assert response["model"] == "saffron-verify-pretrained" + assert 0 <= response["confidence"] <= 1 + assert response["prediction"] in ["mogra", "lacha", "adulterated"] + + def test_saffron_grade_mapping(self): + """Saffron grades should map correctly""" + grade_map = { + "mogra": "Grade A", + "lacha": "Grade B", + "adulterated": "Adulterated", + } + assert grade_map["mogra"] == "Grade A" + assert grade_map["lacha"] == "Grade B" + assert grade_map["adulterated"] == "Adulterated" + + +class TestWalnutDefectClassifier: + """Test walnut defect classification""" + + def test_walnut_defect_classes(self): + """Should have 4 defect classes""" + classes = ["Healthy", "Black Spot", "Shriveled", "Damaged"] + assert len(classes) == 4 + assert "Healthy" in classes + + def test_walnut_defect_response_format(self): + """Walnut defect response should have correct fields""" + response = { + "model": "walnut-defect-classifier", + "prediction": "Healthy", + "confidence": 0.98, + "all_predictions": [ + {"label": "Healthy", "confidence": 0.98}, + {"label": "Black Spot", "confidence": 0.01}, + {"label": "Shriveled", "confidence": 0.005}, + {"label": "Damaged", "confidence": 0.005}, + ], + "timestamp": "2026-03-07T08:00:00Z", + } + assert response["model"] == "walnut-defect-classifier" + assert 0 <= response["confidence"] <= 1 + assert len(response["all_predictions"]) == 4 + + +class TestWalnutRancidityPredictor: + """Test walnut rancidity prediction""" + + def test_rancidity_arrhenius_kinetics(self): + """Arrhenius kinetics should produce valid rate constant""" + import math + A = 1.5e12 + Ea = 80000 + R = 8.314 + T_kelvin = 25 + 273.15 # 25Β°C + k = A * math.exp(-Ea / (R * T_kelvin)) + assert k > 0 + assert k < 1 # rate constant should be small for real conditions + + def test_rancidity_probability_range(self): + """Rancidity probability should be between 0 and 1""" + import math + for pv in [0.1, 1.0, 3.0, 5.0, 8.0, 15.0]: + prob = 1.0 / (1.0 + math.exp(-(pv - 5))) + assert 0 <= prob <= 1 + + def test_rancidity_threshold(self): + """PV > 5 should give rancidity probability > 0.5""" + import math + pv_safe = 2.0 + pv_rancid = 8.0 + prob_safe = 1.0 / (1.0 + math.exp(-(pv_safe - 5))) + prob_rancid = 1.0 / (1.0 + math.exp(-(pv_rancid - 5))) + assert prob_safe < 0.5 + assert prob_rancid > 0.5 + + def test_risk_level_classification(self): + """Risk levels should classify correctly""" + def classify(prob): + if prob < 0.30: + return "LOW" + elif prob < 0.70: + return "MEDIUM" + else: + return "HIGH" + + assert classify(0.1) == "LOW" + assert classify(0.5) == "MEDIUM" + assert classify(0.8) == "HIGH" + + def test_rancidity_input_validation(self): + """Should validate input ranges""" + valid_inputs = { + "storage_days": 30, + "temperature": 25, + "humidity": 60, + "moisture": 5, + } + assert 0 <= valid_inputs["storage_days"] <= 365 + assert -10 <= valid_inputs["temperature"] <= 50 + assert 0 <= valid_inputs["humidity"] <= 100 + assert 0 <= valid_inputs["moisture"] <= 20 + + +class TestApplePricePredictor: + """Test apple price prediction""" + + def test_apple_varieties(self): + """Should have correct apple varieties""" + varieties = ["Shimla", "Kinnauri", "Royal Delicious", "Golden Delicious", "Maharaji"] + assert len(varieties) == 5 + assert "Kinnauri" in varieties + + def test_apple_regions(self): + """Should have correct Indian regions""" + regions = ["Himachal Pradesh", "Jammu & Kashmir", "Uttarakhand", + "Arunachal Pradesh", "Nagaland"] + assert len(regions) == 5 + assert "Himachal Pradesh" in regions + + def test_storage_cost_calculation(self): + """Storage cost should be β‚Ή0.75/kg/day""" + storage_cost_per_day = 0.75 + storage_cost_7d = storage_cost_per_day * 7 + assert storage_cost_7d == pytest.approx(5.25) + + def test_sell_store_decision(self): + """SELL/STORE decision should be based on breakeven""" + current_price = 120.0 + storage_cost_7d = 5.25 + breakeven = current_price + storage_cost_7d + + predicted_high = 130.0 + predicted_low = 122.0 + + assert predicted_high > breakeven # should STORE + assert predicted_low < breakeven # should SELL + + def test_seasonal_adjustment(self): + """Seasonal adjustments should be applied for Indian market""" + # Harvest season (Jul-Oct): discount + # Summer scarcity (Apr-Jun): premium + harvest_months = [7, 8, 9, 10] + scarcity_months = [4, 5, 6] + + for m in harvest_months: + assert 7 <= m <= 10 + for m in scarcity_months: + assert 4 <= m <= 6 + + def test_apple_price_response_format(self): + """Apple price response should have correct fields""" + expected_keys = {"model", "predicted_price_7d", "recommendation", + "current_price", "storage_cost_7d", "breakeven_price", + "currency", "confidence", "advisory", "timestamp"} + response = { + "model": "apple-price-predictor", + "predicted_price_7d": 127.5, + "recommendation": "STORE", + "current_price": 120.0, + "storage_cost_7d": 5.25, + "breakeven_price": 125.25, + "currency": "INR", + "confidence": "hybrid seasonal+trend model", + "advisory": "Predicted price in 7 days: β‚Ή127.5/kg. Store for better returns.", + "timestamp": "2026-03-07T08:00:00Z", + } + assert set(response.keys()) == expected_keys + assert response["currency"] == "INR" + assert response["recommendation"] in ["SELL", "STORE"] + + +if __name__ == "__main__": + pytest.main([__file__, "-v"]) diff --git a/ai-backend/tests/test_models.py b/ai-backend/tests/test_models.py new file mode 100644 index 0000000000000000000000000000000000000000..3ee2f236d3c39cef035af898af2961502d6db0d8 --- /dev/null +++ b/ai-backend/tests/test_models.py @@ -0,0 +1,328 @@ +"""Unit tests for model manager and prediction functions. + +Tests each model's prediction functionality with sample inputs. +Uses mocked models to avoid heavy downloads and ensure fast, deterministic tests. +""" +import pytest +import numpy as np +from unittest.mock import patch, MagicMock +import sys +import os + +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) + +from src.models import manager + +# Check if torchvision is available +try: + import torchvision + TORCHVISION_AVAILABLE = True +except ImportError: + TORCHVISION_AVAILABLE = False + + +class TestModelManager: + """Tests for model manager initialization and caching.""" + + def test_get_device(self): + """Test device detection.""" + device = manager.get_device() + assert device is not None + assert str(device) in ['cpu', 'cuda'] + + def test_model_cache_empty_initially(self): + """Test that model cache starts empty.""" + manager._model_cache.clear() + assert len(manager._model_cache) == 0 + + def test_is_model_loaded(self): + """Test model loaded status check.""" + manager._model_cache.clear() + assert not manager.is_model_loaded('crop_model') + + manager._model_cache['crop_model'] = MagicMock() + assert manager.is_model_loaded('crop_model') + + def test_get_model_status(self): + """Test getting status of all models.""" + manager._model_cache.clear() + status = manager.get_model_status() + + assert isinstance(status, dict) + assert 'disease_model' in status + assert 'crop_model' in status + assert 'fertilizer_classifier' in status + assert 'loan_price_model' in status + assert 'loan_approval_model' in status + + +class TestCropRecommendation: + """Tests for crop recommendation model.""" + + def test_predict_crop_with_valid_input(self, mock_crop_model): + """Test crop prediction with valid input.""" + # Setup mocks in cache + manager._model_cache['crop_model'] = mock_crop_model['model'] + manager._model_cache['crop_standard_scaler'] = mock_crop_model['standard_scaler'] + manager._model_cache['crop_minmax_scaler'] = mock_crop_model['minmax_scaler'] + + # Create sample features + features = np.array([[50, 30, 40, 28, 65, 6.5, 200]]) + + # Make prediction + result = manager.predict_crop(features) + + # Assertions + assert isinstance(result, int) + assert result == 1 # Mock returns 1 for "Rice" + + def test_predict_crop_without_models_raises_error(self): + """Test that prediction fails gracefully when models not loaded.""" + manager._model_cache.clear() + + # Ensure models are explicitly None to avoid auto-loading + manager._model_cache['crop_model'] = None + manager._model_cache['crop_standard_scaler'] = None + manager._model_cache['crop_minmax_scaler'] = None + + features = np.array([[50, 30, 40, 28, 65, 6.5, 200]]) + + with pytest.raises(RuntimeError, match="Crop recommendation models not loaded"): + manager.predict_crop(features) + + def test_crop_prediction_calls_scalers(self, mock_crop_model): + """Test that crop prediction uses both scalers.""" + manager._model_cache['crop_model'] = mock_crop_model['model'] + manager._model_cache['crop_standard_scaler'] = mock_crop_model['standard_scaler'] + manager._model_cache['crop_minmax_scaler'] = mock_crop_model['minmax_scaler'] + + features = np.array([[50, 30, 40, 28, 65, 6.5, 200]]) + manager.predict_crop(features) + + # Verify scalers were called + mock_crop_model['minmax_scaler'].transform.assert_called_once() + mock_crop_model['standard_scaler'].transform.assert_called_once() + mock_crop_model['model'].predict.assert_called_once() + + +class TestFertilizerPrediction: + """Tests for fertilizer prediction model.""" + + def test_predict_fertilizer_with_valid_input(self, mock_fertilizer_model): + """Test fertilizer prediction with valid input.""" + manager._model_cache['fertilizer_classifier'] = mock_fertilizer_model['classifier'] + manager._model_cache['fertilizer_label_encoder'] = mock_fertilizer_model['label_encoder'] + + features = np.array([[28, 65, 45, 2, 10, 50, 40, 30]]) + + result = manager.predict_fertilizer(features) + + assert isinstance(result, str) + assert result == "Urea" + + def test_predict_fertilizer_without_models_raises_error(self): + """Test that prediction fails when models not loaded.""" + manager._model_cache.clear() + + # Ensure models are explicitly None to avoid auto-loading + manager._model_cache['fertilizer_classifier'] = None + manager._model_cache['fertilizer_label_encoder'] = None + + features = np.array([[28, 65, 45, 2, 10, 50, 40, 30]]) + + with pytest.raises(RuntimeError, match="Fertilizer prediction models not loaded"): + manager.predict_fertilizer(features) + + +class TestDiseasePrediction: + """Tests for disease detection model.""" + + @pytest.mark.skipif(not TORCHVISION_AVAILABLE, reason="torchvision not installed") + @patch('model_utils.predict') + def test_predict_disease_with_valid_image(self, mock_predict, mock_disease_model, mock_pil_image): + """Test disease prediction with valid image.""" + if mock_pil_image is None: + pytest.skip("PIL not available") + + model, labels, remedies = mock_disease_model + manager._model_cache['disease_model'] = model + manager._model_cache['disease_labels'] = labels + manager._model_cache['disease_remedies'] = remedies + + # Mock the predict function to return expected values + mock_predict.return_value = ("bacterial_blight", 0.95, [ + ("bacterial_blight", 0.95), + ("leaf_spot", 0.03), + ("rust", 0.02) + ]) + + label, confidence, topk = manager.predict_disease(mock_pil_image, topk=3) + + assert label == "bacterial_blight" + assert confidence == 0.95 + assert len(topk) == 3 + + @pytest.mark.skipif(not TORCHVISION_AVAILABLE, reason="torchvision not installed") + def test_predict_disease_without_model_raises_error(self, mock_pil_image): + """Test that prediction fails when model not loaded.""" + if mock_pil_image is None: + pytest.skip("PIL not available") + + manager._model_cache.clear() + # Ensure models are explicitly None to avoid auto-loading + manager._model_cache['disease_model'] = None + manager._model_cache['disease_labels'] = [] + + with pytest.raises(RuntimeError, match="Disease model not loaded"): + manager.predict_disease(mock_pil_image) + + def test_get_disease_remedy(self, mock_disease_model): + """Test getting remedy for a disease.""" + _, _, remedies = mock_disease_model + manager._model_cache['disease_remedies'] = remedies + + remedy = manager.get_disease_remedy("bacterial_blight") + assert remedy == "Apply copper-based fungicide" + + # Test non-existent disease + remedy = manager.get_disease_remedy("unknown_disease") + assert remedy is None + + +class TestLoanPrediction: + """Tests for loan prediction models.""" + + def test_loan_models_in_cache(self, mock_loan_models): + """Test that loan models can be cached.""" + manager._model_cache['loan_price_model'] = mock_loan_models['price_model'] + manager._model_cache['loan_approval_model'] = mock_loan_models['approval_model'] + + assert manager.is_model_loaded('loan_price_model') + assert manager.is_model_loaded('loan_approval_model') + + def test_get_loan_model(self, mock_loan_models): + """Test retrieving loan models from cache.""" + manager._model_cache['loan_price_model'] = mock_loan_models['price_model'] + + model = manager.get_model('loan_price_model', auto_load=False) + assert model is not None + assert model == mock_loan_models['price_model'] + + +class TestBinaryCompatibilityHandling: + """Tests explicit failure behavior when sklearn/scipy binaries are incompatible.""" + + def test_fertilizer_load_raises_on_numpy_binary_error(self): + from src.models import manager + manager._model_cache.clear() + + with patch('src.models.manager._download_from_hf', return_value='/tmp/mock.pkl'), \ + patch('builtins.open', side_effect=ImportError('numpy.core.multiarray failed to import')): + with pytest.raises(RuntimeError, match="NumPy/SciPy binary compatibility"): + manager.load_fertilizer_models() + + def test_crop_load_raises_on_array_api_error(self): + from src.models import manager + manager._model_cache.clear() + + with patch('src.models.manager.joblib.load', side_effect=AttributeError('_ARRAY_API not found')): + with pytest.raises(RuntimeError, match="NumPy/SciPy binary compatibility"): + manager.load_crop_recommendation_models() + + def test_loan_load_raises_on_numpy_binary_error(self): + from src.models import manager + manager._model_cache.clear() + + with patch('src.models.manager.joblib.load', side_effect=ImportError('numpy.core.multiarray failed to import')): + with pytest.raises(RuntimeError, match="NumPy/SciPy binary compatibility"): + manager.load_loan_models() + + +@pytest.mark.parametrize("model_type,expected_keys", [ + ("crop", ["model", "standard_scaler", "minmax_scaler"]), + ("fertilizer", ["classifier", "label_encoder"]), + ("loan", ["price_model", "approval_model"]), +]) +def test_model_loading_functions(model_type, expected_keys): + """Parametrized test for model loading functions. + + Note: This test uses real HF downloads and is slow. + It should be mocked or skipped in CI without HF access. + """ + pytest.skip("Skipping real HF download tests - use mocks instead") + + if model_type == "crop": + models = manager.load_crop_recommendation_models() + elif model_type == "fertilizer": + models = manager.load_fertilizer_models() + elif model_type == "loan": + models = manager.load_loan_models() + + assert isinstance(models, dict) + for key in expected_keys: + assert key in models + assert models[key] is not None + + +class TestModelInitialization: + """Tests for model initialization.""" + + @patch('src.models.manager.load_disease_model') + @patch('src.models.manager.load_crop_recommendation_models') + @patch('src.models.manager.load_fertilizer_models') + @patch('src.models.manager.load_loan_models') + def test_initialize_models_all( + self, mock_loan, mock_fert, mock_crop, mock_disease + ): + """Test initializing all models.""" + # Setup mocks + mock_disease.return_value = (MagicMock(), ["label1"], {"label1": "remedy"}) + mock_crop.return_value = { + "model": MagicMock(), + "standard_scaler": MagicMock(), + "minmax_scaler": MagicMock() + } + mock_fert.return_value = { + "classifier": MagicMock(), + "label_encoder": MagicMock() + } + mock_loan.return_value = { + "price_model": MagicMock(), + "approval_model": MagicMock() + } + + manager._model_cache.clear() + manager.initialize_models(load_all=True) + + # Verify all loaders were called + mock_disease.assert_called_once() + mock_crop.assert_called_once() + mock_fert.assert_called_once() + mock_loan.assert_called_once() + + # Verify models are in cache + assert 'disease_model' in manager._model_cache + assert 'crop_model' in manager._model_cache + assert 'fertilizer_classifier' in manager._model_cache + assert 'loan_price_model' in manager._model_cache + + def test_initialize_models_lazy(self): + """Test lazy initialization (don't load all at startup).""" + manager._model_cache.clear() + manager.initialize_models(load_all=False) + + # Cache should remain empty with lazy loading + assert len(manager._model_cache) == 0 + + @patch('src.models.manager.load_disease_model') + def test_initialize_handles_load_failure(self, mock_disease): + """Test that initialization continues even if a model fails to load.""" + mock_disease.side_effect = Exception("HF Hub connection failed") + + manager._model_cache.clear() + # Should not raise, just log error + manager.initialize_models(load_all=True) + + # Disease model should be None in cache + assert manager._model_cache.get('disease_model') is None + assert manager._model_cache.get('disease_labels') == [] diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..28299376335c945311db9d8407a1d7f9202aa1fd --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,55 @@ +# Backend Dockerfile (HF Spaces compatible) + +FROM node:22-alpine as base + +WORKDIR /app + +# Install dependencies for native modules + wget for healthcheck +RUN apk add --no-cache python3 make g++ wget + +# Copy package files +COPY package*.json ./ + +# ======================== +# Development stage +# ======================== +FROM base as development +RUN npm ci +COPY . . +EXPOSE 7860 +CMD ["npm", "run", "dev"] + +# ======================== +# Production stage +# ======================== +FROM base as production + +ENV NODE_ENV=production + +# Install production dependencies only +RUN npm ci --omit=dev + +# Copy source files +COPY . . + +# Create non-root user (uid 1000 required by HF Spaces) +RUN set -ex && \ + if ! getent group 1000 > /dev/null 2>&1; then \ + addgroup -g 1000 -S nodejs; \ + fi && \ + GROUP_NAME=$(getent group 1000 | cut -d: -f1) && \ + if ! getent passwd 1000 > /dev/null 2>&1; then \ + adduser -D -u 1000 -G ${GROUP_NAME} nodejs; \ + fi && \ + chown -R 1000:1000 /app + +USER 1000 + +# EXPOSE is informational (HF ignores it but safe to keep) +EXPOSE 7860 + +# Healthcheck probes backend on port 7860 +HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:7860/health || exit 1 + +CMD ["node", "server.js"] diff --git a/backend/FIREBASE_FIRESTORE_SETUP.md b/backend/FIREBASE_FIRESTORE_SETUP.md new file mode 100644 index 0000000000000000000000000000000000000000..5cb4fb3931aa9d481d83de983e866b73cc5b4492 --- /dev/null +++ b/backend/FIREBASE_FIRESTORE_SETUP.md @@ -0,0 +1,34 @@ +# Firebase Auth and Firestore REST setup + +AgroMind uses **Firebase Authentication** for identity and **Cloud Firestore** for application data. The backend does not use MongoDB, a custom JWT secret, `firebase-admin`, a service-account JSON file, Google Application Default Credentials, or Google Cloud IAM. + +## Required deployment configuration + +Set the following Hugging Face Space secrets: + +| Secret | Value | +|---|---| +| `FIREBASE_PROJECT_ID` | `agromind-a62c1` | +| `FIREBASE_API_KEY` | The Firebase Web API key from the Firebase app configuration | + +The API key is used only to call Firebase Identity Toolkit's `accounts:lookup` endpoint. The browser sends a short-lived Firebase ID token to the backend. Firestore REST requests use that same user token as a bearer token, so Firestore Security Rulesβ€”not a privileged server credentialβ€”authorize the data operation. + +The frontend Vercel deployment continues to use the normal `VITE_FIREBASE_*` Web SDK configuration. Never place service-account JSON, private keys, GitHub tokens, or Hugging Face write tokens in the repository or in `VITE_*` variables. + +## Authentication and persistence flow + +The browser signs users in with Firebase Auth using email/password or Google. `newRequest` attaches the current Firebase ID token to protected API calls. The backend verifies that token with Firebase Identity Toolkit, attaches the verified Firebase UID to the request, and carries the token into the REST-backed Firestore compatibility adapter. The adapter preserves the existing model surface while applying Firestore rules to each read and write. + +The browser stores no custom JWT. A tab-scoped session record keeps the Profile login time stable across refreshes and is cleared on explicit logout or when the tab is closed. The Profile page also reads and upserts the user's `users/{uid}` document with the Firebase Web SDK repository. + +## Firestore data model + +Former application models remain top-level Firestore collections such as `users`, `appointments`, `crops`, `farmerDetails`, `tasks`, `records`, `posts`, `notifications`, `milletListings`, `oilPalmProfiles`, and feature-specific collections. User references are Firebase Auth UIDs or Firestore document IDs; passwords are never stored. + +## Deployment checklist + +1. Add `FIREBASE_PROJECT_ID` and `FIREBASE_API_KEY` to the Hugging Face Space secrets. +2. Deploy the rules in `firestore.rules` using the Firebase CLI or the Firebase Console's Rules editor. +3. Confirm the backend health endpoint returns `services.firestore = "user-token-rest"` and does not attempt a startup Firestore connection. +4. Confirm a signed-in user can load Profile and perform one representative protected read and write. +5. Confirm an unauthenticated request receives HTTP 401 and a user cannot write another user's owner-scoped document. diff --git a/backend/contracts/AgroExchange.sol b/backend/contracts/AgroExchange.sol new file mode 100644 index 0000000000000000000000000000000000000000..a2c9260687f3dbf7fd5ae3862246bdb6f1affc14 --- /dev/null +++ b/backend/contracts/AgroExchange.sol @@ -0,0 +1,383 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +/** + * @title AgroExchange + * @dev Escrow contract for agricultural commodity transactions + * @notice This contract facilitates secure transactions between farmers and buyers + */ +contract AgroExchange { + // State variables + address public owner; + uint256 public transactionCount; + uint256 public platformFeePercent; // in basis points (100 = 1%) + + // Structs + struct Transaction { + uint256 id; + address payable seller; + address payable buyer; + uint256 amount; + string listingId; // MongoDB listing ID + TransactionState state; + uint256 createdAt; + uint256 releasedAt; + string productType; + uint256 quantityKg; + } + + enum TransactionState { + Created, + Funded, + Delivered, + Completed, + Disputed, + Refunded, + Cancelled + } + + // Mappings + mapping(uint256 => Transaction) public transactions; + mapping(address => uint256[]) public userTransactions; + mapping(string => uint256) public listingToTransaction; + + // Events + event TransactionCreated( + uint256 indexed transactionId, + address indexed seller, + address indexed buyer, + uint256 amount, + string listingId + ); + + event TransactionFunded( + uint256 indexed transactionId, + address indexed buyer, + uint256 amount + ); + + event DeliveryConfirmed( + uint256 indexed transactionId, + address indexed buyer + ); + + event FundsReleased( + uint256 indexed transactionId, + address indexed seller, + uint256 amount + ); + + event TransactionDisputed( + uint256 indexed transactionId, + address indexed disputer, + string reason + ); + + event DisputeResolved( + uint256 indexed transactionId, + address indexed winner, + uint256 amount + ); + + event TransactionRefunded( + uint256 indexed transactionId, + address indexed buyer, + uint256 amount + ); + + event TransactionCancelled( + uint256 indexed transactionId + ); + + // Modifiers + modifier onlyOwner() { + require(msg.sender == owner, "Only owner can call this function"); + _; + } + + modifier onlySeller(uint256 _transactionId) { + require( + msg.sender == transactions[_transactionId].seller, + "Only seller can call this function" + ); + _; + } + + modifier onlyBuyer(uint256 _transactionId) { + require( + msg.sender == transactions[_transactionId].buyer, + "Only buyer can call this function" + ); + _; + } + + modifier onlyParties(uint256 _transactionId) { + require( + msg.sender == transactions[_transactionId].seller || + msg.sender == transactions[_transactionId].buyer, + "Only transaction parties can call this function" + ); + _; + } + + modifier inState(uint256 _transactionId, TransactionState _state) { + require( + transactions[_transactionId].state == _state, + "Transaction is not in the required state" + ); + _; + } + + // Constructor + constructor() { + owner = msg.sender; + platformFeePercent = 100; // 1% platform fee + transactionCount = 0; + } + + /** + * @dev Create a new escrow transaction + * @param _seller Address of the seller + * @param _listingId MongoDB listing ID for reference + * @param _productType Type of product being sold + * @param _quantityKg Quantity in kilograms + */ + function createTransaction( + address payable _seller, + string memory _listingId, + string memory _productType, + uint256 _quantityKg + ) external payable returns (uint256) { + require(_seller != address(0), "Invalid seller address"); + require(_seller != msg.sender, "Seller cannot be buyer"); + require(msg.value > 0, "Transaction amount must be greater than 0"); + require(bytes(_listingId).length > 0, "Listing ID required"); + require(listingToTransaction[_listingId] == 0, "Transaction already exists for this listing"); + + transactionCount++; + uint256 transactionId = transactionCount; + + transactions[transactionId] = Transaction({ + id: transactionId, + seller: _seller, + buyer: payable(msg.sender), + amount: msg.value, + listingId: _listingId, + state: TransactionState.Funded, + createdAt: block.timestamp, + releasedAt: 0, + productType: _productType, + quantityKg: _quantityKg + }); + + userTransactions[_seller].push(transactionId); + userTransactions[msg.sender].push(transactionId); + listingToTransaction[_listingId] = transactionId; + + emit TransactionCreated(transactionId, _seller, msg.sender, msg.value, _listingId); + emit TransactionFunded(transactionId, msg.sender, msg.value); + + return transactionId; + } + + /** + * @dev Buyer confirms delivery and releases funds to seller + * @param _transactionId ID of the transaction + */ + function confirmDelivery(uint256 _transactionId) + external + onlyBuyer(_transactionId) + inState(_transactionId, TransactionState.Funded) + { + Transaction storage txn = transactions[_transactionId]; + + txn.state = TransactionState.Completed; + txn.releasedAt = block.timestamp; + + // Calculate platform fee + uint256 platformFee = (txn.amount * platformFeePercent) / 10000; + uint256 sellerAmount = txn.amount - platformFee; + + // Transfer funds + txn.seller.transfer(sellerAmount); + payable(owner).transfer(platformFee); + + emit DeliveryConfirmed(_transactionId, msg.sender); + emit FundsReleased(_transactionId, txn.seller, sellerAmount); + } + + /** + * @dev Raise a dispute for a transaction + * @param _transactionId ID of the transaction + * @param _reason Reason for dispute + */ + function raiseDispute(uint256 _transactionId, string memory _reason) + external + onlyParties(_transactionId) + inState(_transactionId, TransactionState.Funded) + { + transactions[_transactionId].state = TransactionState.Disputed; + + emit TransactionDisputed(_transactionId, msg.sender, _reason); + } + + /** + * @dev Resolve a dispute (only owner/arbitrator can call) + * @param _transactionId ID of the transaction + * @param _refundBuyer If true, refund buyer; if false, release to seller + */ + function resolveDispute(uint256 _transactionId, bool _refundBuyer) + external + onlyOwner + inState(_transactionId, TransactionState.Disputed) + { + Transaction storage txn = transactions[_transactionId]; + + if (_refundBuyer) { + txn.state = TransactionState.Refunded; + txn.buyer.transfer(txn.amount); + emit DisputeResolved(_transactionId, txn.buyer, txn.amount); + emit TransactionRefunded(_transactionId, txn.buyer, txn.amount); + } else { + txn.state = TransactionState.Completed; + txn.releasedAt = block.timestamp; + + uint256 platformFee = (txn.amount * platformFeePercent) / 10000; + uint256 sellerAmount = txn.amount - platformFee; + + txn.seller.transfer(sellerAmount); + payable(owner).transfer(platformFee); + + emit DisputeResolved(_transactionId, txn.seller, sellerAmount); + emit FundsReleased(_transactionId, txn.seller, sellerAmount); + } + } + + /** + * @dev Cancel a transaction (only if not yet funded or both parties agree) + * @param _transactionId ID of the transaction + */ + function cancelTransaction(uint256 _transactionId) + external + onlyParties(_transactionId) + { + Transaction storage txn = transactions[_transactionId]; + + require( + txn.state == TransactionState.Created || + txn.state == TransactionState.Funded, + "Cannot cancel transaction in current state" + ); + + if (txn.state == TransactionState.Funded) { + // Refund buyer + txn.state = TransactionState.Cancelled; + txn.buyer.transfer(txn.amount); + emit TransactionRefunded(_transactionId, txn.buyer, txn.amount); + } else { + txn.state = TransactionState.Cancelled; + } + + emit TransactionCancelled(_transactionId); + } + + /** + * @dev Auto-release funds after timeout (14 days) + * @param _transactionId ID of the transaction + */ + function autoRelease(uint256 _transactionId) + external + inState(_transactionId, TransactionState.Funded) + { + Transaction storage txn = transactions[_transactionId]; + + require( + block.timestamp >= txn.createdAt + 14 days, + "Auto-release period not yet reached" + ); + + txn.state = TransactionState.Completed; + txn.releasedAt = block.timestamp; + + uint256 platformFee = (txn.amount * platformFeePercent) / 10000; + uint256 sellerAmount = txn.amount - platformFee; + + txn.seller.transfer(sellerAmount); + payable(owner).transfer(platformFee); + + emit FundsReleased(_transactionId, txn.seller, sellerAmount); + } + + // View functions + + /** + * @dev Get transaction details + * @param _transactionId ID of the transaction + */ + function getTransaction(uint256 _transactionId) + external + view + returns (Transaction memory) + { + require(_transactionId > 0 && _transactionId <= transactionCount, "Invalid transaction ID"); + return transactions[_transactionId]; + } + + /** + * @dev Get user's transactions + * @param _user Address of the user + */ + function getUserTransactions(address _user) + external + view + returns (uint256[] memory) + { + return userTransactions[_user]; + } + + /** + * @dev Get transaction ID by listing ID + * @param _listingId MongoDB listing ID + */ + function getTransactionByListing(string memory _listingId) + external + view + returns (uint256) + { + return listingToTransaction[_listingId]; + } + + /** + * @dev Get contract balance + */ + function getContractBalance() external view returns (uint256) { + return address(this).balance; + } + + // Admin functions + + /** + * @dev Update platform fee (only owner) + * @param _newFeePercent New fee in basis points + */ + function updatePlatformFee(uint256 _newFeePercent) external onlyOwner { + require(_newFeePercent <= 500, "Fee cannot exceed 5%"); + platformFeePercent = _newFeePercent; + } + + /** + * @dev Transfer ownership (only owner) + * @param _newOwner Address of new owner + */ + function transferOwnership(address _newOwner) external onlyOwner { + require(_newOwner != address(0), "Invalid address"); + owner = _newOwner; + } + + /** + * @dev Emergency withdraw (only owner, for stuck funds) + */ + function emergencyWithdraw() external onlyOwner { + payable(owner).transfer(address(this).balance); + } +} diff --git a/backend/contracts/hardhat.config.js b/backend/contracts/hardhat.config.js new file mode 100644 index 0000000000000000000000000000000000000000..888474d4fa6b3471ae69e853ab508a5b139c0a99 --- /dev/null +++ b/backend/contracts/hardhat.config.js @@ -0,0 +1,35 @@ +require("@nomicfoundation/hardhat-toolbox"); +require("dotenv").config(); + +/** @type import('hardhat/config').HardhatUserConfig */ +module.exports = { + solidity: { + version: "0.8.19", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + networks: { + localhost: { + url: "http://127.0.0.1:8545", + }, + hardhat: { + chainId: 31337, + }, + sepolia: { + url: process.env.BLOCKCHAIN_RPC_URL || "", + accounts: process.env.BLOCKCHAIN_PRIVATE_KEY + ? [process.env.BLOCKCHAIN_PRIVATE_KEY] + : [], + }, + }, + paths: { + sources: "./", + tests: "./test", + cache: "./cache", + artifacts: "./artifacts", + }, +}; diff --git a/backend/contracts/package-lock.json b/backend/contracts/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..1ed801f908180b527a706f23299dadce36534a79 --- /dev/null +++ b/backend/contracts/package-lock.json @@ -0,0 +1,8977 @@ +{ + "name": "agromind-contracts", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "agromind-contracts", + "version": "1.0.0", + "dependencies": { + "ethers": "^6.9.0" + }, + "devDependencies": { + "@nomicfoundation/hardhat-toolbox": "^4.0.0", + "hardhat": "^2.19.0" + } + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", + "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", + "license": "MIT" + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@ethereumjs/rlp": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-5.0.2.tgz", + "integrity": "sha512-DziebCdg4JpGlEqEdGgXmjqcFoJi+JGulUXwEjsZGAscAQ7MyD/7LE/GVCP29vEQxKc7AAwjT3A2ywHp2xfoCA==", + "dev": true, + "license": "MPL-2.0", + "bin": { + "rlp": "bin/rlp.cjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ethereumjs/util": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-9.1.0.tgz", + "integrity": "sha512-XBEKsYqLGXLah9PNJbgdkigthkG7TAGvlD/sH12beMXEyHDyigfcbdvHhmLyDWgDyOJn4QwiQUaF7yeuhnjdog==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@ethereumjs/rlp": "^5.0.2", + "ethereum-cryptography": "^2.2.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.8.0.tgz", + "integrity": "sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz", + "integrity": "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/networks": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/web": "^5.8.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz", + "integrity": "sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz", + "integrity": "sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/rlp": "^5.8.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.8.0.tgz", + "integrity": "sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.8.0.tgz", + "integrity": "sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/properties": "^5.8.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", + "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", + "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.8.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.8.0.tgz", + "integrity": "sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.8.0", + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/transactions": "^5.8.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz", + "integrity": "sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.8.0.tgz", + "integrity": "sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/basex": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/pbkdf2": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/sha2": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0", + "@ethersproject/strings": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/wordlists": "^5.8.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.8.0.tgz", + "integrity": "sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/hdnode": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/pbkdf2": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/random": "^5.8.0", + "@ethersproject/strings": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/json-wallets/node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz", + "integrity": "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", + "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT" + }, + "node_modules/@ethersproject/networks": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", + "integrity": "sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.8.0.tgz", + "integrity": "sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/sha2": "^5.8.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", + "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.8.0.tgz", + "integrity": "sha512-3Il3oTzEx3o6kzcg9ZzbE+oCZYyY+3Zh83sKkn4s1DZfTUjIegHnN2Cm0kbn9YFy45FDVcuCLLONhU7ny0SsCw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/base64": "^5.8.0", + "@ethersproject/basex": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/networks": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/random": "^5.8.0", + "@ethersproject/rlp": "^5.8.0", + "@ethersproject/sha2": "^5.8.0", + "@ethersproject/strings": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/web": "^5.8.0", + "bech32": "1.1.4", + "ws": "8.18.0" + } + }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ethersproject/random": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.8.0.tgz", + "integrity": "sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.8.0.tgz", + "integrity": "sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.8.0.tgz", + "integrity": "sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", + "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "bn.js": "^5.2.1", + "elliptic": "6.6.1", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/solidity": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.8.0.tgz", + "integrity": "sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/sha2": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", + "integrity": "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", + "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/rlp": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.8.0.tgz", + "integrity": "sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.8.0.tgz", + "integrity": "sha512-G+jnzmgg6UxurVKRKvw27h0kvG75YKXZKdlLYmAHeF32TGUzHkOFd7Zn6QHOTYRFWnfjtSSFjBowKo7vfrXzPA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/hdnode": "^5.8.0", + "@ethersproject/json-wallets": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/random": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/wordlists": "^5.8.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.8.0.tgz", + "integrity": "sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.8.0.tgz", + "integrity": "sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nomicfoundation/edr": { + "version": "0.12.0-next.23", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.12.0-next.23.tgz", + "integrity": "sha512-F2/6HZh8Q9RsgkOIkRrckldbhPjIZY7d4mT9LYuW68miwGQ5l7CkAgcz9fRRiurA0+YJhtsbx/EyrD9DmX9BOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/edr-darwin-arm64": "0.12.0-next.23", + "@nomicfoundation/edr-darwin-x64": "0.12.0-next.23", + "@nomicfoundation/edr-linux-arm64-gnu": "0.12.0-next.23", + "@nomicfoundation/edr-linux-arm64-musl": "0.12.0-next.23", + "@nomicfoundation/edr-linux-x64-gnu": "0.12.0-next.23", + "@nomicfoundation/edr-linux-x64-musl": "0.12.0-next.23", + "@nomicfoundation/edr-win32-x64-msvc": "0.12.0-next.23" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-darwin-arm64": { + "version": "0.12.0-next.23", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.12.0-next.23.tgz", + "integrity": "sha512-Amh7mRoDzZyJJ4efqoePqdoZOzharmSOttZuJDlVE5yy07BoE8hL6ZRpa5fNYn0LCqn/KoWs8OHANWxhKDGhvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-darwin-x64": { + "version": "0.12.0-next.23", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.12.0-next.23.tgz", + "integrity": "sha512-9wn489FIQm7m0UCD+HhktjWx6vskZzeZD9oDc2k9ZvbBzdXwPp5tiDqUBJ+eQpByAzCDfteAJwRn2lQCE0U+Iw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { + "version": "0.12.0-next.23", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.12.0-next.23.tgz", + "integrity": "sha512-nlk5EejSzEUfEngv0Jkhqq3/wINIfF2ED9wAofc22w/V1DV99ASh9l3/e/MIHOQFecIZ9MDqt0Em9/oDyB1Uew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-musl": { + "version": "0.12.0-next.23", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.12.0-next.23.tgz", + "integrity": "sha512-SJuPBp3Rc6vM92UtVTUxZQ/QlLhLfwTftt2XUiYohmGKB3RjGzpgduEFMCA0LEnucUckU6UHrJNFHiDm77C4PQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-gnu": { + "version": "0.12.0-next.23", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.12.0-next.23.tgz", + "integrity": "sha512-NU+Qs3u7Qt6t3bJFdmmjd5CsvgI2bPPzO31KifM2Ez96/jsXYho5debtTQnimlb5NAqiHTSlxjh/F8ROcptmeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-musl": { + "version": "0.12.0-next.23", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.12.0-next.23.tgz", + "integrity": "sha512-F78fZA2h6/ssiCSZOovlgIu0dUeI7ItKPsDDF3UUlIibef052GCXmliMinC90jVPbrjUADMd1BUwjfI0Z8OllQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-win32-x64-msvc": { + "version": "0.12.0-next.23", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.12.0-next.23.tgz", + "integrity": "sha512-IfJZQJn7d/YyqhmguBIGoCKjE9dKjbu6V6iNEPApfwf5JyyjHYyyfkLU4rf7hygj57bfH4sl1jtQ6r8HnT62lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/hardhat-chai-matchers": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.1.2.tgz", + "integrity": "sha512-NlUlde/ycXw2bLzA2gWjjbxQaD9xIRbAF30nsoEprAWzH8dXEI1ILZUKZMyux9n9iygEXTzN0SDVjE6zWDZi9g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/chai-as-promised": "^7.1.3", + "chai-as-promised": "^7.1.1", + "deep-eql": "^4.0.1", + "ordinal": "^1.0.3" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-ethers": "^3.1.0", + "chai": "^4.2.0", + "ethers": "^6.14.0", + "hardhat": "^2.26.0" + } + }, + "node_modules/@nomicfoundation/hardhat-ethers": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.1.3.tgz", + "integrity": "sha512-208JcDeVIl+7Wu3MhFUUtiA8TJ7r2Rn3Wr+lSx9PfsDTKkbsAsWPY6N6wQ4mtzDv0/pB9nIbJhkjoHe1EsgNsA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.1.1", + "lodash.isequal": "^4.5.0" + }, + "peerDependencies": { + "ethers": "^6.14.0", + "hardhat": "^2.28.0" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.1.2.tgz", + "integrity": "sha512-p7HaUVDbLj7ikFivQVNhnfMHUBgiHYMwQWvGn9AriieuopGOELIrwj2KjyM2a6z70zai5YKO264Vwz+3UFJZPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ethereumjs-util": "^7.1.4" + }, + "peerDependencies": { + "hardhat": "^2.26.0" + } + }, + "node_modules/@nomicfoundation/hardhat-toolbox": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-4.0.0.tgz", + "integrity": "sha512-jhcWHp0aHaL0aDYj8IJl80v4SZXWMS1A2XxXa1CA6pBiFfJKuZinCkO6wb+POAt0LIfXB3gA3AgdcOccrcwBwA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", + "@nomicfoundation/hardhat-ethers": "^3.0.0", + "@nomicfoundation/hardhat-network-helpers": "^1.0.0", + "@nomicfoundation/hardhat-verify": "^2.0.0", + "@typechain/ethers-v6": "^0.5.0", + "@typechain/hardhat": "^9.0.0", + "@types/chai": "^4.2.0", + "@types/mocha": ">=9.1.0", + "@types/node": ">=16.0.0", + "chai": "^4.2.0", + "ethers": "^6.4.0", + "hardhat": "^2.11.0", + "hardhat-gas-reporter": "^1.0.8", + "solidity-coverage": "^0.8.1", + "ts-node": ">=8.0.0", + "typechain": "^8.3.0", + "typescript": ">=4.5.0" + } + }, + "node_modules/@nomicfoundation/hardhat-verify": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.1.3.tgz", + "integrity": "sha512-danbGjPp2WBhLkJdQy9/ARM3WQIK+7vwzE0urNem1qZJjh9f54Kf5f1xuQv8DvqewUAkuPxVt/7q4Grz5WjqSg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@ethersproject/address": "^5.0.2", + "cbor": "^8.1.0", + "debug": "^4.1.1", + "lodash.clonedeep": "^4.5.0", + "picocolors": "^1.1.0", + "semver": "^6.3.0", + "table": "^6.8.0", + "undici": "^5.14.0" + }, + "peerDependencies": { + "hardhat": "^2.26.0" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz", + "integrity": "sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.2", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.2" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz", + "integrity": "sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz", + "integrity": "sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz", + "integrity": "sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz", + "integrity": "sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz", + "integrity": "sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz", + "integrity": "sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz", + "integrity": "sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/core/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/node/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/tracing/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@solidity-parser/parser": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", + "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@typechain/ethers-v6": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v6/-/ethers-v6-0.5.1.tgz", + "integrity": "sha512-F+GklO8jBWlsaVV+9oHaPh5NJdd6rAKN4tklGfInX1Q7h0xPgVLP39Jl3eCulPB5qexI71ZFHwbljx4ZXNfouA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + }, + "peerDependencies": { + "ethers": "6.x", + "typechain": "^8.3.2", + "typescript": ">=4.7.0" + } + }, + "node_modules/@typechain/hardhat": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@typechain/hardhat/-/hardhat-9.1.0.tgz", + "integrity": "sha512-mtaUlzLlkqTlfPwB3FORdejqBskSnh+Jl8AIJGjXNAQfRQ4ofHADPl1+oU7Z3pAJzmZbUXII8MhOLQltcHgKnA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fs-extra": "^9.1.0" + }, + "peerDependencies": { + "@typechain/ethers-v6": "^0.5.1", + "ethers": "^6.1.0", + "hardhat": "^2.9.9", + "typechain": "^8.3.2" + } + }, + "node_modules/@types/bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "4.3.20", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", + "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/chai-as-promised": { + "version": "7.1.8", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", + "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/concat-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/node": { + "version": "26.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz", + "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/secp256k1": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.7.tgz", + "integrity": "sha512-Rcvjl6vARGAKRO6jHeKMatGrvOMGrR/AR11N1x2LqintPCyDZ7NBhrh238Z2VZc7aM7KIwnFpFQ7fnfK4H/9Qw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true, + "license": "BSD-3-Clause OR MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.4.2" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz", + "integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.6", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/bn.js": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.5.tgz", + "integrity": "sha512-Vq886eXykuP5E6HcKSSStP3bJgrE6In5WKxVUvJ8XGpWWYs2xZHWqUwzCtGgEtBcxyd57KBFDPFoUfNzdaHCNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true, + "license": "Apache-2.0", + "peer": true + }, + "node_modules/cbor": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", + "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "nofilter": "^3.1.0" + }, + "engines": { + "node": ">=12.19" + } + }, + "node_modules/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-as-promised": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", + "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", + "dev": true, + "license": "WTFPL", + "peer": true, + "dependencies": { + "check-error": "^1.0.2" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cipher-base": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/cli-table3/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-table3/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-table3/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/command-line-usage/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-usage/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/command-line-usage/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/command-line-usage/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/command-line-usage/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", + "dev": true, + "peer": true + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "peer": true, + "dependencies": { + "heap": ">= 0.2.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz", + "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=0.12.0" + }, + "optionalDependencies": { + "source-map": "~0.2.0" + } + }, + "node_modules/esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eth-gas-reporter": { + "version": "0.2.27", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.27.tgz", + "integrity": "sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@solidity-parser/parser": "^0.14.0", + "axios": "^1.5.1", + "cli-table3": "^0.5.0", + "colors": "1.4.0", + "ethereum-cryptography": "^1.0.3", + "ethers": "^5.7.2", + "fs-readdir-recursive": "^1.1.0", + "lodash": "^4.17.14", + "markdown-table": "^1.1.3", + "mocha": "^10.2.0", + "req-cwd": "^2.0.0", + "sha1": "^1.1.1", + "sync-request": "^6.0.0" + }, + "peerDependencies": { + "@codechecks/client": "^0.1.0" + }, + "peerDependenciesMeta": { + "@codechecks/client": { + "optional": true + } + } + }, + "node_modules/eth-gas-reporter/node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "peer": true + }, + "node_modules/eth-gas-reporter/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/eth-gas-reporter/node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/eth-gas-reporter/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/diff": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", + "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/eth-gas-reporter/node_modules/ethereum-cryptography": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "node_modules/eth-gas-reporter/node_modules/ethers": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.8.0.tgz", + "integrity": "sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abi": "5.8.0", + "@ethersproject/abstract-provider": "5.8.0", + "@ethersproject/abstract-signer": "5.8.0", + "@ethersproject/address": "5.8.0", + "@ethersproject/base64": "5.8.0", + "@ethersproject/basex": "5.8.0", + "@ethersproject/bignumber": "5.8.0", + "@ethersproject/bytes": "5.8.0", + "@ethersproject/constants": "5.8.0", + "@ethersproject/contracts": "5.8.0", + "@ethersproject/hash": "5.8.0", + "@ethersproject/hdnode": "5.8.0", + "@ethersproject/json-wallets": "5.8.0", + "@ethersproject/keccak256": "5.8.0", + "@ethersproject/logger": "5.8.0", + "@ethersproject/networks": "5.8.0", + "@ethersproject/pbkdf2": "5.8.0", + "@ethersproject/properties": "5.8.0", + "@ethersproject/providers": "5.8.0", + "@ethersproject/random": "5.8.0", + "@ethersproject/rlp": "5.8.0", + "@ethersproject/sha2": "5.8.0", + "@ethersproject/signing-key": "5.8.0", + "@ethersproject/solidity": "5.8.0", + "@ethersproject/strings": "5.8.0", + "@ethersproject/transactions": "5.8.0", + "@ethersproject/units": "5.8.0", + "@ethersproject/wallet": "5.8.0", + "@ethersproject/web": "5.8.0", + "@ethersproject/wordlists": "5.8.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eth-gas-reporter/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eth-gas-reporter/node_modules/mocha": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/eth-gas-reporter/node_modules/workerpool": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true, + "license": "Apache-2.0", + "peer": true + }, + "node_modules/eth-gas-reporter/node_modules/yargs": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz", + "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eth-gas-reporter/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ethereum-bloom-filters": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.2.0.tgz", + "integrity": "sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/hashes": "^1.4.0" + } + }, + "node_modules/ethereum-bloom-filters/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "license": "MPL-2.0", + "peer": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ethers": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.17.0.tgz", + "integrity": "sha512-BpyrpIPJ3ydEVow8zGaz1DuPS7YU8DcWxuBnY9a0UA/lvAPwrMr+EPXsfrul628SRaekPNeIM4UFh/91GWZang==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "1.11.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "22.7.5", + "aes-js": "4.0.0-beta.5", + "tslib": "2.7.0", + "ws": "8.21.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethers/node_modules/@types/node": { + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/ethers/node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" + }, + "node_modules/ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-unit/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fast-uri": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ghost-testrpc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", + "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "chalk": "^2.4.2", + "node-emoji": "^1.10.0" + }, + "bin": { + "testrpc-sc": "index.js" + } + }, + "node_modules/ghost-testrpc/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ghost-testrpc/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ghost-testrpc/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/ghost-testrpc/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/ghost-testrpc/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ghost-testrpc/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ghost-testrpc/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globby": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/globby/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/globby/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globby/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hardhat": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.29.0.tgz", + "integrity": "sha512-tsj5mCSjDCFOhGfBl4vwqDEcwdlES9VUzRWfdrwvEVhus6D8W6u+WfUKRLLwFhKGS/8lKPoXGsjYWPXl3CCpOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ethereumjs/util": "^9.1.0", + "@ethersproject/abi": "^5.1.2", + "@nomicfoundation/edr": "0.12.0-next.23", + "@nomicfoundation/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "boxen": "^5.1.2", + "chokidar": "^4.0.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "find-up": "^5.0.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "json-stream-stringify": "^3.1.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "micro-eth-signer": "^0.14.0", + "mnemonist": "^0.38.0", + "mocha": "^11.1.0", + "p-map": "^4.0.0", + "picocolors": "^1.1.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.8.26", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tinyglobby": "^0.2.6", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/bootstrap.js" + }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/hardhat-gas-reporter": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.10.tgz", + "integrity": "sha512-02N4+So/fZrzJ88ci54GqwVA3Zrf0C9duuTyGt0CFRIh/CdNwbnTgkXkRfojOMLBQ+6t+lBIkgbsOtqMvNwikA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "array-uniq": "1.0.3", + "eth-gas-reporter": "^0.2.25", + "sha1": "^1.1.1" + }, + "peerDependencies": { + "hardhat": "^2.0.2" + } + }, + "node_modules/hardhat/node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, + "node_modules/hardhat/node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/hardhat/node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/hardhat/node_modules/ethereum-cryptography": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "node_modules/hardhat/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/hardhat/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/hardhat/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/hardhat/node_modules/ws": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/hash-base/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hash-base/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/hash-base/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/hash-base/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "^10.0.3" + } + }, + "node_modules/http-response-object/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.9.tgz", + "integrity": "sha512-ObHy4YN7ycwZOUCLI1/6svfyAFu7vL8RhAvVu/bh/RZW9EPlOyDaQ9jDQWCtdqzaXUjgXZCW1migtHE7YI7UGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fp-ts": "^1.0.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/json-stream-stringify": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.7.tgz", + "integrity": "sha512-F4MWetLtY42YMaAKw5cV4e47zMD5aOT+tjjQWjX18ACtdkQ5Y/vrcfbcQ107Rh+MXjOCIx4KhW0wPmOvG8iQ5w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=7.10.1" + } + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonschema": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz", + "integrity": "sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/keccak": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micro-eth-signer": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.14.0.tgz", + "integrity": "sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.8.1", + "@noble/hashes": "~1.7.1", + "micro-packed": "~0.7.2" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/curves": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.2" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/hashes": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-ftch": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", + "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/micro-packed": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.7.3.tgz", + "integrity": "sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "obliterator": "^2.0.0" + } + }, + "node_modules/mocha": { + "version": "11.8.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.8.0.tgz", + "integrity": "sha512-VyCeUdGN3A9lmCTTgG4yuvY9ixxaDk+xt2R/7/+1AP6EqNG+G9OKkzBwhVtVYoNX8YsxNSgAl8mOv3IAeOpFbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "browser-stdout": "^1.3.1", + "chokidar": "^4.0.1", + "debug": "^4.3.5", + "diff": "^7.0.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^9.0.5", + "ms": "^2.1.3", + "picocolors": "^1.1.1", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "dev": true, + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12.19" + } + }, + "node_modules/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/number-to-bn/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obliterator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", + "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", + "dev": true, + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ordinal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz", + "integrity": "sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true, + "peer": true + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.6.tgz", + "integrity": "sha512-BT6eelPB1EyGHo8pC0o9Bl6k6SYVhKO1jEbd3lcTrtr7XHdjP8BW1YpfCV3G9Kwkxgattk+S5q2/RvuttCsS1g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "peer": true + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "peer": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/recursive-readdir/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/recursive-readdir/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/req-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", + "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "req-from": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/req-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/ripemd160": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, + "license": "MPL-2.0", + "peer": true, + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sc-istanbul": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", + "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "istanbul": "lib/cli.js" + } + }, + "node_modules/sc-istanbul/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/sc-istanbul/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/sc-istanbul/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sc-istanbul/node_modules/has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sc-istanbul/node_modules/js-yaml": { + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz", + "integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/sc-istanbul/node_modules/js-yaml/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sc-istanbul/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sc-istanbul/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/sc-istanbul/node_modules/supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/sc-istanbul/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/secp256k1": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.5.tgz", + "integrity": "sha512-SQZi5+/uiJIFPYbeRrVuu77Sr3bFOTq0oCQs67CqYwdmg0lhnqi/8djSWhzNO3GKGOqxBYCdx8zJJv0zUwDDvw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "elliptic": "^6.5.7", + "node-addon-api": "^5.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/secp256k1/node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "dev": true, + "license": "(MIT AND BSD-3-Clause)", + "peer": true, + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shelljs/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/shelljs/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/shelljs/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/solc": { + "version": "0.8.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.26.tgz", + "integrity": "sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "command-exists": "^1.2.8", + "commander": "^8.1.0", + "follow-redirects": "^1.12.1", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solc.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/solc/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/solidity-coverage": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.17.tgz", + "integrity": "sha512-5P8vnB6qVX9tt1MfuONtCTEaEGO/O4WuEidPHIAJjx4sktHHKhO3rFvnE0q8L30nWJPTrcqGQMT7jpE29B2qow==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.0.9", + "@solidity-parser/parser": "^0.20.1", + "chalk": "^2.4.2", + "death": "^1.1.0", + "difflib": "^0.2.4", + "fs-extra": "^8.1.0", + "ghost-testrpc": "^0.0.2", + "global-modules": "^2.0.0", + "globby": "^10.0.1", + "jsonschema": "^1.2.4", + "lodash": "^4.17.21", + "mocha": "^10.2.0", + "node-emoji": "^1.10.0", + "pify": "^4.0.1", + "recursive-readdir": "^2.2.2", + "sc-istanbul": "^0.4.5", + "semver": "^7.3.4", + "shelljs": "^0.8.3", + "web3-utils": "^1.3.6" + }, + "bin": { + "solidity-coverage": "plugins/bin.js" + }, + "peerDependencies": { + "hardhat": "^2.11.0" + } + }, + "node_modules/solidity-coverage/node_modules/@solidity-parser/parser": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.20.2.tgz", + "integrity": "sha512-rbu0bzwNvMcwAjH86hiEAcOeRI2EeK8zCkHDrFykh/Al8mvJeFmjy3UrE7GYQjNwOgbGUUtCn5/k8CB8zIu7QA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/solidity-coverage/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/solidity-coverage/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/solidity-coverage/node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/solidity-coverage/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/solidity-coverage/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/solidity-coverage/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/solidity-coverage/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/solidity-coverage/node_modules/diff": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", + "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/solidity-coverage/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/solidity-coverage/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/solidity-coverage/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "peer": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/solidity-coverage/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/solidity-coverage/node_modules/mocha": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/solidity-coverage/node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/solidity-coverage/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/solidity-coverage/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/solidity-coverage/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/solidity-coverage/node_modules/supports-color/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/solidity-coverage/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/solidity-coverage/node_modules/workerpool": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true, + "license": "Apache-2.0", + "peer": true + }, + "node_modules/solidity-coverage/node_modules/yargs": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz", + "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/solidity-coverage/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/stacktrace-parser": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", + "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", + "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", + "dev": true, + "license": "WTFPL OR MIT", + "peer": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sync-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/sync-rpc": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.7.tgz", + "integrity": "sha512-YHciI7TUxL8EPqz/bg01sZfwuzQA0odao1wf1Ywdtw7j5vl30aQ6s+bLRTvgPPgzr94cg+WMm6Bxi/P7BJOxgw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "get-port": "^3.1.0" + } + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/then-request/node_modules/@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/then-request/node_modules/form-data": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.6.tgz", + "integrity": "sha512-Ogz/E85h9tlfJzpI6TuFpGcHZFhLrb9Gw8wq9v40CxSCPnv7ahKr6Xgtkn0KYCDQJ8DNn5VoMO8EXr9V5PadyA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-command-line-args": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz", + "integrity": "sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "chalk": "^4.1.0", + "command-line-args": "^5.1.1", + "command-line-usage": "^6.1.0", + "string-format": "^2.0.0" + }, + "bin": { + "write-markdown": "dist/write-markdown.js" + } + }, + "node_modules/ts-essentials": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", + "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "typescript": ">=3.7.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "license": "0BSD" + }, + "node_modules/tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typechain": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/typechain/-/typechain-8.3.2.tgz", + "integrity": "sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/prettier": "^2.1.1", + "debug": "^4.3.1", + "fs-extra": "^7.0.0", + "glob": "7.1.7", + "js-sha3": "^0.8.0", + "lodash": "^4.17.15", + "mkdirp": "^1.0.4", + "prettier": "^2.3.1", + "ts-command-line-args": "^2.2.0", + "ts-essentials": "^7.0.1" + }, + "bin": { + "typechain": "dist/cli/cli.js" + }, + "peerDependencies": { + "typescript": ">=4.3.0" + } + }, + "node_modules/typechain/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/typechain/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/typechain/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typechain/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "peer": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/typechain/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/typechain/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typechain/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc" + }, + "engines": { + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" + } + }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/web3-utils": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.4.tgz", + "integrity": "sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==", + "dev": true, + "license": "LGPL-3.0", + "peer": true, + "dependencies": { + "@ethereumjs/util": "^8.1.0", + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereum-cryptography": "^2.1.2", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils/node_modules/@ethereumjs/rlp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", + "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", + "dev": true, + "license": "MPL-2.0", + "peer": true, + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/web3-utils/node_modules/@ethereumjs/util": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", + "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", + "dev": true, + "license": "MPL-2.0", + "peer": true, + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/web3-utils/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wordwrapjs/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/workerpool": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/backend/contracts/package.json b/backend/contracts/package.json new file mode 100644 index 0000000000000000000000000000000000000000..071a45d33271ed712d1ffa1d7a32b3d272441a3c --- /dev/null +++ b/backend/contracts/package.json @@ -0,0 +1,19 @@ +{ + "name": "agromind-contracts", + "version": "1.0.0", + "description": "Smart contracts for AgroMind escrow and transactions", + "scripts": { + "compile": "npx hardhat compile", + "test": "npx hardhat test", + "deploy:local": "npx hardhat run scripts/deploy.js --network localhost", + "deploy:sepolia": "npx hardhat run scripts/deploy.js --network sepolia", + "node": "npx hardhat node" + }, + "devDependencies": { + "@nomicfoundation/hardhat-toolbox": "^4.0.0", + "hardhat": "^2.19.0" + }, + "dependencies": { + "ethers": "^6.9.0" + } +} diff --git a/backend/contracts/scripts/deploy.js b/backend/contracts/scripts/deploy.js new file mode 100644 index 0000000000000000000000000000000000000000..55471ddfe30d025c65e964ec259f0ea79f503111 --- /dev/null +++ b/backend/contracts/scripts/deploy.js @@ -0,0 +1,40 @@ +const { ethers } = require("hardhat"); + +async function main() { + console.log("Deploying AgroExchange contract..."); + + const [deployer] = await ethers.getSigners(); + console.log("Deploying with account:", deployer.address); + + const balance = await ethers.provider.getBalance(deployer.address); + console.log("Account balance:", ethers.formatEther(balance), "ETH"); + + // Deploy contract + const AgroExchange = await ethers.getContractFactory("AgroExchange"); + const agroExchange = await AgroExchange.deploy(); + + await agroExchange.waitForDeployment(); + + const address = await agroExchange.getAddress(); + console.log("AgroExchange deployed to:", address); + + // Log deployment info + console.log("\n=== Deployment Summary ==="); + console.log("Contract Address:", address); + console.log("Owner:", deployer.address); + console.log("Network:", network.name); // eslint-disable-line no-undef + console.log("Gas Used:", (await agroExchange.deploymentTransaction().wait()).gasUsed.toString()); + + // Verify contract settings + const platformFee = await agroExchange.platformFeePercent(); + console.log("Platform Fee:", platformFee.toString(), "basis points (", Number(platformFee) / 100, "%)"); + + return address; +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/backend/contracts/test/AgroExchange.test.js b/backend/contracts/test/AgroExchange.test.js new file mode 100644 index 0000000000000000000000000000000000000000..34c85d374e35210cbd521a56cecc555d6ce81ab1 --- /dev/null +++ b/backend/contracts/test/AgroExchange.test.js @@ -0,0 +1,325 @@ +const { expect } = require("chai"); +const { ethers } = require("hardhat"); + +describe("AgroExchange", function () { + let agroExchange; + let owner; + let seller; + let buyer; + let addr3; + + const listingId = "listing123"; + const productType = "groundnut"; + const quantityKg = 1000; + const transactionAmount = ethers.parseEther("1.0"); + + beforeEach(async function () { + [owner, seller, buyer, addr3] = await ethers.getSigners(); + + const AgroExchange = await ethers.getContractFactory("AgroExchange"); + agroExchange = await AgroExchange.deploy(); + await agroExchange.waitForDeployment(); + }); + + describe("Deployment", function () { + it("Should set the right owner", async function () { + expect(await agroExchange.owner()).to.equal(owner.address); + }); + + it("Should have correct initial platform fee", async function () { + expect(await agroExchange.platformFeePercent()).to.equal(100); // 1% + }); + + it("Should have zero transaction count initially", async function () { + expect(await agroExchange.transactionCount()).to.equal(0); + }); + }); + + describe("Transaction Creation", function () { + it("Should create a transaction successfully", async function () { + await expect( + agroExchange.connect(buyer).createTransaction( + seller.address, + listingId, + productType, + quantityKg, + { value: transactionAmount } + ) + ) + .to.emit(agroExchange, "TransactionCreated") + .withArgs(1, seller.address, buyer.address, transactionAmount, listingId); + + expect(await agroExchange.transactionCount()).to.equal(1); + }); + + it("Should reject if seller is buyer", async function () { + await expect( + agroExchange.connect(buyer).createTransaction( + buyer.address, + listingId, + productType, + quantityKg, + { value: transactionAmount } + ) + ).to.be.revertedWith("Seller cannot be buyer"); + }); + + it("Should reject if amount is zero", async function () { + await expect( + agroExchange.connect(buyer).createTransaction( + seller.address, + listingId, + productType, + quantityKg, + { value: 0 } + ) + ).to.be.revertedWith("Transaction amount must be greater than 0"); + }); + + it("Should reject duplicate listing", async function () { + await agroExchange.connect(buyer).createTransaction( + seller.address, + listingId, + productType, + quantityKg, + { value: transactionAmount } + ); + + await expect( + agroExchange.connect(addr3).createTransaction( + seller.address, + listingId, + productType, + quantityKg, + { value: transactionAmount } + ) + ).to.be.revertedWith("Transaction already exists for this listing"); + }); + }); + + describe("Delivery Confirmation", function () { + beforeEach(async function () { + await agroExchange.connect(buyer).createTransaction( + seller.address, + listingId, + productType, + quantityKg, + { value: transactionAmount } + ); + }); + + it("Should confirm delivery and release funds", async function () { + const sellerBalanceBefore = await ethers.provider.getBalance(seller.address); + + await expect(agroExchange.connect(buyer).confirmDelivery(1)) + .to.emit(agroExchange, "DeliveryConfirmed") + .to.emit(agroExchange, "FundsReleased"); + + const sellerBalanceAfter = await ethers.provider.getBalance(seller.address); + + // Seller should receive 99% (1% platform fee) + const expectedAmount = transactionAmount * BigInt(9900) / BigInt(10000); + expect(sellerBalanceAfter - sellerBalanceBefore).to.equal(expectedAmount); + }); + + it("Should reject if not buyer", async function () { + await expect( + agroExchange.connect(seller).confirmDelivery(1) + ).to.be.revertedWith("Only buyer can call this function"); + }); + + it("Should update transaction state to Completed", async function () { + await agroExchange.connect(buyer).confirmDelivery(1); + + const txn = await agroExchange.getTransaction(1); + expect(txn.state).to.equal(4); // Completed state + }); + }); + + describe("Disputes", function () { + beforeEach(async function () { + await agroExchange.connect(buyer).createTransaction( + seller.address, + listingId, + productType, + quantityKg, + { value: transactionAmount } + ); + }); + + it("Should allow buyer to raise dispute", async function () { + await expect( + agroExchange.connect(buyer).raiseDispute(1, "Product not as described") + ) + .to.emit(agroExchange, "TransactionDisputed") + .withArgs(1, buyer.address, "Product not as described"); + }); + + it("Should allow seller to raise dispute", async function () { + await expect( + agroExchange.connect(seller).raiseDispute(1, "Buyer not responding") + ) + .to.emit(agroExchange, "TransactionDisputed") + .withArgs(1, seller.address, "Buyer not responding"); + }); + + it("Should resolve dispute in favor of buyer", async function () { + await agroExchange.connect(buyer).raiseDispute(1, "Product not as described"); + + const buyerBalanceBefore = await ethers.provider.getBalance(buyer.address); + + await expect(agroExchange.connect(owner).resolveDispute(1, true)) + .to.emit(agroExchange, "DisputeResolved") + .to.emit(agroExchange, "TransactionRefunded"); + + const buyerBalanceAfter = await ethers.provider.getBalance(buyer.address); + expect(buyerBalanceAfter - buyerBalanceBefore).to.equal(transactionAmount); + }); + + it("Should resolve dispute in favor of seller", async function () { + await agroExchange.connect(buyer).raiseDispute(1, "Product not as described"); + + const sellerBalanceBefore = await ethers.provider.getBalance(seller.address); + + await expect(agroExchange.connect(owner).resolveDispute(1, false)) + .to.emit(agroExchange, "DisputeResolved") + .to.emit(agroExchange, "FundsReleased"); + + const sellerBalanceAfter = await ethers.provider.getBalance(seller.address); + const expectedAmount = transactionAmount * BigInt(9900) / BigInt(10000); + expect(sellerBalanceAfter - sellerBalanceBefore).to.equal(expectedAmount); + }); + + it("Should reject dispute resolution from non-owner", async function () { + await agroExchange.connect(buyer).raiseDispute(1, "Product not as described"); + + await expect( + agroExchange.connect(buyer).resolveDispute(1, true) + ).to.be.revertedWith("Only owner can call this function"); + }); + }); + + describe("Cancellation", function () { + beforeEach(async function () { + await agroExchange.connect(buyer).createTransaction( + seller.address, + listingId, + productType, + quantityKg, + { value: transactionAmount } + ); + }); + + it("Should cancel and refund funded transaction", async function () { + const buyerBalanceBefore = await ethers.provider.getBalance(buyer.address); + + const tx = await agroExchange.connect(buyer).cancelTransaction(1); + const receipt = await tx.wait(); + const gasUsed = receipt.gasUsed * tx.gasPrice; + + const buyerBalanceAfter = await ethers.provider.getBalance(buyer.address); + + // Account for gas costs + expect(buyerBalanceAfter + gasUsed - buyerBalanceBefore).to.equal(transactionAmount); + }); + + it("Should not allow cancellation after dispute", async function () { + await agroExchange.connect(buyer).raiseDispute(1, "Issue"); + + await expect( + agroExchange.connect(buyer).cancelTransaction(1) + ).to.be.revertedWith("Cannot cancel transaction in current state"); + }); + }); + + describe("Auto Release", function () { + beforeEach(async function () { + await agroExchange.connect(buyer).createTransaction( + seller.address, + listingId, + productType, + quantityKg, + { value: transactionAmount } + ); + }); + + it("Should reject auto-release before timeout", async function () { + await expect( + agroExchange.autoRelease(1) + ).to.be.revertedWith("Auto-release period not yet reached"); + }); + + it("Should auto-release after timeout", async function () { + // Increase time by 14 days + await ethers.provider.send("evm_increaseTime", [14 * 24 * 60 * 60]); + await ethers.provider.send("evm_mine"); + + const sellerBalanceBefore = await ethers.provider.getBalance(seller.address); + + await expect(agroExchange.autoRelease(1)) + .to.emit(agroExchange, "FundsReleased"); + + const sellerBalanceAfter = await ethers.provider.getBalance(seller.address); + const expectedAmount = transactionAmount * BigInt(9900) / BigInt(10000); + expect(sellerBalanceAfter - sellerBalanceBefore).to.equal(expectedAmount); + }); + }); + + describe("View Functions", function () { + beforeEach(async function () { + await agroExchange.connect(buyer).createTransaction( + seller.address, + listingId, + productType, + quantityKg, + { value: transactionAmount } + ); + }); + + it("Should return transaction details", async function () { + const txn = await agroExchange.getTransaction(1); + expect(txn.seller).to.equal(seller.address); + expect(txn.buyer).to.equal(buyer.address); + expect(txn.amount).to.equal(transactionAmount); + expect(txn.listingId).to.equal(listingId); + }); + + it("Should return user transactions", async function () { + const buyerTxns = await agroExchange.getUserTransactions(buyer.address); + expect(buyerTxns.length).to.equal(1); + expect(buyerTxns[0]).to.equal(1); + + const sellerTxns = await agroExchange.getUserTransactions(seller.address); + expect(sellerTxns.length).to.equal(1); + }); + + it("Should return transaction by listing ID", async function () { + const txnId = await agroExchange.getTransactionByListing(listingId); + expect(txnId).to.equal(1); + }); + }); + + describe("Admin Functions", function () { + it("Should update platform fee", async function () { + await agroExchange.connect(owner).updatePlatformFee(200); // 2% + expect(await agroExchange.platformFeePercent()).to.equal(200); + }); + + it("Should reject fee update from non-owner", async function () { + await expect( + agroExchange.connect(buyer).updatePlatformFee(200) + ).to.be.revertedWith("Only owner can call this function"); + }); + + it("Should reject fee above 5%", async function () { + await expect( + agroExchange.connect(owner).updatePlatformFee(600) + ).to.be.revertedWith("Fee cannot exceed 5%"); + }); + + it("Should transfer ownership", async function () { + await agroExchange.connect(owner).transferOwnership(addr3.address); + expect(await agroExchange.owner()).to.equal(addr3.address); + }); + }); +}); diff --git a/backend/controllers/appointmentController.js b/backend/controllers/appointmentController.js new file mode 100644 index 0000000000000000000000000000000000000000..21735b3c56ad3d5752fe503a4d63bf0674724a89 --- /dev/null +++ b/backend/controllers/appointmentController.js @@ -0,0 +1,81 @@ +// appointmentController.js + +import Appointment from "../models/appointmentModel.js"; +import User from "../models/auth.model.js"; + +// Booking an appointment +export const bookAppointment = async (req, res, io) => { + try { + const { expertId } = req.body; + const farmerId = req.userId; // Get farmerId from the token + + const appointment = await Appointment.create({ farmerId, expertId }); + const expert = await User.findById(expertId); + + if (expert.socketId) { + io.to(expert.socketId).emit('appointmentRequest', { + appointMentId: appointment._id, + farmerId: farmerId, + }); + } + + res.status(200).json({ message: "Appointment request sent to expert" }); + } catch (error) { + console.error(error); + res.status(500).json({ error: "An error occurred while booking the appointment" }); + } +}; + +// Accept an appointment +export const acceptAppointment = async (req, res, io) => { + try { + const { appointmentId } = req.params; + const appointment = await Appointment.findByIdAndUpdate(appointmentId, { status: 'accepted' }, { new: true }); + if (!appointment) return res.status(404).json({ error: "Appointment not found" }); + + io.to(appointment.farmerId.toString()).emit('appointmentAccepted', { appointmentId }); + res.status(200).json({ message: "Appointment accepted successfully" }); + } catch (_error) { + res.status(500).json({ error: "An error occurred while accepting an appointment" }); + } +}; + +// Decline an appointment +export const declineAppointment = async (req, res, io) => { + try { + const { appointmentId } = req.params; + const appointment = await Appointment.findByIdAndUpdate(appointmentId, { status: 'declined' }, { new: true }); + if (!appointment) return res.status(404).json({ error: "Appointment not found" }); + + io.to(appointment.farmerId.toString()).emit('appointmentDeclined', { appointmentId }); + res.status(200).json({ message: "Appointment declined successfully" }); + } catch (_error) { + res.status(500).json({ error: "An error occurred while declining the appointment" }); + } +}; + +// Get all appointments for expert +export const getAppointmentsForExpert = async (req, res) => { + try { + const expertId = req.userId; // Get expertId from the token + const appointments = await Appointment.find({ expertId }).populate('farmerId', 'name'); // Assuming 'farmerId' contains the farmer's data like name + if (!appointments) return res.status(404).json({ error: "No appointments found for this expert" }); + + res.status(200).json(appointments); + } catch (_error) { + res.status(500).json({ error: "An error occurred while fetching appointments for expert" }); + } +}; + +// Get all appointments for farmer +export const getAppointmentsForFarmer = async (req, res) => { + try { + const farmerId = req.userId; // Get farmerId from the token + const appointments = await Appointment.find({ farmerId }).populate('expertId', 'name'); // Assuming 'expertId' contains the expert's data like name + if (!appointments) return res.status(404).json({ error: "No appointments found for this farmer" }); + + res.status(200).json(appointments); + } catch (_error) { + res.status(500).json({ error: "An error occurred while fetching appointments for farmer" }); + } +}; diff --git a/backend/controllers/authController.js b/backend/controllers/authController.js new file mode 100644 index 0000000000000000000000000000000000000000..ce3b96c933f09f94799c01c274b8c374dd8c5b2c --- /dev/null +++ b/backend/controllers/authController.js @@ -0,0 +1,73 @@ +import User from "../models/auth.model.js"; + +const normalizeEmail = (email) => email?.trim().toLowerCase() || null; + +const profileFromRequest = (req) => ({ + _id: req.userId, + id: req.userId, + firebaseUid: req.userId, + email: normalizeEmail(req.userEmail || req.firebaseUser?.email), + name: req.firebaseUser?.name || req.firebaseUser?.email?.split("@")[0] || "User", + role: req.userRole || "farmer", + img: req.firebaseUser?.picture || null, +}); + +/** + * POST /api/auth/sync-user + * Firebase Auth is the identity provider. Firestore stores the application + * profile and role; passwords and server-issued JWTs are never persisted. + */ +export const syncGoogleUser = async (req, res) => { + try { + if (!req.firebaseUser?.uid) return res.status(401).json({ message: "Unauthorized" }); + + const uid = req.firebaseUser.uid; + const existing = await User.findById(uid); + const requestedRole = req.body?.role; + const role = existing?.role || requestedRole || req.userRole || "farmer"; + const profile = { + ...profileFromRequest(req), + role, + email: normalizeEmail(req.firebaseUser.email), + updatedAt: new Date(), + }; + + const user = await User.findByIdAndUpdate(uid, { $set: profile }, { upsert: true, new: true }); + return res.status(200).json({ + message: "User synced", + role: user?.role || role, + userId: uid, + user, + }); + } catch (error) { + console.error("syncFirebaseUser error:", error); + return res.status(500).json({ message: "Unable to sync Firebase user" }); + } +}; + +// Password creation and verification now happen in Firebase Auth on the client. +// These routes remain explicit so stale clients receive a clear migration error +// rather than silently creating a legacy JWT session. +export const signup = async (_req, res) => res.status(410).json({ + message: "Password signup moved to Firebase Authentication. Please update the app.", +}); + +export const signin = async (_req, res) => res.status(410).json({ + message: "Password sign-in moved to Firebase Authentication. Please update the app.", +}); + +export const signout = async (req, res) => { + res.clearCookie("firebaseToken", { httpOnly: true, secure: true, sameSite: "none", path: "/" }); + return res.status(200).json({ message: "Logged out successfully" }); +}; + +export const getUserProfile = async (req, res) => { + try { + if (!req.userId) return res.status(401).json({ message: "Authentication required" }); + const user = await User.findById(req.userId); + return res.json(user || profileFromRequest(req)); + } catch (error) { + console.error("getUserProfile error:", error); + return res.status(500).json({ message: "Internal server error" }); + } +}; diff --git a/backend/controllers/blogRecommendationsController.js b/backend/controllers/blogRecommendationsController.js new file mode 100644 index 0000000000000000000000000000000000000000..56bc8d535a0a5e19411112dc2e074b51014c9ae6 --- /dev/null +++ b/backend/controllers/blogRecommendationsController.js @@ -0,0 +1,29 @@ +import { generateAIContent } from '../utils/aiHelper.js'; +import { extractLanguage, getLanguageName } from '../utils/aiOrchestrator.js'; +import dotenv from 'dotenv'; + +export const getBlogRecommendations = async (req, res) => { + dotenv.config(); + + const { region: _region } = req.query; + const lang = extractLanguage(req); + const langName = getLanguageName(lang); + const langInstruction = lang !== 'en' ? `\nRespond STRICTLY in ${langName} language.` : ''; + + try { + const promptText = ` + please provide the following for the experts with new recommendations every time : + + Suggest 2 topics in 5-6 words that an expert can write about to help farmers address current issues effectively . + + + Keep each point clear, expert-friendly, and should focus on the most current weather problems, crop health problems, or economic conditions of the farmers or any recent concerns.${langInstruction} + `; + + const recommendations = await generateAIContent(promptText.trim()); + res.status(200).json({ recommendations }); + } catch (err) { + console.error("Error fetching expert recommendations: ", err); + res.status(500).json({ error: "Failed to fetch recommendations" }); + } +}; diff --git a/backend/controllers/cropController.js b/backend/controllers/cropController.js new file mode 100644 index 0000000000000000000000000000000000000000..338561c20a9a9307dc9194acebab2b94d164034b --- /dev/null +++ b/backend/controllers/cropController.js @@ -0,0 +1,47 @@ +import Crop from '../models/crop.model.js'; + +export const addCrop = async (req, res) => { + try { + console.log("User ID:", req.userId); // Log the user ID for debugging + const newCrop = new Crop({ + ...req.body, + user: req.userId, // Make sure req.userId is set by the middleware + }); + + const savedCrop = await newCrop.save(); + res.status(201).json(savedCrop); + } catch (error) { + res.status(500).json({ message: "Error occurred while adding crop", error }); + } +}; + +export const getAllCrops = async (req, res) => { + try { + const crops = await Crop.find({ user: req.userId }).populate("irrigationData"); + res.status(200).json(crops); + } catch (error) { + res.status(500).json({ message: error.message }); + } +}; + +export const updateCrop = async (req, res) => { + const { id } = req.params; + const { name, growthProgress, yieldData } = req.body; + try { + const crop = await Crop.findOne({ _id: id, user: req.userId }); + if (!crop) return res.status(404).json({ message: "Crop not found" }); + + if (name) crop.name = name; + if (growthProgress !== undefined) crop.growthProgress = growthProgress; + + // Ensure yieldData is an array of objects with "month" and "yield" + if (Array.isArray(yieldData) && yieldData.every(item => item.month && item.yield)) { + crop.yieldData.push(...yieldData); + } + + const updatedCrop = await crop.save(); + res.status(200).json(updatedCrop); + } catch (err) { + res.status(500).json({ message: "Failed to update crop", error: err.message }); + } +}; diff --git a/backend/controllers/cropRotationController.js b/backend/controllers/cropRotationController.js new file mode 100644 index 0000000000000000000000000000000000000000..525b122120f04dab7321de1f55b57cd583fc6336 --- /dev/null +++ b/backend/controllers/cropRotationController.js @@ -0,0 +1,66 @@ +import { generateAIContent } from '../utils/aiHelper.js'; +import { extractLanguage, getLanguageName } from '../utils/aiOrchestrator.js'; +import dotenv from "dotenv"; + +export const cropRotationRecommendations = async (req, res) => { + dotenv.config(); + + const { previousCrop, npkDepletion, waterAvailability, soilType, region } = + req.body; + + if ( + !previousCrop || + !npkDepletion || + !waterAvailability || + !soilType || + !region + ) { + return res.status(400).json({ + error: "Missing required inputs: previousCrop, npkDepletion, waterAvailability, soilType, region", + }); + } + + const lang = extractLanguage(req); + const langName = getLanguageName(lang); + const langInstruction = lang !== 'en' ? `\n\nRespond STRICTLY in ${langName} language. Translate all fields and values.` : ''; + + try { + const prompt = ` + You are an expert agricultural crop rotation scientist. + + Based on the following: + - Previous Crop: ${previousCrop} + - NPK Depletion (major nutrient lost): ${npkDepletion} + - Water Availability: ${waterAvailability} + - Soil Type: ${soilType} + - Region: ${region} + + Suggest the best crop to plant next to: + - Restore depleted nutrients naturally + - Increase soil fertility long-term + - Improve economic profitability + + Provide the answer ONLY in this strict JSON format: + + { + "recommended_crop": "", + "reasons": ["", "", ""], + "nutrient_restoration_benefit": "", + "expected_profitability": "", + "note": "" + }${langInstruction} + `; + + const recommendation = await generateAIContent(prompt.trim()); + const formattedRecommendation = recommendation + .replace("```json", "") + .replace("```", "") + .trim(); + res.status(200).json({ + recommendation: formattedRecommendation, + }); + } catch (err) { + console.error("Error fetching recommendations: ", err); + res.status(500).json({ error: "Failed to fetch recommendations" }); + } +}; diff --git a/backend/controllers/detectHarvestReadinessController.js b/backend/controllers/detectHarvestReadinessController.js new file mode 100644 index 0000000000000000000000000000000000000000..bdc22f75df49d2271a5b2e185e2ce068b1f6963f --- /dev/null +++ b/backend/controllers/detectHarvestReadinessController.js @@ -0,0 +1,92 @@ +import dotenv from "dotenv"; +import { generateAIContentWithVision } from "../utils/aiHelper.js"; +import { extractLanguage, getLanguageName } from "../utils/aiOrchestrator.js"; +import FormData from "form-data"; + +const AI_BACKEND_URL = process.env.AI_BACKEND_URL || "http://localhost:5000"; + +/** + * Try the YOLO harvest readiness model on the AI backend first. + * Returns the result object or null if the AI backend is unavailable. + */ +async function tryYoloModel(fileBuffer, originalname, mimetype) { + try { + const form = new FormData(); + form.append("file", fileBuffer, { + filename: originalname || "image.jpg", + contentType: mimetype || "image/jpeg", + }); + + const response = await fetch(`${AI_BACKEND_URL}/harvest_readiness`, { + method: "POST", + body: form, + headers: form.getHeaders(), + }); + + if (!response.ok) return null; + const data = await response.json(); + if (data.error) return null; + return data; + } catch { + return null; + } +} + +export const detectHarvestReadiness = async (req, res) => { + dotenv.config(); + try { + if (!req.file) { + return res.status(400).json({ error: "No image uploaded" }); + } + + // Try YOLO model first + const yoloResult = await tryYoloModel( + req.file.buffer, + req.file.originalname, + req.file.mimetype + ); + if (yoloResult) { + return res.status(200).json(yoloResult); + } + + // Fallback to Gemini vision AI + const base64Image = req.file.buffer?.toString("base64"); + const lang = extractLanguage(req); + const langName = getLanguageName(lang); + const langInstruction = lang !== 'en' ? `\nRespond STRICTLY in ${langName} language for the "note" field.` : ''; + + const prompt = ` + You are an agricultural expert. + + Analyze the crop in this image and provide: + + 1. Whether the crop is ready for harvest (Yes/No). + 2. Percentage maturity (0–100%). + 3. Estimated days left for optimal harvest. + 4. Very short explanation (1–2 lines). + + Return data in strict JSON format: + { + "ready": "Yes/No", + "maturity": 0-100, + "days_left": number, + "note": "short text" + }${langInstruction} + `; + + const aiText = await generateAIContentWithVision(prompt, base64Image, req.file.mimetype); + + const cleanJsonString = aiText.replace("```json", "").replace("```", "").trim(); + + try { + const result = JSON.parse(cleanJsonString); + return res.status(200).json(result); + } catch (_err) { + console.log("AI did not return valid JSON:", aiText); + return res.status(500).json({ error: "Failed to parse AI response", raw: aiText }); + } + } catch (error) { + console.error("Error detecting harvest readiness:", error.message || error); + res.status(500).json({ error: "Failed to detect harvest readiness" }); + } +}; diff --git a/backend/controllers/expertDetailsController.js b/backend/controllers/expertDetailsController.js new file mode 100644 index 0000000000000000000000000000000000000000..3eeafeb31b797792d1fa197ca1e4ac4b593f28e3 --- /dev/null +++ b/backend/controllers/expertDetailsController.js @@ -0,0 +1,128 @@ +import ExpertDetails from '../models/expertDetail.model.js'; +import User from '../models/auth.model.js'; + +// Get Expert Details +export const getExpertDetails = async (req, res) => { + try { + const expertDetails = await ExpertDetails.findOne({ userId: req.params.userId }); + + // If expert details are not found, return default values + if (!expertDetails) { + const defaultDetails = { + expertStats: { successfulAppointments: 0, farmersHelped: 0, experience: 0, rating: 0 }, + appointmentStats: { + totalAppointments: 0, + satisfactionRating: 0, + adviceAreas: { cropManagement: 0, pestControl: 0, irrigation: 0 } + }, + blogEngagement: { views: 0, comments: 0, likes: 0 } + }; + return res.status(200).json(defaultDetails); + } + + res.status(200).json(expertDetails); + } catch (error) { + res.status(500).json({ message: 'Server Error', error }); + } +}; + +// Add Expert Details +export const addExpertDetails = async (req, res) => { + try { + const userId = req.userId; // Use authenticated user's ID + const { expertStats, appointmentStats, blogEngagement } = req.body; + + // Check if the user exists and is an expert + const user = await User.findById(userId); + if (!user || user.role !== 'expert') { + return res.status(400).json({ message: 'Invalid expert user ID' }); + } + + // Check if expert details already exist + const existingDetails = await ExpertDetails.findOne({ userId }); + if (existingDetails) { + return res.status(400).json({ message: 'Expert details already exist' }); + } + + const newExpertDetails = new ExpertDetails({ + userId, + expertStats, + appointmentStats, + blogEngagement, + }); + + await newExpertDetails.save(); + res.status(201).json(newExpertDetails); + } catch (error) { + res.status(500).json({ message: 'Server Error', error }); + } +}; + +// Update Expert Details +export const updateExpertDetails = async (req, res) => { + try { + // Try to find the expert details for the given userId + let expertDetails = await ExpertDetails.findOne({ userId: req.params.userId }); + + // If expert details don't exist, create a new document for this user + if (!expertDetails) { + expertDetails = new ExpertDetails({ + userId: req.params.userId, + expertStats: { + successfulAppointments: 0, + farmersHelped: 0, + experience: 0, + rating: 0 + }, + appointmentStats: { + totalAppointments: 0, + satisfactionRating: 0, + adviceAreas: { + cropManagement: 0, + pestControl: 0, + irrigation: 0 + } + }, + blogEngagement: { + views: 0, + comments: 0, + likes: 0 + } + }); + } + + // Update the expert details with the values from the request body, if provided + const { expertStats, appointmentStats, blogEngagement } = req.body; + + if (expertStats) { + expertDetails.expertStats = { + ...expertDetails.expertStats.toObject(), + ...expertStats + }; + } + + if (appointmentStats) { + expertDetails.appointmentStats = { + ...expertDetails.appointmentStats.toObject(), + ...appointmentStats + }; + } + + if (blogEngagement) { + expertDetails.blogEngagement = { + ...expertDetails.blogEngagement.toObject(), + ...blogEngagement + }; + } + + // Save the updated expert details + await expertDetails.save(); + + // Respond with the updated expert details + res.status(200).json(expertDetails); + + } catch (error) { + // Handle any server errors + res.status(500).json({ message: 'Server Error', error }); + } +}; diff --git a/backend/controllers/farmerDetailsController.js b/backend/controllers/farmerDetailsController.js new file mode 100644 index 0000000000000000000000000000000000000000..f65b992aac2ace34c6a1cfce81c2080c37908ce0 --- /dev/null +++ b/backend/controllers/farmerDetailsController.js @@ -0,0 +1,92 @@ +import FarmerDetails from "../models/farmerDetail.model.js"; +import User from '../models/auth.model.js' + +//getting farmer details by id +export const getFarmerDetails = async (req, res) => { + try { + const farmerDetails = await FarmerDetails.findOne({ user: req.params.userId }); + if (!farmerDetails) { + return res.status(404).json({ message: 'Farmer details not found' }); + } + res.status(200).json(farmerDetails); + } catch (error) { + res.status(500).json({ message: 'Server Error', error }); + } + }; + +//adding farmer details +export const addFarmerDetails = async(req,res)=>{ + try{ + const userId = req.userId + const {phone, address, region, climate, cropNames, amountOfLand, otherDetails}= req.body + + const user = await User.findById(userId) + if(!user || user.role!=='farmer'){ + return res.status(400).json({message:"Invalid expert user ID"}) + } + + const existingDetails = await FarmerDetails.findOne({userId}) + if(existingDetails){ + return res.status(400).json({message:'Farmer details already exist'}) + } + + const newFarmerDetails = new FarmerDetails({ + user: userId, + phone, + address, + region, + climate, + cropNames, + amountOfLand, + otherDetails + }) + await newFarmerDetails.save() + res.status(201).json(newFarmerDetails) + + }catch(error){ + res.status(500).json({ message: 'Server Error', error }); + } +} + +export const updateFarmerDetails = async (req, res) => { + try { + // Find the farmer's details based on the userId in the URL + const farmerDetails = await FarmerDetails.findOne({ user: req.params.userId }); + if (!farmerDetails) { + return res.status(404).json({ message: "Farmer details not found" }); + } + + // Destructure fields from the request body + const { phone, address, region, climate, cropNames, amountOfLand, otherDetails } = req.body; + + // Update fields only if they are provided and different from the existing values + if (phone && phone !== farmerDetails.phone) { + farmerDetails.phone = phone; + } + if (address && address !== farmerDetails.address) { + farmerDetails.address = address; + } + if (region && region !== farmerDetails.region) { + farmerDetails.region = region; + } + if (climate && climate !== farmerDetails.climate) { + farmerDetails.climate = climate; + } + if (cropNames && JSON.stringify(cropNames) !== JSON.stringify(farmerDetails.cropNames)) { + farmerDetails.cropNames = cropNames; + } + if (amountOfLand && amountOfLand !== farmerDetails.amountOfLand) { + farmerDetails.amountOfLand = amountOfLand; + } + if (otherDetails && otherDetails !== farmerDetails.otherDetails) { + farmerDetails.otherDetails = otherDetails; + } + + // Save the updated farmer details + await farmerDetails.save(); + + res.status(200).json({ message: "Farmer details updated successfully", farmerDetails }); + } catch (error) { + res.status(500).json({ message: "Error updating farmer details", error }); + } +}; diff --git a/backend/controllers/farmingNewsController.js b/backend/controllers/farmingNewsController.js new file mode 100644 index 0000000000000000000000000000000000000000..2b9d3b0ad5bcb0d7a67e249edf4d81c132bfedba --- /dev/null +++ b/backend/controllers/farmingNewsController.js @@ -0,0 +1,17 @@ +import axios from 'axios' + +export const getFarmingNews = async(req, res)=>{ + const api_key = process.env.NEWS_API_KEY; + const url = `https://newsapi.org/v2/everything?q=farming&apiKey=${api_key}`; + + try{ + const response = await axios.get(url); + // console.log(response); + const articles = response.data.articles; + // console.log(" Articles is : ", articles); + res.status(200).json(articles); + }catch(err){ + console.error("Error fetching news : ", err); + res.status(500).json({message : "Error fetching news"}); + } +} \ No newline at end of file diff --git a/backend/controllers/geoPestDiseaseHeatmapController.js b/backend/controllers/geoPestDiseaseHeatmapController.js new file mode 100644 index 0000000000000000000000000000000000000000..31f55a1e72ab8fc1872192f225fe265c01e37e5f --- /dev/null +++ b/backend/controllers/geoPestDiseaseHeatmapController.js @@ -0,0 +1,60 @@ +import { generateAIContent } from '../utils/aiHelper.js'; +import { extractLanguage, getLanguageName } from '../utils/aiOrchestrator.js'; +import dotenv from "dotenv"; + +export const geoPestDiseaseHeatmapRecommendations = async (req, res) => { + dotenv.config(); + + const { location, cropType, cropStage } = req.body; + + if (!location) { + return res.status(400).json({ + error: "Missing required input: location", + }); + } + + const lang = extractLanguage(req); + const langName = getLanguageName(lang); + const langInstruction = lang !== 'en' ? `\n\nRespond STRICTLY in ${langName} language. Translate all fields and values.` : ''; + + try { + const prompt = ` + You are an agricultural pest & disease outbreak prediction expert. + + Analyze early pest/disease outbreak risks based on: + - Farm Location: ${location} + - Crop Type (optional): ${cropType || "Not provided"} + - Crop Stage (optional): ${cropStage || "Not provided"} + + Use indicators such as: + - Satellite vegetation stress signals + - Humidity + temperature patterns + - Rainfall + soil moisture + - Community farmer reports in nearby villages + - Seasonal pest migration trends + + Provide ONLY the JSON output in the following format: + + { + "risk_level": "Low/Moderate/High/Severe", + "hotspot_zones": ["", "", ""], + "likely_threat": "", + "expected_outbreak_days": 0, + "preventive_actions": ["", "", ""], + "note": "" + }${langInstruction} + `; + + const recommendation = await generateAIContent(prompt.trim()); + const formattedRecommendation = recommendation + .replace("```json", "") + .replace("```", "") + .trim(); + res.status(200).json({ + recommendation: formattedRecommendation, + }); + } catch (err) { + console.error("Error fetching recommendations: ", err); + res.status(500).json({ error: "Failed to fetch recommendations" }); + } +}; diff --git a/backend/controllers/getExpertsController.js b/backend/controllers/getExpertsController.js new file mode 100644 index 0000000000000000000000000000000000000000..8845b614aba4d0556a82ebefe6b0a799d7c1ec75 --- /dev/null +++ b/backend/controllers/getExpertsController.js @@ -0,0 +1,11 @@ +import User from '../models/auth.model.js' + +// controller to get all expert user +export const getExperts = async(req, res)=>{ + try{ + const experts = await User.find({role: 'expert'}); + res.status(200).json(experts); + }catch(err){ + res.status(500).json({message : "Failed to fetch the user details", err}); + } +} \ No newline at end of file diff --git a/backend/controllers/getLoanEligibilityReportController.js b/backend/controllers/getLoanEligibilityReportController.js new file mode 100644 index 0000000000000000000000000000000000000000..5da359d050aa307cc2056974b4108b521691ccc8 --- /dev/null +++ b/backend/controllers/getLoanEligibilityReportController.js @@ -0,0 +1,73 @@ +import { generateAIContent } from '../utils/aiHelper.js'; +import { extractLanguage, getLanguageName } from '../utils/aiOrchestrator.js'; +import dotenv from "dotenv"; + +export const getLoanEligibilityReport = async (req, res) => { + dotenv.config(); + + const { + location, + landSize, + landType, + cropType, + cropStage, + pastYield, + existingLoans, + } = req.body; + + if (!location || !landSize || !landType || !cropType || !cropStage) { + return res.status(400).json({ + error: "Missing required inputs: location, landSize, landType, cropType, cropStage", + }); + } + + const lang = extractLanguage(req); + const langName = getLanguageName(lang); + const langInstruction = lang !== 'en' ? `\n\nRespond STRICTLY in ${langName} language. Translate all fields and values.` : ''; + + try { + const prompt = ` + You are an expert agricultural financial analyst who evaluates farmer credit eligibility based on farm potential and financial risk. + + Evaluate the farmer using: + - Farm Location: ${location} + - Land Size: ${landSize} + - Land Type: ${landType} + - Crop Type: ${cropType} + - Crop Stage: ${cropStage} + - Past Yield (optional): ${pastYield || "Not provided"} + - Existing Loans (optional): ${existingLoans || "Not provided"} + + Consider: + - Crop yield prediction + - Soil health and farm productivity potential + - Market price forecast & demand trends + - Climate risk profile (drought/flood probability) + - Irrigation access and fertilizer usage (assume based on crop & region if not given) + - Cropping pattern stability + + Provide the output ONLY in the following JSON format: + + { + "loan_approval_probability": 0, + "eligible_loan_amount_range": "", + "risk_category": "", + "expected_repayment_capacity": "", + "recommendations": ["", "", ""], + "note": "" + }${langInstruction} + `; + + const recommendation = await generateAIContent(prompt.trim()); + const formattedRecommendation = recommendation + .replace("```json", "") + .replace("```", "") + .trim(); + res.status(200).json({ + recommendation: formattedRecommendation, + }); + } catch (err) { + console.error("Error fetching recommendations: ", err); + res.status(500).json({ error: "Failed to fetch recommendations" }); + } +}; diff --git a/backend/controllers/irrigationController.js b/backend/controllers/irrigationController.js new file mode 100644 index 0000000000000000000000000000000000000000..c135492cf4224ae4a436dc37adb03f249e32f231 --- /dev/null +++ b/backend/controllers/irrigationController.js @@ -0,0 +1,37 @@ +// controllers/irrigationController.js +import Irrigation from '../models/irrigation.model.js'; + +export const addIrrigationData = async (req, res) => { + const { cropId } = req.params; + const { month, waterUsage, forecastedUsage } = req.body; + + try { + + const userId = req.userId; + // Create and save new irrigation data associated with the crop + const irrigationData = new Irrigation({ + crop: cropId, + user: userId, + month, + waterUsage, + forecastedUsage, + }); + await irrigationData.save(); + + res.status(201).json({ message: 'Irrigation data added successfully', irrigationData }); + } catch (error) { + res.status(500).json({ message: 'Failed to add irrigation data', error }); + } +}; + +// Optional: Controller to get all irrigation data for a specific crop +export const getAllIrrigationDataByCrop = async (req, res) => { + const { cropId } = req.params; + try { + const userId = req.userId; + const irrigationData = await Irrigation.find({ crop: cropId, user: userId }); + res.status(200).json(irrigationData); + } catch (error) { + res.status(500).json({ message: 'Failed to retrieve irrigation data', error }); + } +}; diff --git a/backend/controllers/marketPredictionController.js b/backend/controllers/marketPredictionController.js new file mode 100644 index 0000000000000000000000000000000000000000..9fd9a957495da9a72f903314b6b1e9af11eff9db --- /dev/null +++ b/backend/controllers/marketPredictionController.js @@ -0,0 +1,76 @@ +import { generateAIContent } from '../utils/aiHelper.js'; +import { extractLanguage, getLanguageName } from '../utils/aiOrchestrator.js'; +import dotenv from "dotenv"; + +export const marketPredictionRecommendations = async (req, res) => { + dotenv.config(); + + const { + cropType, + region, + currentPrice, + mandiOptions, + season, + marketArrivals, + } = req.body; + + if ( + !cropType || + !region || + !currentPrice || + !mandiOptions || + !season || + !marketArrivals + ) { + return res.status(400).json({ + error: "Missing required inputs: cropType, region, currentPrice, mandiOptions, season, marketArrivals", + }); + } + + const lang = extractLanguage(req); + const langName = getLanguageName(lang); + const langInstruction = lang !== 'en' ? `\n\nRespond STRICTLY in ${langName} language. Translate all fields and values.` : ''; + + try { + const prompt = ` + You are an agricultural market economist specializing in crop price forecasting. + + Analyze and predict crop selling strategy based on: + - Crop: ${cropType} + - Region: ${region} + - Current Price: ${currentPrice} + - Available Mandis/Markets: ${mandiOptions} + - Current Season/Festival Impact: ${season} + - Market Arrivals (supply level): ${marketArrivals} + + Consider: + - Historical mandi data + - Demand–supply trends + - Seasonal/Festival inflation + - Weather influence on supply + + Provide ONLY this JSON output: + + { + "predicted_price_next_week": "β‚Ήvalue per quintal/kg", + "sell_now": "Yes/No", + "best_market": "", + "price_trend": "Rising/Stable/Falling", + "expected_change_percent": 0, + "note": "" + }${langInstruction} + `; + + const recommendation = await generateAIContent(prompt.trim()); + const formattedRecommendation = recommendation + .replace("```json", "") + .replace("```", "") + .trim(); + res.status(200).json({ + recommendation: formattedRecommendation, + }); + } catch (err) { + console.error("Error fetching recommendations: ", err); + res.status(500).json({ error: "Failed to fetch recommendations" }); + } +}; diff --git a/backend/controllers/notificationsController.js b/backend/controllers/notificationsController.js new file mode 100644 index 0000000000000000000000000000000000000000..d169eaa7a139b6bccde1906d0794ca51d5a3fd15 --- /dev/null +++ b/backend/controllers/notificationsController.js @@ -0,0 +1,88 @@ +import { generateAIContent } from '../utils/aiHelper.js'; +import { extractLanguage, getLanguageName } from '../utils/aiOrchestrator.js'; +import dotenv from 'dotenv'; +import { Notification } from "../utils/firestoreCollections.js"; + +export const getFarmingAlerts = async (req, res) => { + dotenv.config(); + + const { region } = req.query; + const lang = extractLanguage(req); + const langName = getLanguageName(lang); + const langInstruction = lang !== 'en' ? `\nRespond STRICTLY in ${langName} language.` : ''; + + try { + const promptText = ` + Please provide a maximum of 2 short and recent farming alerts or notifications in max 5-6 words related to farming weather and conditions, specifically for the region of ${region}. + + Focus on: + - Important weather-related alerts relevant to farming today. + - Any immediate farming precautions or actions farmers should take. + + Keep each alert clear, brief, and farmer-friendly. Thank you!${langInstruction} + `; + + const alerts = await generateAIContent(promptText.trim()); + res.status(200).json({ alerts }); + } catch (err) { + console.error("Error fetching farming alerts: ", err); + res.status(500).json({ error: "Failed to fetch alerts" }); + } +}; + +export const listNotifications = async (req, res) => { + try { + const userId = req.user?._id; + + if (!userId) { + return res.status(401).json({ success: false, error: 'Unauthorized' }); + } + + const notifications = await Notification.find({ userId }).sort('-createdAt').limit(20).lean(); + const unread = notifications.filter((n) => !n.read).length; + + return res.status(200).json({ + success: true, + data: { + notifications, + unread, + }, + }); + } catch (err) { + return res.status(500).json({ success: false, error: err.message }); + } +}; + +export const seedNotification = async (req, res) => { + try { + const userId = req.user?._id; + if (!userId) { + return res.status(401).json({ success: false, error: 'Unauthorized' }); + } + + const { title, message, type = 'general', link } = req.body || {}; + if (!title || !message) { + return res.status(400).json({ success: false, error: 'title and message are required' }); + } + + const created = await Notification.create({ userId, title, message, type, link }); + return res.status(201).json({ success: true, data: created }); + } catch (err) { + return res.status(500).json({ success: false, error: err.message }); + } +}; + +export const markNotificationRead = async (req, res) => { + try { + const userId = req.user?._id; + const { id } = req.params; + if (!userId) { + return res.status(401).json({ success: false, error: 'Unauthorized' }); + } + + await Notification.updateOne({ _id: id, userId }, { $set: { read: true } }); + return res.status(200).json({ success: true }); + } catch (err) { + return res.status(500).json({ success: false, error: err.message }); + } +}; diff --git a/backend/controllers/pestOutbreakController.js b/backend/controllers/pestOutbreakController.js new file mode 100644 index 0000000000000000000000000000000000000000..a27125f789d2d3c1a12f7bbfceafb9c3d5a99321 --- /dev/null +++ b/backend/controllers/pestOutbreakController.js @@ -0,0 +1,62 @@ +import { generateAIContent } from '../utils/aiHelper.js'; +import { extractLanguage, getLanguageName } from '../utils/aiOrchestrator.js'; +import dotenv from "dotenv"; + +export const pestOutbreakRecommendations = async (req, res) => { + dotenv.config(); + + const { region, weather, cropType, communityReports } = req.body; + + if (!region || !weather || !cropType || !communityReports) { + return res.status(400).json({ + error: "Missing required inputs: region, weather, cropType, communityReports", + }); + } + + const lang = extractLanguage(req); + const langName = getLanguageName(lang); + const langInstruction = lang !== 'en' ? `\n\nRespond STRICTLY in ${langName} language. Translate all fields and values.` : ''; + + try { + const prompt = ` + You are an agricultural pest outbreak prediction expert. + + Analyze the risk of pest infestation using: + - Region: ${region} + - Weather forecast: ${weather} + - Crop type: ${cropType} + - Community pest reports (last 7 days): ${communityReports} + + Provide: + 1. Whether there is a risk of pest outbreak (Yes/No) + 2. Likely pest that may attack (e.g., stem borer, aphids, bollworm, etc.) + 3. Risk level (%) based on severity and probability + 4. Expected time window (days until possible outbreak) + 5. Preventive actions farmers should take immediately (bullet points) + 6. A short note (1–2 lines of advice) + + Respond ONLY in this JSON format: + + { + "outbreak_risk": "", + "likely_pest": "", + "risk_level_percent": 0, + "expected_days": 0, + "preventive_actions": ["", "", ""], + "note": "" + }${langInstruction} + `; + + const recommendation = await generateAIContent(prompt.trim()); + const formattedRecommendation = recommendation + .replace("```json", "") + .replace("```", "") + .trim(); + res.status(200).json({ + recommendation: formattedRecommendation, + }); + } catch (err) { + console.error("Error fetching recommendations: ", err); + res.status(500).json({ error: "Failed to fetch recommendations" }); + } +}; diff --git a/backend/controllers/postController.js b/backend/controllers/postController.js new file mode 100644 index 0000000000000000000000000000000000000000..242af5db3bedc16f442b78ae73319c0be6616478 --- /dev/null +++ b/backend/controllers/postController.js @@ -0,0 +1,95 @@ +import Post from '../models/post.model.js'; + +// creating a post +export const createPost = async(req, res)=>{ + try{ + const {title, content} = req.body; + const post = new Post({title, content, author: req.userId}); + await post.save(); + res.status(201).json({message: "Post saved successfully", post}); + }catch(err){ + res.status(500).json({message: "Something went wrong", err}); + } +} + +// Get all posts for loggedin user +export const getAllPost = async(req, res)=>{ + try{ + const posts = await Post.find().populate('author', 'username'); + res.status(200).json(posts); + }catch(err){ + res.status(500).json({message: "Error fetching all post", err}); + } +} + +// Get posts of a user +export const getPostsByUser = async (req, res) => { + try { + // Extract userId from the authenticated user (JWT token) + const userId = req.userId; // Assuming the userId is decoded and set in the token verification middleware + + if (!userId) { + return res.status(400).json({ message: 'User ID is missing or invalid' }); + } + + // Find posts based on the userId + const posts = await Post.find({ author: userId }).populate('author', 'username'); + if (posts.length === 0) { + return res.status(404).json({ message: 'No posts found for this user' }); + } + res.status(200).json(posts); + } catch (err) { + console.error('Error fetching user posts:', err); + res.status(500).json({ message: 'Error fetching user posts', error: err.message }); + } + }; + +export const getPostById = async(req, res)=>{ + try{ + const {id} = req.params; + const post = await Post.findById(id).populate('author', 'username'); + if(!post){ + return res.status(404).json({message: 'Post not found'}); + } + + res.status(200).json(post); + }catch(err){ + res.status(500).json({message: 'Error fetching the post', error: err.message}) + } +} + + + +// update post +export const updatePost = async(req, res)=>{ + try{ + const {id} = req.params; + const {title, content} = req.body; + const post = await Post.findByIdAndUpdate({ + _id: id, author: req.userId + }, + { + title, content + },{ + new: true + }); + if(!post){ + return res.status(404).json({message: "Post not found or you are not authorized"}); + } + res.status(200).json({message: "Post updated successfully", post}); + }catch(err){ + res.status(500).json({message: "Failed to update post", err}); + } +} + +// Delete post +export const deletePost = async(req, res)=>{ + try{ + const {id} = req.params; + const post = await Post.findByIdAndDelete({_id: id, author: req.userId}); + if(!post) res.status(404).json({message: "Post not found or you are not authorized"}); + res.status(200).json({message: 'Post deleted successfully'}); + }catch(err){ + res.status(500).json({message: "Failed to delete post", err}); + } +} \ No newline at end of file diff --git a/backend/controllers/recommendationController.js b/backend/controllers/recommendationController.js new file mode 100644 index 0000000000000000000000000000000000000000..df40810088cec6dd6817e28b33e638f25d8681ad --- /dev/null +++ b/backend/controllers/recommendationController.js @@ -0,0 +1,38 @@ +import dotenv from 'dotenv'; +import { extractLanguage } from '../utils/aiOrchestrator.js'; +import { generateAIContent } from '../utils/aiHelper.js'; + +export const getRecommendations = async (req, res) => { + dotenv.config(); + + const { climate, soilType, cropType, cropInfo, weatherDetails, cropConditions } = req.body; + const lang = extractLanguage(req); + + try { + // Construct a detailed prompt for the API based on the farmer's inputs + const promptText = ` + Please provide farming recommendations based on the following information: + + 1. **Climate**: ${climate} + 2. **Soil Type**: ${soilType} + 3. **Crop Type**: ${cropType} + 4. **Information about the Crop**: ${cropInfo} + 5. **Today's Weather**: ${weatherDetails} + 6. **Crop Conditions**: ${cropConditions} + + Based on this information, please suggest: + - Suitable farming practices for today. + - Care tips for the specified crop considering the current weather and soil conditions. + - Any precautions to take given today's weather and crop requirements. + + Make the recommendations clear and easy to understand for farmers. Thank you! + ${lang !== 'en' ? `\n\nRespond STRICTLY in ${req.langName || 'the user\'s preferred language'}.` : ''} + `; + + const recommendation = await generateAIContent(promptText.trim()); + res.status(200).json({ recommendation }); + } catch (err) { + console.error("Error fetching recommendations: ", err); + res.status(500).json({ error: "Failed to fetch recommendations" }); + } +}; diff --git a/backend/controllers/recordController.js b/backend/controllers/recordController.js new file mode 100644 index 0000000000000000000000000000000000000000..655eb3adefb6ef00ec1d29dab415625e447d82f4 --- /dev/null +++ b/backend/controllers/recordController.js @@ -0,0 +1,76 @@ +import Record from "../models/record.model.js"; +import MonthlySummary from'../models/monthlySummary.model.js' + +export const addRecord = async(req,res)=>{ + try { + console.log(req.body); + const { date, expenditure, earnings } = req.body; + const parsedDate = new Date(date); + const month = parsedDate.getMonth() + 1; // JS months are 0-indexed, so add 1 + const year = parsedDate.getFullYear(); + const userId = req.userId; + + const record = new Record({ + date: parsedDate, + expenditure, + earnings, + month, + year, + user: userId, + }); + + await record.save(); + res.status(201).json({ message: 'Record added successfully' }); + } catch (error) { + res.status(500).json({ error: 'Failed to add record', details: error.message }); + } +} + +export const getMonthlySummary = async (req, res) => { + try { + const { year } = req.params; + const userId = req.userId; + const summaries = await MonthlySummary.find({ year, user: userId }); + + res.status(200).json(summaries); + } catch (_error) { + res.status(500).json({ error: 'Failed to retrieve monthly summaries' }); + } +}; + +export const calculateMonthlySummary = async(req,res)=>{ + try { + const { month, year } = req.body; + const userId = req.userId; + + const records = await Record.find({ month, year, user: userId }); + + const totalEarnings = records.reduce((sum, record) => sum + record.earnings, 0); + const totalExpenditure = records.reduce((sum, record) => sum + record.expenditure, 0); + const revenue = totalEarnings - totalExpenditure; + + // Check if a summary already exists for this month and year + let monthlySummary = await MonthlySummary.findOne({ month, year, user: userId }); + if (monthlySummary) { + // Update existing summary + monthlySummary.totalEarnings = totalEarnings; + monthlySummary.totalExpenditure = totalExpenditure; + monthlySummary.revenue = revenue; + } else { + // Create a new summary + monthlySummary = new MonthlySummary({ + month, + year, + totalEarnings, + totalExpenditure, + revenue, + user: userId, + }); + } + + await monthlySummary.save(); + res.status(200).json({ message: 'Monthly summary calculated and saved successfully', monthlySummary }); + } catch (_error) { + res.status(500).json({ error: 'Failed to calculate monthly summary' }); + } +} \ No newline at end of file diff --git a/backend/controllers/soilHealthController.js b/backend/controllers/soilHealthController.js new file mode 100644 index 0000000000000000000000000000000000000000..c548b6d72b1b69002bb4b6f773589f9dda495133 --- /dev/null +++ b/backend/controllers/soilHealthController.js @@ -0,0 +1,74 @@ +import { generateAIContent } from '../utils/aiHelper.js'; +import { extractLanguage, getLanguageName } from '../utils/aiOrchestrator.js'; +import dotenv from "dotenv"; + +export const soilHealthRecommendations = async (req, res) => { + dotenv.config(); + + const { + soilPH, + organicMatter, + nitrogen, + phosphorus, + potassium, + salinity, + cropType, + } = req.body; + + if ( + soilPH === undefined || + organicMatter === undefined || + nitrogen === undefined || + phosphorus === undefined || + potassium === undefined || + salinity === undefined || + !cropType + ) { + return res.status(400).json({ + error: "Missing required inputs: soilPH, organicMatter, nitrogen, phosphorus, potassium, salinity, cropType", + }); + } + + const lang = extractLanguage(req); + const langName = getLanguageName(lang); + const langInstruction = lang !== 'en' ? `\n\nRespond STRICTLY in ${langName} language. Translate all fields and values.` : ''; + + try { + const prompt = ` + You are an expert soil scientist. + + Based on the soil data below: + - pH: ${soilPH} + - Organic Matter (%): ${organicMatter} + - Nitrogen (N): ${nitrogen} + - Phosphorus (P): ${phosphorus} + - Potassium (K): ${potassium} + - Salinity (EC): ${salinity} + - Crop Type: ${cropType} + + Provide: + 1. The main current soil issue (1 short line) + 2. Recommended amendments (bullet list; include lime, gypsum, compost, manure, biofertilizer, etc. if relevant) + 3. NPK balancing recommendation (for example: "increase nitrogen slightly", "reduce phosphorus", etc.) + 4. Estimated time for improvement (e.g., "2–4 weeks", "1–2 months") + 5. A short explanation + + ⚠️ Respond ONLY in valid JSON with this structure: + + { + "current_issue": "", + "recommended_amendments": ["", "", ""], + "npk_adjustment": "", + "expected_improvement_time": "", + "note": "" + }${langInstruction} + `; + + const recommendation = await generateAIContent(prompt.trim()); + const formattedRecommendation = recommendation.replace("```json", "").replace("```", "").trim(); + res.status(200).json({ recommendation: formattedRecommendation }); + } catch (err) { + console.error("Error fetching recommendations: ", err); + res.status(500).json({ error: "Failed to fetch recommendations" }); + } +}; diff --git a/backend/controllers/taskController.js b/backend/controllers/taskController.js new file mode 100644 index 0000000000000000000000000000000000000000..a61b3d82c953b29c22d98c989628e670a8aa40ee --- /dev/null +++ b/backend/controllers/taskController.js @@ -0,0 +1,107 @@ +// import axios from 'axios'; +import Task from '../models/task.model.js'; +// import dotenv from 'dotenv'; + +export const createTask = async(req, res)=>{ + try{ + const {title, description, date, isCompleted} = req.body; + const userId = req.userId; + console.log("Received Date: ", date); + + const task = new Task({title,description,date, isCompleted, user: userId}) + await task.save(); + res.status(201).json(task); + }catch(err){ + res.status(500).json({message: "Failed to create Task",err}); + } +} + +export const getTasks = async(req, res)=>{ + try{ + const userId = req.userId; + const {date} = req.query; + console.log(date); + + const query = date? {date, user: userId} : {user: userId};// if date is provided filter tasks by date + const tasks = await Task.find(query);// fetch task with the query + res.status(200).json(tasks); + }catch(_err){ + res.status(500).json({message : "Failed to get tasks"}); + } +} + +export const getTask = async(req, res)=>{ + try{ + const {id} = req.params; + const userId = req.userId; + const task = await Task.findOne({_id: id, user: userId}); + if(task){ + res.status(201).json(task); + }else{ + res.status(404).json({message: 'Task not found'}); + } + }catch(_err){ + res.status(500).json({message: "Failed to fetch the task"}); + } +} + +export const getTaskByDate = async(req, res)=>{ + try{ + const userId = req.userId; + const {date} = req.params; + const tasks = await Task.find({date : new Date(date), user: userId}); + res.status(200).json(tasks); + }catch(err){ + res.status(500).json({message: "Failed to get task by date"}, err); + } +} + + +export const getMonthlyTaskStats = async (req, res) => { + try { + const { year, month } = req.query; + const userId = req.userId; + const startDate = new Date(year, month - 1, 1); + const endDate = new Date(year, month, 0); + + const tasks = await Task.find({ date: { $gte: startDate, $lte: endDate }, user: userId }); + const totalTasks = tasks.length; + const completedTasks = tasks.filter(task => task.isCompleted).length; + const remainingTasks = totalTasks - completedTasks; + + res.status(200).json({ totalTasks, completedTasks, remainingTasks }); + } catch (error) { + res.status(500).json({ message: 'Failed to get task statistics', error }); + } +}; + +export const updateTask = async(req, res)=>{ + try{ + const {id} = req.params; + const userId = req.userId; + const {title, description, date, isCompleted} = req.body; + const updatedTask = await Task.findOneAndUpdate( + { _id: id, user: userId }, // Ensure the task belongs to the user + { title, description, date, isCompleted }, + { new: true } + ); + if (updatedTask) { + res.status(200).json(updatedTask); + } else { + res.status(404).json({ message: 'Task not found' }); + } + }catch(err){ + res.status(500).json({message: "Failed to update the task", err}); + } +} + +export const deleteTask = async(req, res)=>{ + try{ + const userId = req.userId; + const {id} = req.params; + await Task.findOneAndDelete({_id: id, user: userId}); + res.status(200).json({message : "Deleted successfully"}); + }catch(_err){ + res.status(500).json({message: "Failed to delete the task"}); + } +} diff --git a/backend/controllers/valuechainController.js b/backend/controllers/valuechainController.js new file mode 100644 index 0000000000000000000000000000000000000000..880fd7e489762e2476701868069cd7483380e8a9 --- /dev/null +++ b/backend/controllers/valuechainController.js @@ -0,0 +1,771 @@ +/** + * Value Chain Controller + * Handles all marketplace operations for oilseed by-products + */ +import Listing from "../models/listing.model.js"; +import Offer from "../models/offer.model.js"; +import Processor from "../models/processor.model.js"; +import TransformRequest from "../models/transformRequest.model.js"; +import PriceHistory from "../models/priceHistory.model.js"; + +/** + * Create a new listing + * POST /valuechain/listings + */ +export const createListing = async (req, res) => { + try { + const { + productType, + productName, + description, + quantityKg, + grade, + harvestDate, + expiryDate, + location, + reservePrice, + priceUnit, + photos, + certifications, + tags, + metadata, + } = req.body; + + // Validate required fields + if (!productType || !quantityKg || !harvestDate || !location || !reservePrice) { + return res.status(400).json({ + success: false, + error: "Missing required fields: productType, quantityKg, harvestDate, location, reservePrice", + }); + } + + // Validate location format + if (!location.coordinates || location.coordinates.length !== 2) { + return res.status(400).json({ + success: false, + error: "Location must include valid coordinates [longitude, latitude]", + }); + } + + const listing = new Listing({ + sellerId: req.user._id, + productType, + productName: productName || productType.replace(/_/g, " ").toUpperCase(), + description, + quantityKg, + availableQuantityKg: quantityKg, + grade: grade || "standard", + harvestDate: new Date(harvestDate), + expiryDate: expiryDate ? new Date(expiryDate) : null, + location: { + type: "Point", + coordinates: location.coordinates, + address: location.address, + district: location.district, + state: location.state, + pincode: location.pincode, + }, + reservePrice, + currentPrice: reservePrice, + priceUnit: priceUnit || "per_kg", + photos: photos || [], + certifications: certifications || [], + tags: tags || [], + metadata: metadata || {}, + status: "active", + }); + + await listing.save(); + + // Emit socket event for real-time updates + const io = req.app.get("socketio"); + if (io && typeof io.to === 'function') { + io.to("valuechain").emit("new_listing", { + listingId: listing._id, + productType: listing.productType, + location: listing.location, + price: listing.reservePrice, + }); + } + + res.status(201).json({ + success: true, + data: listing, + message: "Listing created successfully", + }); + } catch (error) { + console.error("Error creating listing:", error); + res.status(500).json({ + success: false, + error: "Failed to create listing", + details: error.message, + }); + } +}; + +/** + * Get listings with search and filtering + * GET /valuechain/listings + */ +export const getListings = async (req, res) => { + try { + const { + productType, + lat, + lng, + radius = 50, // km + minPrice, + maxPrice, + grade, + status = "active", + sort = "-createdAt", + page = 1, + limit = 20, + } = req.query; + + const query = { status }; + + // Product type filter + if (productType) { + query.productType = productType; + } + + // Geospatial filter + if (lat && lng) { + const radiusInMeters = parseFloat(radius) * 1000; + query.location = { + $near: { + $geometry: { + type: "Point", + coordinates: [parseFloat(lng), parseFloat(lat)], + }, + $maxDistance: radiusInMeters, + }, + }; + } + + // Price range filter + if (minPrice || maxPrice) { + query.reservePrice = {}; + if (minPrice) query.reservePrice.$gte = parseFloat(minPrice); + if (maxPrice) query.reservePrice.$lte = parseFloat(maxPrice); + } + + // Grade filter + if (grade) { + query.grade = grade; + } + + const skip = (parseInt(page) - 1) * parseInt(limit); + + const [listings, total] = await Promise.all([ + Listing.find(query) + .populate("sellerId", "name email phone") + .sort(sort) + .skip(skip) + .limit(parseInt(limit)) + .lean(), + Listing.countDocuments(query), + ]); + + res.json({ + success: true, + data: listings, + pagination: { + total, + page: parseInt(page), + limit: parseInt(limit), + pages: Math.ceil(total / parseInt(limit)), + }, + }); + } catch (error) { + console.error("Error fetching listings:", error); + res.status(500).json({ + success: false, + error: "Failed to fetch listings", + details: error.message, + }); + } +}; + +/** + * Get a single listing by ID + * GET /valuechain/listings/:id + */ +export const getListingById = async (req, res) => { + try { + const { id } = req.params; + + const listing = await Listing.findById(id) + .populate("sellerId", "name email phone") + .lean(); + + if (!listing) { + return res.status(404).json({ + success: false, + error: "Listing not found", + }); + } + + // Increment view count + await Listing.findByIdAndUpdate(id, { $inc: { viewCount: 1 } }); + + res.json({ + success: true, + data: listing, + }); + } catch (error) { + console.error("Error fetching listing:", error); + res.status(500).json({ + success: false, + error: "Failed to fetch listing", + details: error.message, + }); + } +}; + +/** + * Update a listing + * PUT /valuechain/listings/:id + */ +export const updateListing = async (req, res) => { + try { + const { id } = req.params; + const updates = req.body; + + const listing = await Listing.findById(id); + + if (!listing) { + return res.status(404).json({ + success: false, + error: "Listing not found", + }); + } + + // Check ownership + if (listing.sellerId.toString() !== req.user._id.toString()) { + return res.status(403).json({ + success: false, + error: "Not authorized to update this listing", + }); + } + + // Prevent updating certain fields + delete updates.sellerId; + delete updates.offerCount; + delete updates.viewCount; + + const updatedListing = await Listing.findByIdAndUpdate( + id, + { $set: updates }, + { new: true, runValidators: true } + ); + + res.json({ + success: true, + data: updatedListing, + message: "Listing updated successfully", + }); + } catch (error) { + console.error("Error updating listing:", error); + res.status(500).json({ + success: false, + error: "Failed to update listing", + details: error.message, + }); + } +}; + +/** + * Create an offer on a listing + * POST /valuechain/offer + */ +export const createOffer = async (req, res) => { + try { + const { + listingId, + offeredPrice, + quantityKg, + message, + deliveryTerms, + paymentTerms, + expiresInHours = 48, + } = req.body; + + // Validate required fields + if (!listingId || !offeredPrice || !quantityKg) { + return res.status(400).json({ + success: false, + error: "Missing required fields: listingId, offeredPrice, quantityKg", + }); + } + + // Get the listing + const listing = await Listing.findById(listingId); + if (!listing) { + return res.status(404).json({ + success: false, + error: "Listing not found", + }); + } + + if (listing.status !== "active") { + return res.status(400).json({ + success: false, + error: "Listing is not available for offers", + }); + } + + if (quantityKg > listing.availableQuantityKg) { + return res.status(400).json({ + success: false, + error: `Requested quantity exceeds available quantity (${listing.availableQuantityKg} kg)`, + }); + } + + // Can't make offer on own listing + if (listing.sellerId.toString() === req.user._id.toString()) { + return res.status(400).json({ + success: false, + error: "Cannot make offer on your own listing", + }); + } + + const expiresAt = new Date(Date.now() + expiresInHours * 60 * 60 * 1000); + + const offer = new Offer({ + listingId, + buyerId: req.user._id, + sellerId: listing.sellerId, + offeredPrice, + priceUnit: listing.priceUnit, + quantityKg, + message, + deliveryTerms, + paymentTerms: paymentTerms || { method: "escrow" }, + expiresAt, + }); + + await offer.save(); + + // Update listing offer count + await Listing.findByIdAndUpdate(listingId, { $inc: { offerCount: 1 } }); + + // Emit socket event + const io = req.app.get("socketio"); + if (io && typeof io.to === 'function') { + io.to("valuechain").emit("new_offer", { + offerId: offer._id, + listingId, + sellerId: listing.sellerId, + }); + } + + res.status(201).json({ + success: true, + data: offer, + message: "Offer submitted successfully", + }); + } catch (error) { + console.error("Error creating offer:", error); + res.status(500).json({ + success: false, + error: "Failed to create offer", + details: error.message, + }); + } +}; + +/** + * Get offers for a user (as buyer or seller) + * GET /valuechain/offers + */ +export const getOffers = async (req, res) => { + try { + const { role = "buyer", status, page = 1, limit = 20 } = req.query; + + const query = {}; + + if (role === "buyer") { + query.buyerId = req.user._id; + } else { + query.sellerId = req.user._id; + } + + if (status) { + query.status = status; + } + + const skip = (parseInt(page) - 1) * parseInt(limit); + + const [offers, total] = await Promise.all([ + Offer.find(query) + .populate("listingId", "productType productName reservePrice photos") + .populate("buyerId", "name email") + .populate("sellerId", "name email") + .sort("-createdAt") + .skip(skip) + .limit(parseInt(limit)) + .lean(), + Offer.countDocuments(query), + ]); + + res.json({ + success: true, + data: offers, + pagination: { + total, + page: parseInt(page), + limit: parseInt(limit), + pages: Math.ceil(total / parseInt(limit)), + }, + }); + } catch (error) { + console.error("Error fetching offers:", error); + res.status(500).json({ + success: false, + error: "Failed to fetch offers", + details: error.message, + }); + } +}; + +/** + * Respond to an offer (accept/reject/counter) + * PUT /valuechain/offer/:id/respond + */ +export const respondToOffer = async (req, res) => { + try { + const { id } = req.params; + const { action, counterPrice, counterMessage } = req.body; + + const offer = await Offer.findById(id); + if (!offer) { + return res.status(404).json({ + success: false, + error: "Offer not found", + }); + } + + // Check if user is the seller + if (offer.sellerId.toString() !== req.user._id.toString()) { + return res.status(403).json({ + success: false, + error: "Not authorized to respond to this offer", + }); + } + + if (offer.status !== "pending") { + return res.status(400).json({ + success: false, + error: "Can only respond to pending offers", + }); + } + + switch (action) { + case "accept": + offer.status = "accepted"; + offer.acceptedAt = new Date(); + + // Update listing available quantity + await Listing.findByIdAndUpdate(offer.listingId, { + $inc: { availableQuantityKg: -offer.quantityKg }, + }); + break; + + case "reject": + offer.status = "rejected"; + break; + + case "counter": + if (!counterPrice) { + return res.status(400).json({ + success: false, + error: "Counter price is required for counter offers", + }); + } + offer.status = "countered"; + offer.counterOffer = { + price: counterPrice, + message: counterMessage, + createdAt: new Date(), + }; + break; + + default: + return res.status(400).json({ + success: false, + error: "Invalid action. Use: accept, reject, or counter", + }); + } + + await offer.save(); + + // Emit socket event + const io = req.app.get("socketio"); + if (io && typeof io.to === 'function') { + io.to("valuechain").emit("offer_response", { + offerId: offer._id, + buyerId: offer.buyerId, + action, + }); + } + + res.json({ + success: true, + data: offer, + message: `Offer ${action}ed successfully`, + }); + } catch (error) { + console.error("Error responding to offer:", error); + res.status(500).json({ + success: false, + error: "Failed to respond to offer", + details: error.message, + }); + } +}; + +/** + * Create a transform request (processor buying raw materials) + * POST /valuechain/transformRequest + */ +export const createTransformRequest = async (req, res) => { + try { + const { + listingId, + sellerId, + requestType, + rawMaterial, + expectedOutput, + processingFee, + timeline, + terms, + } = req.body; + + // Find processor profile for current user + const processor = await Processor.findOne({ userId: req.user._id }); + if (!processor) { + return res.status(400).json({ + success: false, + error: "Processor profile not found. Please create a processor profile first.", + }); + } + + if (!rawMaterial || !rawMaterial.productType || !rawMaterial.quantityKg) { + return res.status(400).json({ + success: false, + error: "Raw material details are required", + }); + } + + const transformRequest = new TransformRequest({ + processorId: processor._id, + listingId, + sellerId, + requestType: requestType || "spot_purchase", + rawMaterial, + expectedOutput: expectedOutput || [], + processingFee, + timeline, + terms, + }); + + await transformRequest.save(); + + res.status(201).json({ + success: true, + data: transformRequest, + message: "Transform request created successfully", + }); + } catch (error) { + console.error("Error creating transform request:", error); + res.status(500).json({ + success: false, + error: "Failed to create transform request", + details: error.message, + }); + } +}; + +/** + * Get market summary with aggregated supply-demand data + * GET /valuechain/market-summary + */ +export const getMarketSummary = async (req, res) => { + try { + const { productType, state, days = 30 } = req.query; + + const dateFilter = new Date(); + dateFilter.setDate(dateFilter.getDate() - parseInt(days)); + + // Aggregate supply data + const supplyPipeline = [ + { + $match: { + status: "active", + createdAt: { $gte: dateFilter }, + ...(productType && { productType }), + ...(state && { "location.state": state }), + }, + }, + { + $group: { + _id: { + productType: "$productType", + state: "$location.state", + }, + totalQuantity: { $sum: "$availableQuantityKg" }, + averagePrice: { $avg: "$reservePrice" }, + listingCount: { $sum: 1 }, + minPrice: { $min: "$reservePrice" }, + maxPrice: { $max: "$reservePrice" }, + }, + }, + { + $sort: { totalQuantity: -1 }, + }, + ]; + + // Aggregate demand data (from offers) + const demandPipeline = [ + { + $match: { + status: { $in: ["pending", "accepted"] }, + createdAt: { $gte: dateFilter }, + }, + }, + { + $lookup: { + from: "listings", + localField: "listingId", + foreignField: "_id", + as: "listing", + }, + }, + { $unwind: "$listing" }, + { + $match: { + ...(productType && { "listing.productType": productType }), + ...(state && { "listing.location.state": state }), + }, + }, + { + $group: { + _id: { + productType: "$listing.productType", + state: "$listing.location.state", + }, + totalDemand: { $sum: "$quantityKg" }, + averageOfferPrice: { $avg: "$offeredPrice" }, + offerCount: { $sum: 1 }, + }, + }, + ]; + + // Get price trends + const priceTrendPipeline = [ + { + $match: { + date: { $gte: dateFilter }, + ...(productType && { commodity: productType }), + }, + }, + { + $group: { + _id: { + date: { $dateToString: { format: "%Y-%m-%d", date: "$date" } }, + commodity: "$commodity", + }, + averagePrice: { $avg: "$prices.modal" }, + volume: { $sum: "$volume.arrivals" }, + }, + }, + { + $sort: { "_id.date": 1 }, + }, + ]; + + const [supplyData, demandData, priceTrends] = await Promise.all([ + Listing.aggregate(supplyPipeline), + Offer.aggregate(demandPipeline), + PriceHistory.aggregate(priceTrendPipeline), + ]); + + // Calculate heatmap data (state-wise supply-demand ratio) + const heatmapData = {}; + supplyData.forEach((item) => { + const key = `${item._id.state}_${item._id.productType}`; + if (!heatmapData[key]) { + heatmapData[key] = { + state: item._id.state, + productType: item._id.productType, + supply: 0, + demand: 0, + }; + } + heatmapData[key].supply = item.totalQuantity; + heatmapData[key].averagePrice = item.averagePrice; + }); + + demandData.forEach((item) => { + const key = `${item._id.state}_${item._id.productType}`; + if (heatmapData[key]) { + heatmapData[key].demand = item.totalDemand; + } + }); + + // Calculate price indices + const priceIndices = supplyData.reduce((acc, item) => { + if (!acc[item._id.productType]) { + acc[item._id.productType] = { + average: 0, + min: Infinity, + max: 0, + count: 0, + }; + } + acc[item._id.productType].average += item.averagePrice; + acc[item._id.productType].min = Math.min(acc[item._id.productType].min, item.minPrice); + acc[item._id.productType].max = Math.max(acc[item._id.productType].max, item.maxPrice); + acc[item._id.productType].count += 1; + return acc; + }, {}); + + Object.keys(priceIndices).forEach((key) => { + priceIndices[key].average = priceIndices[key].average / priceIndices[key].count; + }); + + res.json({ + success: true, + data: { + supply: supplyData, + demand: demandData, + heatmap: Object.values(heatmapData), + priceTrends, + priceIndices, + generatedAt: new Date(), + periodDays: parseInt(days), + }, + }); + } catch (error) { + console.error("Error fetching market summary:", error); + res.status(500).json({ + success: false, + error: "Failed to fetch market summary", + details: error.message, + }); + } +}; + +export default { + createListing, + getListings, + getListingById, + updateListing, + createOffer, + getOffers, + respondToOffer, + createTransformRequest, + getMarketSummary, +}; diff --git a/backend/controllers/videoCallController.js b/backend/controllers/videoCallController.js new file mode 100644 index 0000000000000000000000000000000000000000..b498688cf5c4bfac0f9ea439b55398a2ca197e4f --- /dev/null +++ b/backend/controllers/videoCallController.js @@ -0,0 +1,10 @@ +// controllers/videoCallController.js +export const startCall = (req, res) => { + const { appointmentId } = req.body; + res.status(200).json({ message: `Call started for appointment ${appointmentId}` }); +}; + +export const joinCall = (req, res) => { + const { appointmentId } = req.body; + res.status(200).json({ message: `Farmer joined call for appointment ${appointmentId}` }); +}; diff --git a/backend/controllers/waterOptimizationController.js b/backend/controllers/waterOptimizationController.js new file mode 100644 index 0000000000000000000000000000000000000000..9dd82ccdb69b8c57a6da06614665e1f4f97f8cdf --- /dev/null +++ b/backend/controllers/waterOptimizationController.js @@ -0,0 +1,46 @@ +import { generateAIContent } from '../utils/aiHelper.js'; +import { extractLanguage, getLanguageName } from '../utils/aiOrchestrator.js'; +import dotenv from 'dotenv'; + +export const getWaterOptimizations = async (req, res) => { + dotenv.config(); + + const { weather, soilMoisture, cropStage, evaporationRate } = req.body; + + const lang = extractLanguage(req); + const langName = getLanguageName(lang); + const langInstruction = lang !== 'en' ? `\n\nRespond STRICTLY in ${langName} language. Translate all fields and values.` : ''; + + try { + const prompt = ` + You are an expert irrigation scientist. + + Based on the following details: + - Weather: ${weather} + - Soil Moisture (%): ${soilMoisture} + - Crop Stage: ${cropStage} + - Evaporation Rate (mm/day): ${evaporationRate} + + Calculate: + + 1. Recommended water requirement per day (in liters per plant OR mm per acre β€” choose best based on input). + 2. Expected water savings (%) compared to traditional irrigation. + 3. A short explanation (1–2 lines). + + Respond ONLY in this JSON structure: + + { + "water_required": "value + units", + "water_saving_percent": number, + "note": "short explanation" + }${langInstruction} + `; + + const recommendation = await generateAIContent(prompt.trim()); + const formattedRecommendation = recommendation.replace("```json", "").replace("```", "").trim(); + res.status(200).json({ recommendation:formattedRecommendation }); + } catch (err) { + console.error("Error fetching recommendations: ", err); + res.status(500).json({ error: "Failed to fetch recommendations" }); + } +}; diff --git a/backend/data/agricultural_knowledge_base.json b/backend/data/agricultural_knowledge_base.json new file mode 100644 index 0000000000000000000000000000000000000000..6309256c45fda66e0bdd1ac244b957733c95bff4 --- /dev/null +++ b/backend/data/agricultural_knowledge_base.json @@ -0,0 +1,12861 @@ +[ + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image812", + "fact_text": "What impact will humidity have on these leaves -> In high humidity conditions, damaged leaves and flower stems may have sparse white mold layers.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4703", + "fact_text": "Under what circumstances will it cause this pest infestation -> Usually, overwintering adults appear in early May of spring when the temperature is above 15 ℃. Then migrate to the field to lay eggs in late May or mid June. Generally, in severe years, it often leads to a shortage of seedlings, broken ridges, and even seed destruction.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4051", + "fact_text": "What measures can be taken to prevent this situation -> Prevention can be achieved by selecting tomato varieties that are resistant to low temperatures and have relatively small variations in the number of central chambers, such as L-402 or Bailey. At the same time, ensure that the night temperature during the seedling cultivation period is not lower than 12 ℃, and manage water and fertilizer reasonably, especially to avoid excessive use of nitrogen fertilizer.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4793", + "fact_text": "How should I prevent and control this pest -> There are various methods for controlling the American leaf miner. Firstly, strict quarantine is required to prevent the spread of pests. Secondly, the planting layout of vegetables can be adjusted to avoid co planting with melons, eggplants, and legumes that are favored by the leafminer as much as possible. Clean the fields in a timely manner after harvest, concentrate and bury the residues of crops damaged by the leaf miner, compost or burn them. In addition, some traps can be used to lure and kill adult insects, and some pesticides can also be scientifically used, such as 25% Banqianjin emulsifiable concentrate 1500 times solution, 48% Chlorpyrifos 1500 times solution, 98% Batan original powder 1500 times solution, etc. When necessary, biological control methods can also be adopted, such as releasing specific parasitic wasps.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5061", + "fact_text": "What causes this anomaly -> This condition is caused by a fungus called fruit rot mold. This fungal mycelium grows lush and appears as white cotton fluff. Even in areas with high annual average temperatures, this fungus appears more frequently.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image5265", + "fact_text": "What are the living habits of this pest -> 5-6 generations are born annually in the Yangtze River Basin, and 4 generations are born annually in the Yellow River Basin. They winter in the form of eggs in alfalfa and weed stems or cotton leaf stalks. In April of the following year, newly hatched nymphs moved on alfalfa, sweet potatoes, and other weeds. The gradually maturing generation of adults began to appear in early May.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "grape rhizopus stolnifer 5", + "fact_text": "What disease is causing this symptom in the picture -> Rhizopus stolnifer", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4766", + "fact_text": "So, what are the main hosts of this pest in the image -> This type of pest has a wide range of hosts and can inhabit gramineae plants such as wheat, barley, corn, sorghum, English white, rice, sugarcane, barnyard grass, and so on.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2866", + "fact_text": "Can this situation be prevented -> Measures can be taken to prevent this situation. For example, when raising seedlings in winter, it is necessary to maintain a temperature above 20 ℃ during the day and above 10 ℃ at night. At the same time, control the amount of nitrogen fertilizer and watering, as well as avoid growth regulators mistakenly spraying on plant growth points. Choosing varieties that are less susceptible to disease is also crucial.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5380", + "fact_text": "What methods should I take to prevent and control this pest -> Firstly, some pests can be eliminated through agricultural management, such as plowing and weeding. Secondly, removing egg masses and killing young larvae are also very effective prevention and control measures. In addition, suitable pesticides can be used for prevention and control. Biological control methods, such as spraying Bacillus subtilis or Bacillus subtilis powder containing over 10 billion spores per gram, are also very effective. Prevention and early identification are equally important. Taking measures before serious damage occurs can reduce the difficulty of prevention and economic losses.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4265", + "fact_text": "How can we prevent and treat this disease -> For this disease, it is recommended to choose high-quality varieties with strong disease resistance in the affected areas. In terms of fertilizer and water management, it is also necessary to strengthen timely drainage and sun drying of the field to avoid the occurrence of diseases in excessively humid environments. In addition, it is necessary to promptly deal with diseased grass to prevent further spread and spread of the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image338", + "fact_text": "What is the mechanism behind the formation of these phenomena -> This type of phenomenon is usually related to the temperature, light, and nutrient management of the planting environment. Low night temperature and insufficient light, especially during the flower bud differentiation stage, as well as extreme high temperatures, are all contributing factors.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1611", + "fact_text": "What are the typical manifestations of this disease -> The typical manifestation is soft rot in the form of water stains at the base of the stem. As time progresses, the stem of the plant will undergo constriction and induced folding.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4758", + "fact_text": "What is the prevention and control method for this insect -> You can try using 16% SF 3 emulsion at 2000-3000 times or 2.5% Zhongbao 4 emulsion at 1000 times for spraying, and this method often yields good results.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3104", + "fact_text": "How can we prevent or improve this situation -> Several measures can be taken to prevent and improve boron deficiency: first, it is necessary to apply boron containing fertilizers reasonably and increase the application of decomposed organic manure, which can provide necessary boron and increase the soil's water retention capacity. In addition, the pH value of the soil should be adjusted and appropriate irrigation should be maintained to avoid soil being too wet or too dry, in order to ensure that plants can absorb boron normally.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4780", + "fact_text": "What type of damage does this pest cause in the pictureics -> The larvae of this pest will feed on the tender leaves of crops, but will not penetrate deep into the interior of the undeveloped tender leaves, forming a network of small holes or causing perforation or withering of the leaves, which can be seen from the images. This may affect the growth and development of crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4681", + "fact_text": "So what impact will this pest have on rice -> The larvae of this pest infest the rice roots in the soil, which may cause the rice plants to turn yellow and in severe cases, the entire plant may wither. In addition, adult insects feed on the heart leaves of rice seedlings near the water surface, and after the affected leaves grow, a row of horizontal small holes will also appear. If exposed to wind, the leaves are prone to breaking and floating on the water surface.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1", + "fact_text": "What pathogen is causing this disease -> Gray grape spore.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2325", + "fact_text": "Has this change led to other visible signs -> Yes, it leads to subsidence and the overflow of sticky bacterial pus, which are signs of further infection development.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3140", + "fact_text": "Is the cabbage size in the image normal -> The cabbage in the image shows dwarfing, with the plant being shorter than the normal plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4725", + "fact_text": "Do the pests in the image have any special appearance features -> In the image, the adult body length of the pest is 14-18mm, with a wingspan of 30-38mm and a grayish brown color. The front wings have brown circular stripes and kidney shaped stripes. In addition, its hind wings are yellow white or light brown, with brown or black tips.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "vitis erythroneura apicalis 40", + "fact_text": "What is the name of the insect in the picture -> Grape Two Star Leaf Cicada", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4978", + "fact_text": "How should we prevent and treat this disease -> The methods for preventing and treating this disease include: breeding resistant varieties, implementing rotation for more than 3 years on the harvested plots after deep plowing to prevent the accumulation of pathogens, sowing at an appropriate time, avoiding the high incidence period of diseases too early, strengthening field management, and increasing the application of organic fertilizer to improve crop disease resistance. If necessary, 75% chlorothalonil wettable powder 600-fold solution or other related pesticides can also be sprayed.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5289", + "fact_text": "At which stage of the year do they cause the most severe damage -> In the northern regions of our country, this pest occurs twice a year. The second-generation larvae are particularly prone to consuming a large amount of beans and fruits, causing severe damage. This usually occurs around September each year and is considered a serious invasion period.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "wheat cerodonta denticornis 138", + "fact_text": "What is the color of the insect in the picture Answer: Black brown", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5421", + "fact_text": "Does this pest seem to exist year-round or seasonal -> This pest has obvious seasonality. In the peanut region of North China, it has 4 generations per year, in the Yangtze River basin it has 5-6 generations, and in South China it can reach 6-7 generations.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "pepper blossom end rot 321", + "fact_text": "What kind of disease has affected the chili peppers in the picture -> Chili navel rot disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4666", + "fact_text": "What crops can this pest attack -> This type of pest mainly harms crops such as rice, Coix, corn, English white, wheat, sorghum, alfalfa, Oxytropis, and aquatic vegetables in the Poaceae family.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image612", + "fact_text": "What effective preventive measures are there for this disease -> Effective measures include maintaining appropriate temperature and humidity inside the greenhouse, avoiding excessive humidity, avoiding high humidity in the greenhouse during the initial planting stage, and timely applying sufficient base fertilizer and topdressing.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image1699", + "fact_text": "Is there any abnormality on the stem and petiole in the image -> The lesions on the stem and petiole appear as vertical stripes, with dark brown strip like indentations. This is also a symptom of infection caused by the same type of fungus.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5276", + "fact_text": "What are the main impacts of pest infestation on marijuana -> The main impact of pests is to cause significant damage to the stem positions of plants, affecting the normal growth of cannabis and thus affecting production.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4760", + "fact_text": "What is the approximate length of their bodies -> The body length of the creature in the image is approximately 2 to 2.5 millimeters.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "management instructions", + "entity": "image4984", + "fact_text": "How to effectively prevent and control this disease -> The prevention and control methods include selecting disease resistant varieties, such as Yueyou 22, Yueyou 551, etc; Adjust the sowing time and plant densely in a reasonable manner; Timely cultivate and weed, make good drainage ditches, and reduce field humidity; And use 95% sodium dichromate wettable powder 600 times solution or 75% chlorothalonil wettable powder 500 times solution and other chemicals for prevention and control. In addition, adding 0.2% adhesive during spraying has a synergistic effect.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4825", + "fact_text": "What color is the surface of the insect in the image -> The insect body surface in the image is mainly black or black brown, and has luster.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4331", + "fact_text": "How did this disease spread and what are the conditions that help it spread -> The pathogen of this wheat disease mainly overwinter or overwinter on the host's diseased residue through conidia and hyphae, and can also attach to seeds for transmission. Seeds or seedlings with fungi can be infected if their roots and stems at the neck or base come into contact with the contaminated soil. In the field with a temperature of around 25 ℃, high humidity, and water film, it is beneficial for bacterial infection and spore formation. Continuous cropping areas with abundant weeds, insufficient fertilizers, and alkaline soil are conducive to disease. There are significant differences in disease resistance among wheat varieties.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4640", + "fact_text": "What are the differences in the life cycles of this species between Heilongjiang and Jiangsu -> This species can have 2-3 generations per year in Heilongjiang and Ningxia, and 4-5 generations in Jiangsu. In Jiangsu, the overwintering generation of adult moths thrives from early May to early June. The first generation is from late June to late July, the second generation is from late July to early August, the third generation is from late August to late September, and the fourth generation is from late September to mid October. In Ningxia, the peak moth season is from early June to late July and from late August to early September.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image4885", + "fact_text": "What is the inflorescence of the weed in the picture like -> The inflorescence is conical in shape and tends to be golden or slightly brownish in color, appearing very compact.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image807", + "fact_text": "What are the characteristics exhibited by leaves when the environmental humidity is high -> Under high humidity conditions, gray to green fuzzy mold layers will grow at the affected area, covering the diseased leaves with a musty odor.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3729", + "fact_text": "What is the impact of humid environments on such issues -> A humid environment can exacerbate the condition, as shown in the image. Under high humidity conditions, a layer of pink mold will form on the surface of the diseased stem, which is a sign of the worsening of the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image107", + "fact_text": "What is the impact of viral infection on the overall growth of watermelon -> Virus infection usually leads to slow growth and overall poor growth of watermelons, and in severe cases, it can even cause the plants to no longer grow, as shown in the figure. The overall condition of the plants is poor.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4441", + "fact_text": "What is the cause of this disease -> This is caused by a virus called Maizestreakdwarfvirus, abbreviated as MsDv. This virus is bullet shaped, with a size of 200-250 x 70-80 (nm), and each particle of the virus has 50 horizontal stripes with a spacing of 4nm.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4986", + "fact_text": "What is the process of plaque formation -> The formation of lesions begins with a small, regular circular spot, which gradually expands and fuses as the condition progresses. In addition, under suitable humidity and temperature conditions, the spores of pathogens fall on the leaves, germinate and produce shoot tubes, which directly penetrate the plant epidermis and enter the internal tissues, causing the appearance of disease spots.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4642", + "fact_text": "What is the spread and lifecycle of this pest -> The life course of this pest will vary depending on its geopictureical location. Two generations are born in the north of the Great Wall, three generations in the south of the Great Wall and the north of the Yellow River, four to five generations in the south of the Yellow River and the north of the Yangtze River, five to six generations in the south of the Yangtze River and six to eight generations in the south of the Nanling Mountain. Generally, in the south, small and medium-sized larvae overwinter by budding on leeward fields, ditches, water chestnuts, bamboo groves, and other Poaceae plants. They can feed at temperatures above 12 ℃ and emerge during the day and night, and emerge in the morning.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4795", + "fact_text": "How to prevent this kind of pest infestation -> There are several methods to prevent the occurrence of this pest: first, timely removal of fallen flowers and plants in the field, and removal of damaged rolled leaves and bean curd to reduce the source of pests; The second is to install black light lamps in bean fields to lure and kill adult insects; The third method is to use chemical prevention and control measures, such as using a 6000 fold solution of killing (21% synergistic cyanide Β· horse emulsion), a 3000 fold solution of 40% fenvalerate, or a 5% deltamethrin fold solution. Starting from the emergence of buds, spray and flower every 10 days to control the occurrence of pests.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4373", + "fact_text": "At what stage did the crops in this image develop -> The crops in the image are in the jointing stage, and some are already able to jointing, but the heading situation is not ideal.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1047", + "fact_text": "In the image, what changes will the development of these spots cause in the leaves -> The development of these spots may cause the leaves to gradually lose vitality and eventually wither.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4407", + "fact_text": "What are the solutions to these problems that affect barley yield -> There are some preventive measures. To prevent nitrogen deficiency, we can use compost or organic fertilizer made by fermenting bacteria, apply 10-15kg of ammonium bicarbonate during the seedling stage, apply hole or water carried fertilizer, apply 3-8kg of urea in the middle stage, and spray 25 urea solution in the later stage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "vitis pseudococcus comstocki kuwana 43", + "fact_text": "What is the scientific name of the insect in the picture -> Pseudofocus comstocki Kuwait", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3020", + "fact_text": "Where does this type of leaf often begin to rot -> Usually it starts from the edge of the leaf and then spreads inward.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image1904", + "fact_text": "Is there any abnormality in the plant leaves displayed in the image -> Yes, some leaf edges in the image show wilting and browning, which may be due to insufficient water and nutrient supply caused by diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1626", + "fact_text": "What is the white thing on the leaves in the image -> The surface of the leaf shown in the image has dense white flocculent mycelium clusters.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1027", + "fact_text": "What are the abnormalities in the stem in the image -> There are also obvious amorphous black lesions on the stem and fruit stalk in the picture.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5406", + "fact_text": "How to prevent and control this insect pest -> When necessary, spray 1000 times 50% acephate emulsion or 400 times 25% insecticidal water repellent, 2000-2500 times 2.5% deltamethrin emulsion, 1000 times 10% Doraemon suspension, or 1000-1500 times 10% imidacloprid wettable powder.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5055", + "fact_text": "Are there any effective prevention and control measures -> Prevention and control measures include selecting seeds, deep plowing to inhibit the germination of dodder seeds, removing dodder vines, appropriate hoeing timing, implementing rotation or intercropping, and high-temperature fermentation treatment of manure. In addition, biological control can also be used, such as spraying Lubao 1 biological agent.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2951", + "fact_text": "How are these root cracks formed -> Mainly due to uneven water supply. If the soil is too dry in the initial stage and suddenly receives sufficient water supply in the later stage, it will cause the internal cells of the roots to rapidly expand while the cortex cannot grow synchronously, leading to cracking.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4376", + "fact_text": "Can you tell me what caused this disease -> This disease is caused by a parasitic nematode called wheat grain nematode. The male and female adults of this nematode have less active linear shapes and lay eggs in green galls.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4939", + "fact_text": "Will this situation have any impact on the fruit development of cotton -> Yes, nutrient deficiency can cause fruit branches to not extend and buds to fall off more, affecting the normal development of the fruit. In severe cases, it may lead to low yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4951", + "fact_text": "What measures should I take to prevent and control this disease -> The main methods to prevent this disease include: selecting high-yield varieties with disease resistance; Disinfect the seeds; Reasonable fertilization, do not overapply nitrogen fertilizer; Timely ditch drainage to prevent moisture retention in the field. Medication can also be used in a timely manner for prevention and treatment.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4694", + "fact_text": "What is this crop in the image -> The crop in the image is barley.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "grape powdery mildew 21", + "fact_text": "What disease is causing the symptoms of the fruit in the picture -> Grape powder mildew", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3906", + "fact_text": "What is the reason why the mushroom in the image looks abnormal in shape -> The abnormal growth of mushrooms may be caused by various environmental factors, such as discomfort in soil cover, inappropriate control of temperature and humidity, etc.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image1517", + "fact_text": "What specific measures should we take to avoid the spread of diseases -> To avoid the spread of diseases, reasonable rotation should be carried out to avoid continuous cropping; Timely removal and treatment of diseased residues, increased application of organic matter and necessary phosphorus and potassium fertilizers to enhance plant resistance; And before and after the occurrence of the disease, use designated pesticides for prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "pepper blossom end rot 332", + "fact_text": "What color is the affected area of the chili pepper in the picture Answer: Brown", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5245", + "fact_text": "How can we prevent and control this pest -> Heavy cotton areas require timely prevention and control. During the peak hatching period or the 1st and 2nd instar larval stage, 80% crystal trichlorfon 800 fold solution, 50% Aikashi emulsion 1500 fold solution, 50% parathion emulsion 2000 fold solution, and 50% phoxim emulsion 1500 fold solution can be sprayed. When controlling other cotton pests, this pest can also be treated simultaneously.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1137", + "fact_text": "How will this disease affect the overall yield of eggplants -> In severely affected areas, cotton blight can cause a large amount of eggplant fruit to rot, making it almost impossible to pick healthy eggplants, which significantly affects the overall yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4427", + "fact_text": "So, how should we prevent and treat this disease -> Regarding prevention and control methods, it may include selecting disease resistant varieties, adapting to local climate, constantly replacing new varieties, and expanding the planting area of disease resistant varieties. In addition, crop rotation can also be adopted to further strengthen field management, especially by increasing the application of potassium fertilizer or a combination of nitrogen, phosphorus, and potassium fertilizer during crop jointing or booting stages, to enhance disease resistance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4723", + "fact_text": "How many generations of this pest are there in a year -> This type of pest usually grows 2 to 3 generations a year north of the Yangtze River, while it can grow 4 to 5 generations in the south, and even 5 to 6 generations in Hainan region.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "mango dasineura sp 11", + "fact_text": "What signs of pest damage do the leaves in the picture show Answer: Dasineura sp", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4530", + "fact_text": "How can we prevent or treat this disease -> To prevent this disease, we can choose disease-free pods, separate threshing and seed retention, and soak the seeds in warm water at 56 Β° C for 5 minutes before sowing for seed disinfection. Reasonable sowing time and fertilization strategies, including increasing potassium fertilizer application appropriately, can improve crop disease resistance. In the early stages of the disease, we can spray specific pesticides every 10 days.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3245", + "fact_text": "Are there any special phenomena at the bottom of the plants in the image -> The bottom of the plant in the image may show waterlogged decay, which usually leads to the plant being unable to support its own weight and ultimately collapsing to the ground.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4766", + "fact_text": "What are the prevention and control methods for it -> The prevention and control of this pest can be achieved by using a pesticide seed mixing method, such as using 150ml of 75% 3911 emulsion, 3kg of water, 50kg of wheat seeds, mixing well, and then burying for 12 hours for sowing. In addition, during the period of pest infestation, pesticides should be sprayed from around the wheat field to prevent pest escape. The commonly used pesticides include 50% malathion emulsion at a ratio of 2000 times, 50% parathion emulsion at a ratio of 2500 times, 40% dimethoate emulsion at a ratio of 1000 times, etc.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5664", + "fact_text": "How to effectively prevent and control this root problem -> Effective prevention and control methods include deep soil plowing before planting, covering the greenhouse with plastic film for high-temperature disinfection after irrigation, using liquid ammonia to treat the soil, and adopting a 2-3 year crop rotation strategy. If necessary, specific chemical agents can also be used for soil treatment to reduce the number of insect eggs and larvae in the soil.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato yellow leaf curl virus 1016", + "fact_text": "Which organ is the main target of tomato yellow leaf curl virus disease Answer: Blades", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image1525", + "fact_text": "What are the suggestions for preventing and treating this condition -> It is recommended to apply timely pesticides to control the spread of aphids, and to use fully decomposed organic fertilizer and appropriate amounts of phosphorus and potassium fertilizer to enhance plant resistance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image900", + "fact_text": "What impact does this state have on plant growth -> This state can lead to a weakening of plant growth, shortening of bamboo shoots, and affecting overall plant growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2942", + "fact_text": "What are the agricultural measures shown in the image that can prevent this disease -> To prevent this disease, it is recommended to take measures such as deep cultivation of the land, removal of diseased residues in the field, avoidance of using diseased residues as soil and miscellaneous fertilizers, and implementation of reasonable crop rotation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4782", + "fact_text": "What effective preventive measures are there to deal with this pest -> One effective preventive measure is to clean the fields in a timely manner after harvesting potatoes, which can reduce the number of overwintering pests. In addition, adopting crop rotation during crop cultivation is also a good preventive measure. For potato seedlings, chemical treatment can be supplemented. For example, 1000 times of 40% dimethoate emulsifiable concentrate or 800 to 900 times of 90% crystal trichlorfon and 80% dichlorvos emulsifiable concentrate can be used for seedbed spray 1-2 days before cutting and planting. Alternatively, soak the seedlings in dimethoate solution for 1-2 minutes before cutting. In addition, spraying the above-mentioned insecticides 5-7 days after the peak of adult emergence is also helpful.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image102", + "fact_text": "What consequences may these symptoms lead to -> If not dealt with in a timely manner, these symptoms may lead to widespread damage to crops, seriously affecting their growth and yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2474", + "fact_text": "Does this process of withering happen quickly -> This process is gradually developing, starting with the green color of the leaves, then yellowing, and finally turning brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image4191", + "fact_text": "What are the transmission modes of disease development -> This type of disease is mainly transmitted through aphids, which transmit viruses from infected plants to healthy plants. Meanwhile, direct contact with viral juices can also spread the virus. There are also some non aphid borne disease strains.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image746", + "fact_text": "What is the impact on the pods of peas -> The pod of peas will also be covered with a gray mold layer on the surface after infection, and there may be signs of decay.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5698", + "fact_text": "What preventive measures are generally required in this situation -> To prevent this situation, it is recommended to choose high and dry plots during planting and drain them promptly after rain. Before planting, soil disinfectants such as lime and Bordeaux liquid, as well as an appropriate amount of fungicides, should be used.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "rice flax spot 3", + "fact_text": "What factors are causing the abnormal phenomenon in the picture Answer: Rice Flax spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "corn spot 3", + "fact_text": "What disease does the leaf in the picture suffer from Answer: Corn spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "rice hispa 71", + "fact_text": "What is the reason for the white parallel stripes on the plant leaves in the picture Answer: Insect bites", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5736", + "fact_text": "Is there any other abnormal phenomenon with the plants in the image -> From the image, it can be observed that in addition to the leaves, the leaf sheaths and caryopsis also exhibit similar symptoms, which may affect the growth of the entire plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4647", + "fact_text": "Is there a way to prevent the reproduction of this insect -> In the image, we can select insect resistant varieties with hard stems and moderate leaves for crops. When the egg laying rate of wheat reaches about 10%, with an average egg laying rate of more than 10, we can also use specific pesticides for spraying.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato verticulium wilt 89", + "fact_text": "What kind of disease has invaded the leaves in the picture -> Tomato verticillium belt", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3158", + "fact_text": "Is the disease spot on the crop leaves in the image spreading throughout the entire leaf surface -> Yes, the image shows that the lesions are interconnected on the leaves, covering a large area and severely affecting the entire leaf surface.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4052", + "fact_text": "Do the leaves in the image show any unusual signs -> The tomato leaves in the image appear normal without any special anomalies.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4489", + "fact_text": "Under what environmental conditions will this disease worsen -> In the late stage of reproduction or under rainy and humid weather conditions, the diseased area produces brown fungal nuclei. In addition, the hyphae of this disease can germinate and produce hyphae after 10-12 days at temperatures of 26-32 ℃ and relative humidity above 95%. Therefore, under such environmental conditions, the disease will worsen.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5266", + "fact_text": "So, what kind of prevention and control measures are more effective for this situation -> For this type of pest, we can refer to the methods for controlling the green blind bug for prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4827", + "fact_text": "What methods should be paid attention to when controlling such pests -> During prevention and control, attention should be paid to timely collecting and destroying adult insects on the surface, reducing breeding opportunities, and considering the use of biological or chemical control methods during the larval stage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5433", + "fact_text": "What impact does the leaf damage shown in the picture have on crops -> This degree of leaf damage can lead to weakened tree vigor, significantly reducing leaf yield on the tree, which is detrimental to the growth and nutrient supply of the entire tree.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato yellow leaf curl virus 1386", + "fact_text": "Will tomato yellow leaf curl virus disease cause slow or stagnant plant growth Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5340", + "fact_text": "Are there any recommended pesticides that have good anti pest effects -> For this pest, Bacillus thuringiensis preparation can be used, and low volume spray should be selected as far as possible; Or mix some chemical pesticides, such as marathon, fenpropathrin, deltamethrin, cypermethrin, etc.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "vitis erythroneura apicalis 30", + "fact_text": "What are the insects in the picture on Answer: Blades", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1613", + "fact_text": "The image shows that the symptoms seem severe, what may be causing this -> These symptoms are caused by specific fungi, which accumulate in diseased tissues or on diseased plants and spread through wind and rain.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image1477", + "fact_text": "What causes this disease -> This is caused by a fungus, specifically called Chrysanthemum oxysporum.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4697", + "fact_text": "What are the specific impacts of pest infestation -> Insect infestation affects the normal growth of barley. You can see small white spots on the leaves, which gradually turn yellow, leading to poor plant growth and stunted growth. In severe cases, the entire plant may even dry up.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image477", + "fact_text": "How does disease occur and spread under such environmental conditions -> This disease is prone to occur under conditions of temperature ranging from 18 to 23 degrees Celsius and relative humidity above 90%. The sustained high humidity environment is the main factor for the occurrence and spread of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5730", + "fact_text": "What are these black dots -> These black dots are a stage of the pathogen, they are enclosed shells and usually appear in the later stages.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4410", + "fact_text": "What can be done to solve this situation -> To prevent potassium deficiency, it is recommended to measure every 667m Β² Applying 5-10kg of potassium fertilizer can be done in one go or in two separate batches.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5516", + "fact_text": "Under what conditions is this phenomenon usually more pronounced -> Usually, it is more pronounced on branches of tea trees that are not growing well, and the growth of these branches may be affected, resulting in poor nutrient transport and more circular pits.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5249", + "fact_text": "What are the main aspects of the impact of this pest on plants -> The larvae of this pest will produce filamentous substances that wrap the tender leaves at the top into a tube shape, hiding in the tube to cause harm. They will bite off flower buds, fruit stems, and leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4854", + "fact_text": "What kind of vitality do they exhibit in the ecosystem -> These plants have strong vitality and reproductive ability, and once they take root, it is difficult to eradicate them.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image126", + "fact_text": "Where do these spots usually appear on the leaves -> This type of spot usually first appears at the bottom of the leaf, and may then spread upwards to the tip and edge of the leaf.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5324", + "fact_text": "Can you describe the characteristics of this pest -> Insects are small in size and belong to the family Aphidae in the order Homoptera. The habits of this pest are complex, and it can produce 24-28 generations per year. They overwinter as eggs, and the incubation time varies depending on the region. In the spring and summer seasons, this type of pest will concentrate on the back of tender leaves to suck on juice.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3337", + "fact_text": "What are the special behaviors of the plants in the image in humid environments -> Under humid environmental conditions, a small amount of white hyphae can be seen on the surface of the affected parts of the leaves in the image.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4929", + "fact_text": "What is the pathogen of this disease -> The pathogen of this disease is a fungus called AscochytagossypiiSyd.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4326", + "fact_text": "So, is there an effective way to prevent and control this disease -> Yes, one method is to plant varieties that are resistant to this disease. In addition, formula fertilization techniques can be used, with appropriate increases in phosphorus and potassium fertilizers, and reasonable dense planting. It is also possible to significantly reduce bacterial sources by promptly removing self growing wheat. In addition, chemical control can also be used, such as using triazolone to mix seeds or spraying Fuxing emulsion.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4792", + "fact_text": "Are there any specialized prevention and control measures -> Yes, in addition to timely removing dead leaves and weeds, chemical control can also be used. For example, using a 1000-2000 fold solution of 50% malathion emulsion, 20% fenvalerate emulsion, or a 6000-7000 fold solution of 2.5% deltamethrin emulsion or 20% fenpropathrin emulsion, spray every 7-10 days, continuously 2-3 times. Note that weeds outside the pea fields, such as the edges of the ground and roads, are also active areas for pest control, so prevention and control measures are also necessary.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3210", + "fact_text": "Do these lesions have any special changes when the humidity is high -> When the humidity is high, the infected area may show watery necrosis and decay.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5583", + "fact_text": "Are there any effective preventive measures that can be taken -> Effective preventive measures include using decomposed organic fertilizers, avoiding overly dense cultivation, promptly draining accumulated water in the field, and using specific chemicals for prevention and control. In addition, drip irrigation or subsurface irrigation should be used to prevent flooding.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5311", + "fact_text": "What is the overall color of sugarcane in the image -> The color near the damaged area at the base of the sugarcane in the picture may appear darker, and the overall color may appear slightly uneven due to insect infestation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5386", + "fact_text": "What pests are affecting the crops in the image -> The soybeans in the image are affected by a pest called the soybean stem borer.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3835", + "fact_text": "Is there any abnormal structure in the mushroom in the image -> Yes, some mushrooms in the image show irregular nodular protrusions, which are usually covered with mushroom caps.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "wheat green bug 12", + "fact_text": "How do the insects in the picture harm the leaves Answer: Sucking juices", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4834", + "fact_text": "What are the methods for preventing and controlling this type of insect -> To prevent and control this type of insect, one can refer to the similar prevention and control methods of Yinchuan oil gourd. Specific measures may include selecting plant varieties that are resistant to this insect, as well as using chemical or biological pesticides for spraying and control at appropriate times.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image905", + "fact_text": "If the condition progresses, what other symptoms will the leaves exhibit -> If the condition continues to develop, the center of the leaves will turn grayish white and be surrounded by reddish brown, ultimately leading to leaf drying.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "rice stemfly 246", + "fact_text": "What are the abnormal symptoms of the leaves in the image Answer: Holes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5078", + "fact_text": "What kind of influence does this image indicate on plants -> From the images, it can be observed that these plants are affected by nutrient deficiencies, specifically the lack of various nutrients such as nitrogen, phosphorus, potassium, magnesium, manganese, sulfur, boron, calcium, zinc, etc. These elements are crucial for the normal growth and development of plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image365", + "fact_text": "What could be the reason for the detachment -> Possible reasons include unsuitable environmental conditions, such as low or high temperatures, insufficient lighting, or an uneven supply of nutrients.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image5083", + "fact_text": "How to avoid and control the occurrence of this situation -> The basic prevention and control methods include the application of compost made by fermenting bacteria or decomposed organic fertilizers, and the rational application of chemical fertilizers such as nitrogen, phosphorus, and potassium needs to be combined. Early sowing and planting at appropriate times can enrich the development of crop roots and further promote the absorption of sufficient nutrients by crops. Maintain drought resistance and drainage work, and maintain the transformation and release of soil organic boron. Moderate application of phosphorus fertilizer to maintain soil acidity and alkalinity, prevent excessive application of lime, and thus prevent the determination of available boron in the soil and the imbalance of calcium and boron ratios in rapeseed. These methods can not only prevent the occurrence of pests and diseases, but also improve crop resistance and yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3044", + "fact_text": "What are the effective methods to deal with this problem -> In the early stages, pesticides can be used for prevention and control, such as the application of triazolone or methyl glyphosate in soil, or emulsified oil can be chosen for spraying.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2042", + "fact_text": "Does the impact on corn in the image also include resistance to diseases -> Yes, potassium deficient corn is more susceptible to the invasion of leaf spot and stem rot, which further worsens the health of the plants and increases the risk of disease spread.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5172", + "fact_text": "What nutrients may be missing from these symptoms -> Symptoms indicate possible deficiency of large amounts of elements such as nitrogen, phosphorus, potassium, as well as trace elements such as iron and manganese, which are crucial for plant growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4689", + "fact_text": "Is there any prevention and control method to deal with this pest -> Timely attention should be paid to prevention and control in the insect source base. For example, in the wheat seedling or jointing stage, or in the early stage of wheat flowering and filling, as long as the number of aphids per hundred plants reaches a certain control index and there is no strong wind or heavy rain in recent days, control can be carried out.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "pepper virus disease 194", + "fact_text": "What kind of disease has affected the leaves in the picture -> Chili pepper virus disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato mosaic virus 1479", + "fact_text": "Is supplementing crops with trace elements effective in reducing the occurrence of Tomato Mosaic virus Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3295", + "fact_text": "Does this disease mainly affect a specific part of the plant -> Yes, usually this disease starts at the root or stem base of the plant and may lead to wilting and necrosis of the entire upper part of the plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3782", + "fact_text": "What color is the moldy substance on the surface of bamboo shoots -> The moldy substance changes from white to pink and covers the surface of the bamboo shoot shell.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3545", + "fact_text": "Is there any abnormality in the crop petiole in the image -> At the junction of the taro petiole and bulb in the image, some white filamentous substances can be seen spreading out.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image5256", + "fact_text": "What are the harmful characteristics of this pest -> This type of pest will suck up the sap from the cotton roots near the main roots, which can cause the main and fibrous roots of cotton to become thinner or wither, and even rot. At the same time, the leaf color may also darken, the plant may appear shrunk, and the cotton stem may turn red. In severe cases, the entire cotton seedling may be damaged to death.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image851", + "fact_text": "What are these symptoms related to -> These symptoms may be related to diseases, usually caused by pathogens such as viruses spreading through aphids.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4130", + "fact_text": "What preventive measures are there for this situation -> An effective preventive measure is to apply slow-release silicon fertilizer, such as silicon fertilizer made from iron and steel slag or yellow phosphorus slag, which can be used as a base fertilizer. This helps to increase the effective silicon content in the soil, thereby improving the plant's disease tolerance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4966", + "fact_text": "What are the prevention and control methods for this disease -> The prevention and control methods mainly include: avoiding excessive application of nitrogen fertilizer, instead using formula fertilization technology, and paying attention to increasing the application of phosphorus and potassium fertilizers. In the early stages of the disease, drugs such as 1:0.5:100 times Bordeaux solution or 60% DTM wettable powder 500 times solution, 14% copper oxychloride solution 300 times solution, 60% Dofu wettable powder 800-1000 times solution, and 36% Thiamethasone suspension 500 times solution can be sprayed for prevention and treatment.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tea algal leaf 306", + "fact_text": "What diseases have affected the leaves in the picture -> Tea algae leaf spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4817", + "fact_text": "So this kind of pest can be effectively controlled, right -> Yes, by taking the above prevention and control measures, the occurrence and spread of this pest can be controlled to a certain extent, protecting the growth of cotton.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image964", + "fact_text": "Is there any abnormality in the root of sweet chili peppers in the image -> Yes, the picture shows that the root and rhizome cortex of sweet chili peppers are light brown and rotten, making them very easy to peel off.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5223", + "fact_text": "How to prevent and control this situation -> (1) Maintain good ventilation and light transmission in the tea garden, and timely drainage should be carried out after rain. (2) Pruning the aging tea tree to stimulate the growth of new branches. (3) If necessary, spray an appropriate amount of Bordeaux solution or other protective agents during spring and summer to prevent the occurrence and spread of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5239", + "fact_text": "What type of plant does the crop in the image appear to be -> The plants in the image belong to the category of cotton and hemp, specifically hemp crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5367", + "fact_text": "How do pests affect these crops -> The impact of pests on crops is mainly manifested in their ability to eat leaves. The early larvae only feed on the leaf flesh and form transparent spots on the vegetable leaves, which we call \"opening the skylight\". When pests develop to 3-4 years old, they can eat the vegetable leaves into holes and gaps, and in severe cases, the entire leaves are eaten into a network. It is worth noting that this pest often damages the central leaves during the seedling stage, affecting the pericardium.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5429", + "fact_text": "How much impact will this pest have -> Adults and nymphs of pests will engage in leaf eating behavior, which affects the growth and development of crops and reduces their commercial value.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "management instructions", + "entity": "image4949", + "fact_text": "So how should this situation in the image be prevented and controlled -> We can prevent and control this situation in the image from six aspects. One is the waterlogging method, which can irrigate soil layers 10cm or even deeper on the surface for several months. Root knot nematodes will not die, but they cannot infect. The second is to implement water drought rotation in fields with severe root knot nematode outbreaks, which has a good control effect. The third is to deeply cultivate and improve the soil, break through ridges and replace ditches, frequently cultivate and weed, timely irrigate to resist drought, and apply fertilizer reasonably. The fourth is to actively select insect resistant varieties. The fifth is to timely implement water drought rotation in fields with severe root knot nematode outbreaks, which has a good control effect. Six, if necessary, use 10% force to fill the warehouse with granules, 5kg per 667m ton, and the effect is very good.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4293", + "fact_text": "How does this disease spread and under what circumstances is it prone to developing -> Diseases are mainly transmitted by rice seeds, straw, and self growing rice, and there may also be cross infection between wild rice and Li's grass. Its bacterial pus can be re infected and spread through wind, rain, dew, etc. High temperature and humidity, as well as the impact of typhoon rainstorm, are prone to disease. In addition, partial nitrogen fertilizer application and too deep irrigation will also aggravate the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "management instructions", + "entity": "image159", + "fact_text": "What are the methods to prevent and control this situation -> To prevent and control this situation, various measures can be taken. Firstly, selecting disease resistant varieties can effectively reduce the occurrence of diseases. Secondly, strengthen field management, timely weed control, and reduce disease sources. In addition, recommended pesticides should be used for spraying before or during the early stages of the disease, while also preventing aphids that transmit the virus.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1633", + "fact_text": "Has the yield of crops been affected -> Yes, the yield of sunflower plants affected by diseases will significantly decrease, especially those that are infected with diseases earlier.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image5251", + "fact_text": "Is there an economically effective preventive method -> Effective general prevention and control measures include breeding insect resistant varieties, timely early sowing, reasonable dense planting, increasing the application of phosphorus, potassium and organic fertilizers, and promoting the healthy growth of crops. In addition, insect pesticides can be sprayed regularly or specific pesticides can be chosen for use.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image902", + "fact_text": "What specific effects do spores have on water bamboo -> The thick wall of spores fills the interior of water bamboo with gray black powder, which can seriously affect consumption.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2330", + "fact_text": "Does the disease affect the roots of shepherd's purse -> According to observation, the main impact is on the floral organs and stems, and the situation of the roots is not directly shown in the figure.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4273", + "fact_text": "How can this disease be prevented -> The prevention and control methods for this disease include selecting resistant rice varieties, waterlogging treatment to reduce bacterial sources, rational use of chemical fertilizers to avoid excessive plant growth, and the use of relevant pesticides for early disease prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2167", + "fact_text": "How severe is the tissue damage of this zucchini in the image -> The image shows that the affected area of the zucchini is severely damaged, showing a rotten state, and may be accompanied by an unpleasant odor.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "rice sogatella 30", + "fact_text": "Is the head of the insect in the picture wide Answer: No", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1262", + "fact_text": "Which parts of the plant first exhibit symptoms -> The cotyledons are the earliest parts to show yellowing symptoms, and gradually this change will expand to more leaves and stems.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4062", + "fact_text": "Is there any way to prevent the formation of such deformed fruits -> In order to prevent the formation of such deformed fruits, it is necessary to avoid low temperatures at night during seedling cultivation, increase the application of organic fertilizer in moderation, control the use of nitrogen and phosphorus fertilizers, and timely spray calcium and boron fertilizers.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2903", + "fact_text": "What can be seen in the image causing the color change of carrot roots -> This is because the bacteria invade the roots of carrots, initially producing water soaked spots that gradually spread and deepen into brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image23", + "fact_text": "Are there any effective prevention methods -> There are various methods to prevent this disease, and the first step is to cultivate disease - free and insect free seedlings, which is the key. In addition, soil disinfection of seedbeds can also be carried out, and it is best to regularly use yellow leaf curly virus or vaccines during the seedling stage for prevention. During planting, use yellow leaf curling virus spirit to irrigate the hole water, and after slowing down the seedlings, spray yellow leaf curling virus spirit continuously. Control the amount of nitrogen fertilizer appropriately and keep the field moist. At the same time, timely remove weeds and residual branches and leaves in the field to reduce the source of pests. The greenhouse air vents are isolated with insect proof nets, and yellow boards are hung in the field to prevent tobacco whiteflies.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "cucumber downy mildew 1", + "fact_text": "What diseases have affected the leaves in the picture -> Cucumber Downy Mildew", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2198", + "fact_text": "Will this situation spread from one plant to another -> Yes, diseases can spread to surrounding plants through the spores on plants driven by wind.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4828", + "fact_text": "What are the living habits of this pest -> This type of pest has a relatively long life cycle. They overwinter in the soil and start to move in early spring. They mainly mate and lay eggs at night. Adults are good at flying and have phototaxis, while larvae continuously penetrate the soil to adapt to environmental changes.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5126", + "fact_text": "Are there any special features on the surface of these affected stems -> The affected stem epidermis will lose its original luster, and as the disease expands, black small dots will grow on the surface of necrotic tissue, which are manifestations of the pathogen's conidia.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4705", + "fact_text": "Are there any effective prevention and control methods -> For the prevention and control methods of this pest, you can refer to another pest control method called the Two Star Sting. Their prevention and control methods may be similar.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "mango cicadellidae 974", + "fact_text": "What color is the body color of the insect in the picture Answer: Yellow green", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "rice stemfly 1", + "fact_text": "What is the name of the insect in the picture Answer: Rice Stamfly", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image727", + "fact_text": "What is the general development speed of this type of lesion -> Once this type of lesion occurs, it can rapidly develop within a few days, especially when conditions are suitable, and the lesion will spread rapidly.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4676", + "fact_text": "What are the visual characteristics of this pest -> This type of insect has a longer body, approximately 11 to 13.5 millimeters, black and glossy in color, and its front wings are nearly parallel on both sides when closed. The crown of the head is slightly convex, with black brown eyes and yellow red eyes. In addition, the egg is long elliptical and milky white.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tea bird eye spot 404", + "fact_text": "Will the incidence rate of tea bird eye spot increase or decrease in the environment with sufficient light and little precipitation Answer: Reduce", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4408", + "fact_text": "What is the best way to prevent this problem -> To prevent potassium deficiency, every 667m Β² Applying 5-10kg of potassium fertilizer can result in better results if applied at once or twice as base fertilizer and jointing fertilizer.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image3463", + "fact_text": "Is there an effective prevention method -> Effective prevention methods include using disease-free seed roots and treating the roots with appropriate chemical treatments, such as formalin solution or wettable powder, before sowing. In addition, timely sowing, especially in high-altitude cold areas, ensures that the soil temperature is not lower than 10 degrees Celsius, and strengthens the overall management of plants, especially by increasing potassium fertilizer to improve plant disease resistance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5369", + "fact_text": "What morphological characteristics will adults exhibit -> The body of the adult is yellow green, with two white spots on the outer center of the forewings. Moreover, there is a thick black stripe above the base of the hind wings, while the hind wings are yellow white.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "rice sogatella 32", + "fact_text": "What color is the body color of the insect in the picture Answer: Milky white", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4680", + "fact_text": "Is there anything special about the position of this creature on an object -> Indeed. This type of organism chooses to lay eggs 12-18cm away from the leaf tip, so that the newly hatched larvae can infiltrate the tissue of the leaves and feed on the leaf flesh here. This may play an important role in improving one's own living environment and increasing the success rate of reproduction.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image1459", + "fact_text": "Will low-lying areas or weed conditions exacerbate diseases -> Yes, low-lying planting areas and the presence of weeds such as purslane and quinoa can exacerbate the spread and development of diseases, as these conditions are conducive to the growth and spread of pathogens.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1168", + "fact_text": "Is there any way to prevent this situation -> Prevention and control of this situation can be achieved through early spraying and the use of disease resistant varieties. For example, specific pesticides such as 20% triazolone emulsion or 30% white pine emulsion can be used, diluted according to the recommended ratio and sprayed regularly.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5330", + "fact_text": "Under what conditions are these pests usually active -> This type of pest is usually active in spring and autumn, especially between April and June when it is most severely affected. When the temperature is between 11.5 and 18.5 degrees Celsius and the soil moisture content is between 20% and 30%, they are more active.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1554", + "fact_text": "What are the symptoms of early infection in celery -> In the initial stage, the infected area of celery appears watery, but later softens and rots.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1907", + "fact_text": "In the image, which parts of the plant first show symptoms -> Initially, the disease manifested as a white frost like mold layer on the stems and leaves of seedlings.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3973", + "fact_text": "What is the general impact of this situation on crop growth -> Usually, this will seriously affect the growth and yield of crops. Infection of Flammulina velutipes can lead to disease from the formation of the original base to the harvesting period, and in severe cases, the fruiting body may shrink and wither, resulting in a significant decrease in yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1744", + "fact_text": "Is there any way to prevent the occurrence of this viral disease -> Preventive measures include the use of antiviral biopesticides, timely elimination of aphids carrying the virus, and reasonable intercropping and rotation to reduce the risk of virus transmission.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image3254", + "fact_text": "Why do the lesions on these leaves appear this color -> This color change may be due to the damage to the leaf tissue caused by pathogen infection, resulting in the color changing from normal green to light yellow brown to light red brown. The gray white color in the center may indicate that the leaf tissue has died and lost normal pigments.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5246", + "fact_text": "What color does the crop in the image look like -> The crop in the image should be cotton, so the color should be green. However, due to the influence of pests, the leaves may have partial defects or holes, or even be eaten up, leaving only the veins, which may affect the overall color.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4695", + "fact_text": "How can we prevent or control the pests displayed in the image -> For the pests displayed in the image, we can try prevention and control methods, such as adjusting crop layout and improving farmland environment, using pest resistant varieties, etc. Spraying specific insecticides is also an effective method when necessary.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5333", + "fact_text": "What significant damage have pests and diseases caused to crops -> In the image, you can see that the leaves of the crops have been gnawed on, and some have even been eaten into holes or notches, leaving only the leaf veins. This is due to damage caused by pests. In addition, insect manure also pollutes the leaf surface, which may reduce the commercial value of crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4603", + "fact_text": "What factors are causing this problem -> This problem is caused by a fungus called Monilochaetesinfuscans. The hyphae produced by this fungus in the early stages are colorless, but later turn black. It can directly invade from the crop epidermis and is more susceptible to disease under high temperature conditions. In addition, rainy weather, heavy soil, poor drainage, or saline alkali land are also favorable conditions for the onset of disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3793", + "fact_text": "May I ask if the plants in the image look healthy -> The plants in the image show watery necrosis of the basal bulbs and young plants, indicating poor health of the plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5508", + "fact_text": "How to usually prevent and control the situation in the picture -> To prevent and control the situation in the picture, pruning dead branches and thinning dense branches can be used to improve ventilation and light transmission conditions. At the same time, when white fluff is found, physical methods can be used to touch and reduce the number of nymphs, and appropriate chemical agents can be used for spraying.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image3103", + "fact_text": "What is the possible cause of this situation -> This is mainly caused by excessive application of chemical fertilizers or manure, especially during changes in soil acidity and alkalinity. Excessive use of chemical fertilizers may lead to such problems.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4439", + "fact_text": "What are the characteristics of the stripes on these leaves -> These stripes have irregular or wavy edges, and they are parallel to the leaf veins. In severe disease conditions, these stripes can extend to affect the entire leaf.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image927", + "fact_text": "What measures should be taken to prevent and control this situation -> Some effective measures include using disease resistant varieties, increasing the application of organic and phosphorus potassium fertilizers, and timely removal and incineration of disease residues. In addition, chemical agents can also be used, such as spraying specific pesticides in the early stages of the disease, and spraying every 10 days or so for continuous prevention and control 2 to 3 times.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5758", + "fact_text": "When are the pests that invade these plants most active -> This type of pest is more active in the early morning or evening and likes to feed and lay eggs during these periods.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4684", + "fact_text": "What morphological features do pests exhibit in images -> The pests in the image have a metallic luster, with copper green to purple black heads. The antennae are not completely brown, and generally the base of each segment is brownish red or light brown, while the ends are black brown. The chest and back panels are copper green or gold green. The feet are reddish brown or light brown in color, and there are large metallic dark blue spots on the back and back half of the legs. The abdomen is covered with silver fur. Its chest and back plate are nearly square, and the small shield is triangular. It can be seen that the hind legs are relatively slender, with a narrow base, an enlarged middle and rear part, and a large tooth at the end.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2370", + "fact_text": "Which part of the crop are these spots more common in -> Spots often appear from the edge or petiole of the lower leaves and gradually spread upwards.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4697", + "fact_text": "How should we understand this anomaly -> These symptoms indicate that wheat may be being ingested by certain organisms. Specifically, it may be caused by some small pest sucking on the sap of wheat leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato yellow leaf curl virus 2", + "fact_text": "What is the simplest and most effective method to prevent tomato yellow leaf curl virus disease -> Set up high-density insect prevention nets", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4647", + "fact_text": "Is there any way to help farmers prevent this pest -> Choosing insect resistant varieties with hard stems and moderate leaves is an important step. When the egg laying rate of wheat reaches about 10%, with an average egg laying rate of more than 10, spraying relevant pesticides immediately at the beginning of the incubation period can effectively prevent the spread of pests.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2579", + "fact_text": "What is the surface covering of the fruits and melons in this picture -> In the image, it can be seen that the surface of the fruit is covered with a white layer of mold, which usually occurs in environments with high humidity.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "mango chlumetia transversa 300", + "fact_text": "Which subject does Chimetia transversa belong to -> Army worm family", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5498", + "fact_text": "What is the edge morphology of these affected leaves -> The edges of the affected leaves show straight notches, indicating the presence of larger larvae feeding on them.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2857", + "fact_text": "How do the tomato leaves in the image look -> The tomato leaves in the image have a gray black to black brown mold layer, which may be due to the infection of a certain disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4103", + "fact_text": "Do the tomato plants in the picture require special management measures -> Yes, based on the symptoms shown in the image, it is recommended to adjust the formula of the nutrient solution appropriately, especially to reduce the supply of calcium, and pay attention to the hardness of the water quality.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1990", + "fact_text": "How does this withering occur -> It may be due to insufficient water absorption capacity of the roots or excessive evaporation of water, resulting in uneven water supply.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "corn leaf beetle 243", + "fact_text": "What is the morphology of the larva of this insect Answer: Adults", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2895", + "fact_text": "Are all plants displaying these symptoms in the image -> Not necessarily, usually symptoms first appear on some plants and may spread to other plants under suitable conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2043", + "fact_text": "Is the slow growth of corn in the picture related to phosphorus deficiency -> Yes, in the image, corn grows slowly, which is directly related to phosphorus deficiency. If there is a lack of phosphorus in the early stage, even if there is sufficient phosphorus supply in the later stage, it is difficult to fully compensate for the loss in growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4404", + "fact_text": "What methods can be used to control the spread of this disease -> There are several main ways to prevent and control this disease. Firstly, establish disease-free barley fields and breed disease-free seeds. Secondly, carefully select seeds before sowing, choose seeds that are full, have strong vitality, and have a high germination rate. Seed treatment can also be carried out, such as using specific pesticides to mix seeds, or using other specific substances such as lime water, ferrous sulfate, and soaking spirit emulsion for soaking treatment. In addition, timely sowing may also help prevent the occurrence of diseases, such as sowing in high soil temperature and low humidity, which can reduce the chances of bacterial infection.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5367", + "fact_text": "What are the characteristics of pests in images -> The insect pest in the image is a small gray brown moth, with a body length of 6-7mm, wings spread 12-15mm, and narrow wings. Its front and rear wings have a yellow white three degree zigzag ripple, and when the two wings close, it presents three consecutive diamond shaped spots.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "management instructions", + "entity": "image5222", + "fact_text": "How should we prevent and deal with this disease of tea trees -> In order to prevent and control this disease, it is first necessary to strengthen the management of tea gardens, timely cultivate and weed, and timely drain water after rain to avoid moisture retention. Pruning aged tea trees and applying nitrogen, phosphorus, and potassium fertilizers in a reasonable manner to ensure their healthy growth. In the early stages of disease occurrence, 25% benzimidazole emulsion or other effective chemical agents can be used for spraying treatment.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2328", + "fact_text": "Is there any way to prevent this situation from happening -> Increasing the application of organic fertilizer and phosphorus potassium fertilizer, while avoiding excessive use of nitrogen fertilizer, can help reduce the occurrence of this disease. Cleaning up disease residues in the field is equally important.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2126", + "fact_text": "What could be the potential cause of this situation -> This may be due to physiological barriers caused by the use of certain pesticides that are more sensitive to cucumbers, which hinder normal growth and development.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4887", + "fact_text": "What kind of environment is this plant most suitable for growing in -> This plant is most suitable for growing in moist and fertile soil. In such an environment, it can form dense growth and has strong regenerative ability.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "pepper virus disease 385", + "fact_text": "What disease caused the results on the leaves in the picture -> Chili pepper virus disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5398", + "fact_text": "What are effective prevention methods for such pests -> Effective prevention methods against this pest in images include the use of agricultural techniques and chemical interventions. In winter, removing dead branches, leaves, and weeds from the field, and timely composting or burning them can eliminate some overwintering adults. During the period of adult and nymph infestation, using broad-spectrum insecticides and spraying at conventional concentrations has good toxic effects.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5551", + "fact_text": "What is the condition of the plant roots in the image -> The roots also show signs of disease, with black fungal nuclei forming along with root decay.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2122", + "fact_text": "How to prevent or improve this situation -> Improving this situation can be achieved through timely application of nitrogen fertilizer or topdressing outside the roots. It is recommended to use ammonium sulfate and ammonium bicarbonate to increase nitrogen fertilizer application, which can be quickly utilized by plants. In addition, a mixture of 0.1% potassium dihydrogen phosphate and 0.2% urea can also be sprayed for foliar spraying.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4431", + "fact_text": "Has there been any change in the state of the fruit ears -> According to the provided information, it can be seen that there are obvious signs of decay and shrinkage in the fruit ears. Light or small fruit clusters may be upright. These states are all abnormal, which should be caused by the influence of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2277", + "fact_text": "Are there any other abnormalities in the leaves besides yellowing -> Leaves curl inward under drought conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4421", + "fact_text": "Is there any effective prevention and control method to deal with this disease -> Effective methods to prevent this disease include selecting resistant varieties for planting, improving cultivation conditions, and strengthening management. In addition, soaking the seeds with a certain amount of medication before sowing is also a simple and effective method for aphid control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4819", + "fact_text": "In which seasons does it usually appear -> This type of insect begins to hatch in late April in the local area, while adults mainly appear from late June to early July, with the peak period of moth emergence occurring from July to August.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4331", + "fact_text": "Is there any way to prevent or treat this disease -> The methods for preventing and controlling this disease include: selecting wheat varieties that are resistant to anthracnose; Crop rotation with non gramineous crops for more than three years; After harvesting, it is necessary to promptly remove diseased or damaged bodies or dig deep; In areas or plots with severe diseases, spraying benzimidazole wettable powder or benzimidazole emulsion can be used for prevention and control, every 15 days.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2132", + "fact_text": "Is this white cotton like substance accidental -> It's not entirely accidental. In environments with high humidity, this white cotton like substance is more likely to appear and is associated with specific health issues.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5266", + "fact_text": "Can you tell what kind of pest it is -> Based on what is seen in the picture, this pest may be a species of insect belonging to the family of stinkbugs.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4641", + "fact_text": "What does the insect pest shown in the image look like -> The pest in the image is an insect with an adult body length of 11-14mm and wings spread between 25-35mm. Their colors are gray yellow white, with gray yellow brown front wings and silver gray brown wavy horizontal stripes decorated on the outer edges. The wing surface is also covered with 5-6 indistinct gray brown short longitudinal stripes, with some small black spots distributed on the stripes. The color of the hind wings gradually changes from white to brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5024", + "fact_text": "What could be the reason for this situation -> This may be due to crops being infected with a virus called Peanutstripvirus, which belongs to the potato Y virus group.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3661", + "fact_text": "Under what conditions will this situation worsen -> If exposed to high humidity (such as relative humidity exceeding 85%) and moderate temperature (about 5 to 20 ℃), the disease will be more prone to deterioration. The diseases in the image spread faster and are more difficult to control in such an environment.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2087", + "fact_text": "What could be the reason for this situation -> This is usually related to pathogenic Fusarium in the soil. When environmental conditions are suitable, such as high temperature and humidity, these pathogenic bacteria can be activated, causing root diseases in celery.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2437", + "fact_text": "What factors usually accelerate the development of this problem in such an environment -> Usually, low temperature and high humidity environmental conditions can accelerate the development of such problems, especially in cases of poor ventilation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "rice grain spreader thrips 36", + "fact_text": "What is the harm caused by the insects in the picture to the leaves Answer: Blade curling", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3367", + "fact_text": "How to prevent this situation from happening -> Appropriate soil temperature and humidity should be maintained to ensure good soil permeability and promote normal physiological activities of roots.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5249", + "fact_text": "Is there a method to prevent and control this pest -> Yes, it is possible to manually kill the larvae in the rolled leaves by combining field management. We can also use natural enemies for biological control. In addition, relevant pesticides can also be sprayed when the larvae begin to develop.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image310", + "fact_text": "What consequences will this state of the root system have on the plant's absorption of water and nutrients -> Damaged root systems weaken their ability to absorb water and nutrients, especially the absorption and utilization of nutrients such as phosphorus, calcium, potassium, and magnesium, which directly affects plant growth and fruit quality.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5201", + "fact_text": "What are the reasons for the formation of these nodular structures -> These are caused by specific plant parasitic nematodes. After invading the cells of tea trees, they secrete some substances that cause the root cells to abnormally expand and form root nodules.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "citrus phyllocoptes oleiverus ashmead 147", + "fact_text": "The tail of the insect in the picture is relatively thin, right Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2833", + "fact_text": "What impact does this situation have on the fruit -> The fruit in the picture has poor coloring, with large contiguous green patches on the surface, and after harvesting, it cannot turn red even after being left for a period of time. Only the green part fades to yellow white, which is caused by physiological diseases caused by excessive nitrogen.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tea brown blight 1", + "fact_text": "What diseases have affected the leaves in the picture -> Tea brown light", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5773", + "fact_text": "What are the characteristics of insects in the image -> The insect in the picture is a female adult, with a body length of approximately 2mm and wings spread 4-5mm. The body color ranges from gray to grayish black, with transparent and colorless front wings and degenerate back wings.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3406", + "fact_text": "Will the symptoms of this type of leaf affect the overall health of the plant -> Yes, severe leaf damage can affect the overall health of the plant, leading to incomplete fruiting or poor seed quality after fruiting.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3428", + "fact_text": "What are the characteristics of these conidia -> They are usually spherical, with brown membrane walls and a pore opening.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image1686", + "fact_text": "What is this layer of white cotton like material composed of -> This white cotton like substance is actually composed of mycelium produced by fungi.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5047", + "fact_text": "So, are there any effective methods to prevent and control this soybean disease -> For this disease, prevention and control methods include: 1. Rotation with grasses for at least 3 years. 2. Choose disease resistant varieties such as Kehuang 2, Xuzhou 424, Nan 493-1, Peixian Dabaijiao, etc. 3. Compost made from Japanese fermenting bacteria or fully decomposed organic fertilizer can be used. Before sowing, 0.3% of the seed weight can be mixed with 50% fipronil. 5. In the early stage of the disease, a 1:1:160 Bordeaux solution or a 30% Green Delicate suspension at a ratio of 400 times can be sprayed. Depending on the condition, prevention and treatment should be carried out once or twice.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5410", + "fact_text": "What are the characteristics of this insect -> The larval stage of insects is usually yellow green with grayish brown spots on the sides, while adults have a body length of about 15-16mm, wings spread 32mm, and have grayish brown front wings and special silver stripes.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5344", + "fact_text": "What methods can prevent the invasion of this insect -> An effective method to prevent and control this type of pest is to thoroughly remove weeds and fallen leaves from vegetable gardens and nearby fields before the adult insects come out of hibernation in spring, in order to lower the source of the pest and reduce damage. The commonly adopted chemical control methods can also refer to the treatment of vegetable bugs.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tea algal leaf 133", + "fact_text": "What disease is the leaf in the picture suffering from -> Tea algae leaf spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5234", + "fact_text": "How to usually prevent and control this pest -> The prevention and control methods include timely prediction and prediction of insect infestation, using insect resistant cotton seeds or planting insect resistant crops such as corn as moth attractants. In addition, biological control is also important as it can naturally suppress pests by releasing natural enemies such as red eyed bees.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "beet fly 37", + "fact_text": "Name a method to prevent and control the insects in the picture. -> Dipterex powder", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1649", + "fact_text": "What changes will occur in the leaves of the crops in the picture during drought -> Under drought conditions, affected diseased leaves will wither and die. Compared to decay under humid conditions, diseased leaves mainly wither during drought.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image993", + "fact_text": "Are the leaves of the plants in the picture uniformly diseased -> No, diseases usually spread from the tip of the leaves, ultimately leading to leaf decay.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "wheat cerodonta denticornis 24", + "fact_text": "What is the specific color of the larvae in the picture Answer: Milky white", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4535", + "fact_text": "So, what is the pathogen that causes this disease -> This is caused by a fungus called Fava bean rust fungus. It mainly parasitizes on both sides of leaves or petioles and stems. Initially, it will be buried inside the leaves or stems. As the disease progresses, it will break through the plant epidermis and form a brownish red summer spore pile.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3526", + "fact_text": "Is there anything special about the texture on the surface of these lesions -> The surface of the lesion will become very rough because the diseased cell tissue has undergone corkification treatment, making the epidermis rough and prone to cracking.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "vitis brevipoalpus lewisi mcgregor 38", + "fact_text": "What is the name of this insect in the picture -> Brevipoulpus lewisi McGregor", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4635", + "fact_text": "Is there any abnormality in the appearance of rice leaves in the image -> The rice leaves in the image show a phenomenon of being rolled up, curling from the edge to the center, which is a typical manifestation of insect damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5334", + "fact_text": "Will this type of pest occur concentrated at specific times of the year -> In southern regions such as Guangzhou, this pest infestation is slightly more common from April to May and October, and relatively less common at other times.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "pepper blossom end rot 13", + "fact_text": "What disease is causing the abnormal phenomenon on the surface of chili peppers in the picture -> Chili navel rot disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1088", + "fact_text": "How will these symptoms affect the overall growth of plants -> Diseases can cause the seedlings of plants to suddenly collapse during the seedling stage, and the affected large seedlings to wither. In the adult stage, severe disease spot fusion and necrosis can lead to cortical detachment, exposing the xylem, increasing the risk of wind damage to the plant, thereby affecting the growth and survival of the entire plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2924", + "fact_text": "What are the specific blade issues -> There are white elliptical spots on the leaves, which gradually connect into patches and eventually cause the leaves to curl and wither.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5572", + "fact_text": "Is there any way to prevent this situation from happening -> It is possible to reduce the incidence of diseases through reasonable dense planting and attention to ventilation and light transmission. In addition, spraying specialized drugs in the early stages of the disease can effectively control the condition.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2072", + "fact_text": "Is it possible for crops to be affected by diseases during various growth stages as shown in the image -> Yes, from the image, it can be seen that from the seedling stage to the mature stage, the leaves, stems, and even the bracts and grains of the crop may be affected.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2853", + "fact_text": "What preventive measures can be taken for this situation -> Suitable varieties should be selected and fertilizers should be applied reasonably, especially paying attention to the balanced application of nitrogen, phosphorus, and potassium fertilizers, while avoiding the adverse effects of high temperature and strong light on plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5804", + "fact_text": "In what environment does this pest usually overwinter -> This type of pest usually winters in clusters in different crevices of the tree, especially in soil crevices near the dry base.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4076", + "fact_text": "Does the soil environment in the image have an impact on this situation -> Yes, in the image, if the soil is suddenly wet and dry, especially after a long drought, excessive watering can cause the fruit to quickly absorb water and crack.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4826", + "fact_text": "What is the activity time of insects in the image -> This type of insect is more active at night, especially when unearthed and mating in the evening, but the phototaxis of adults is not strong.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4547", + "fact_text": "What causes this disease -> This disease is caused by a fungus called Uromycespisi (Pers.) Schrot, which is a parasitic bacterium. There are many physiological races on peas.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5102", + "fact_text": "How is its growth condition -> According to the image, the growth of the plants is not ideal, showing some signs of thinness and slow growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "citrus parlatoria zizyphus lucus 68", + "fact_text": "Are the insects on this fruit circular Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2767", + "fact_text": "Where are these lesions more common on the leaves -> These lesions usually appear in the middle of the leaves or along the main and leaf veins.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image912", + "fact_text": "How was this situation caused -> This situation is mainly due to the infection of various pathogenic fungi inside or in the root area of lotus roots, which affects the life activities of the entire plant, including the discoloration of vascular bundles and the decay of underground stems. These factors together lead to plant withering and death.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image8", + "fact_text": "Are there any effective prevention methods -> Bananas can be treated with the bacterial solution of Bacillus subtilis B63, B68, B74, and B75 strains and non bacterial filtrate after harvesting, which can effectively prevent banana crown rot caused by Fusarium. Among them, the T368 strain has the highest and significantly better control effect than commonly used fungicides, with the best prevention and control effect. The prevention effect will increase with the increase of filtrate concentration.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "soybean mosaic disease 1", + "fact_text": "What causes the symptoms on the leaves in the picture -> Soybean mosaic disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2081", + "fact_text": "Under what conditions do these symptoms usually worsen -> Under humid and rainy conditions, these symptoms can quickly spread, especially in the temperature range of 20 to 25 degrees Celsius.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4152", + "fact_text": "How does the stem of tomatoes perform -> The stem exhibits brown cork like cracks and curvature, which are typical symptoms of boron deficiency in the stem.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4705", + "fact_text": "What does this insect look like and what are its characteristics -> The adult body of this insect species is 8-13.5mm long and approximately 6mm wide, with an elliptical shape, yellow brown or purple, densely covered with white fur and black small dots; The antennae appear as black and white alternating; Its beak is slender and tightly attached to the ventral surface of the head. The end of the small shield is blunt and smooth, appearing yellow white.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "grape powdery mildew 200", + "fact_text": "What is causing this abnormal phenomenon -> Grape powder mildew", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image338", + "fact_text": "Is there any way to save deformed or cracked fruits that have already formed -> Once the fruit has cracked or deformed, it is difficult to effectively salvage it. The best strategy is to prevent other fruits from experiencing the same problem by adjusting future management measures. At the same time, the use of plant growth stimulants should be strictly controlled to avoid adverse effects on partially opened flower buds.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "beet fly 15", + "fact_text": "What color is the eye of the insect in the picture Answer: Red", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "wheat green bug 204", + "fact_text": "Will the one in the picture spread other diseases Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image2595", + "fact_text": "Can you distinguish which drug caused the damage when observing the image -> It is difficult to directly identify specific drugs from images, but usually this type of drug damage is caused by improper dosage of the fifth generation agent or the quenching agent.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2478", + "fact_text": "Will there be any new changes on the leaves after about a month of appearance of white powder -> About a month later, there may be many small black spots on the leaves, which are the ascocarp formed by the pathogen.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "potato hollow heart 76", + "fact_text": "Where does Potato tuber hollow disease usually occur in tubers Answer: Marrow", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3370", + "fact_text": "At what stage of crop growth does this problem typically occur -> This type of problem often occurs in the later stages of growth, but in severe cases, it may also begin to appear in the middle or even early stages of growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4816", + "fact_text": "What are the methods for preventing and controlling this pest -> It can be prevented from laying eggs by clearing surrounding weeds in early spring, or by using black light lamps and sugar vinegar to lure and kill adults for prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image397", + "fact_text": "Are there any other abnormal phenomena on the leaves -> Yes, you will notice that the edges of the leaves are scorched and the overall leaves are wrinkled.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4388", + "fact_text": "What are the causes of these symptoms -> Mainly due to the deficiency of elements in the soil, such as nitrogen, phosphorus, potassium, and other essential elements for plant growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5374", + "fact_text": "Can the excrement of pests be observed on the affected plants -> It can be observed that there are small pieces of excrement on the affected plants, which may lead to further contamination and decay of the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2394", + "fact_text": "What are the effects on the growth of carrots after this situation occurs -> This disease can seriously affect the photosynthesis and nutrient absorption of carrots, leading to overall health and growth damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image750", + "fact_text": "What are the environmental conditions around the plants shown in the image -> The environment in the image appears relatively humid, which may contribute to the occurrence and development of certain diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4296", + "fact_text": "How fast does this symptom expand -> This disease can occur during the tillering, jointing, and panicle stages. During the tillering stage, the leaves turn yellow from bottom to top, and the edges of the leaf sheaths near the water surface are brown, with gray elongated spots in the middle. The root nodes change color with a foul odor. At the panicle stage, the diseased plants first lose water and wither, then form withered booted panicles, white panicles, or semi white panicles. The root nodes change color and have short and few lateral roots, which have a foul odor. The spread of this disease is systematic and continuous.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4785", + "fact_text": "What are the feeding characteristics of this pest -> The larvae of this pest mainly feed on leaves and also bite on tender stems and petioles. In severe cases, it is possible to eat all the leaves and tender stems, which will cause serious damage to the crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4630", + "fact_text": "What measures can be taken to reduce the occurrence of this pest -> Reasonable fertilization, strengthened field management, and the use of biological control methods, such as releasing natural enemies such as red eyed bees, can all help reduce pest damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4779", + "fact_text": "What are the morphological characteristics of pests in the image -> This type of pest has a body length of 4.2 to 5.6 millimeters, with a semi-spherical shape and a humped back. It ranges from yellow green to turquoise green and has a metallic luster. The front chest, back plate, and sides of the wings extend outward in a turtle like shape, and there are network like patterns on the extended parts. There are two closely spaced black lines in the center of the back of the chest, and some insects can merge together. There is a black to dark brown \"V\" shaped spot at the edge of the dorsal protrusion of the Coleoptera. There is a longitudinal line at the middle seam, which varies in thickness, and some longitudinal lines may disappear. Its antennae have 11 segments, light green, and some have 2-3 segments of black brown at the end, extending backwards over the shoulder corner of the Coleoptera.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image299", + "fact_text": "Is there a way to prevent this situation -> Prevention can be achieved by correctly mastering the concentration and method of using 2,4-D, such as using an appropriate concentration, paying attention to the time and frequency of dipping flowers, avoiding repeated spraying, and paying attention to timely watering and topdressing after spraying.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5344", + "fact_text": "Can you describe the colors and textures of objects in the image -> In the image, the body color of this pest is mainly orange yellow or orange red. Its head is black, and there are six black spots on the chest and back panel. There are orange yellow or orange red Y-shaped patterns on the small shield, which shrink at the intersection. The membrane is black with white edges.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5262", + "fact_text": "What season is usually when this type of insect appears -> This type of insect starts its activity in April every year, and September is the peak period for their occurrence and damage, especially in autumn, when they are most severely affected.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "grape powdery mildew 95", + "fact_text": "What factors are causing the phenomenon on the surface of the fruit in the picture -> Grape powder mildew", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5689", + "fact_text": "What happens after the rupture -> After the blister ruptured, a large amount of yellow brown powder was scattered, which were the spores of the bacteria.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4352", + "fact_text": "How should we prevent and treat this disease -> Epidemic prevention can be achieved through clever seed processing methods, such as soaking seeds in warm soup, which is an effective method of prevention and control. In addition, using pesticides to mix seeds can also prevent the occurrence of such diseases, for example, using 75% chlorpyrifos wettable powder or 20% triazolone emulsion for seed mixing. These drugs can effectively prevent such diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1221", + "fact_text": "When and under what conditions is this disease prone to occur -> This disease is prone to occur under high temperature and humidity conditions, especially during the rainy season, as well as under poor ventilation and weakened plant growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2357", + "fact_text": "What are the recommended preventive measures for this situation -> The recommended preventive measures for the situation in the picture include selecting heat-resistant varieties, planting on plots with suitable drainage and good soil permeability, timely drainage after rain to prevent water accumulation, and increasing watering in sunny weather to cope with high evaporation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image1195", + "fact_text": "Did you see any special taste in the diseased parts of winter melon -> Although not directly detectable, this type of disease usually causes winter melon to emit an unpleasant odor.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "tomato leaf miner 9", + "fact_text": "What is the abnormal phenomenon in the picture Answer: White stripes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5155", + "fact_text": "At which stage did this phenomenon occur -> This phenomenon can occur from the seedling stage to the adult stage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2044", + "fact_text": "What is the development of the corn root system in the picture -> From the image, it can be observed that the root system development of corn is poor. This is because phosphorus deficiency directly affects the development of the root system, weakening the plant's ability to absorb water and nutrients.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4668", + "fact_text": "Are there any good preventive measures for pests and diseases in the images -> Yes, weeds and dead leaves can be removed from the fields and ditches in a timely manner before planting to reduce overwintering insect sources. Timely apply sufficient basal and foliar fertilizers, while sun drying and fallowing the fields, to improve the insect tolerance of rice seedlings. For damaged fields, nitrogen, phosphorus, and potassium quick acting fertilizers should be applied to promote rice seedling growth. Chemical control methods can also be adopted, such as timely spraying of corresponding agricultural drugs.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4773", + "fact_text": "What color is the organism in the image -> In the image, the color of this species is mainly black or black brown. Its antennae, back of head, and front half of the first six segments of the abdomen are black. In addition, its compound eyes are brownish red, and the back of the chest and back panel is brownish black.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "corn mole cricket 74", + "fact_text": "Will Mole cricket bite the roots and tender stems of plant seedlings Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4729", + "fact_text": "How did this situation arise -> The reason for this situation is a type of pest whose larvae attack the plant, feeding on leaves and causing gaps or holes.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "rice stemfly 1", + "fact_text": "What is the color of the insect in the picture Answer: Yellow white", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2111", + "fact_text": "What changes do the leaves and petioles undergo under humid conditions -> Under high humidity conditions, the base and petiole of the leaves will turn black and soften.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2172", + "fact_text": "What measures should we take to prevent and control this situation -> Prevention can be achieved by selecting disease resistant varieties and strengthening temperature and humidity management in greenhouses. Once the disease occurs, specific chemicals can be used for treatment, such as spraying sulfur containing drugs.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "cucumber powdery mildew 3", + "fact_text": "What kind of disease is the crop in the picture suffering from -> Cucumber powdery mildew", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "soybean mosaic disease 3", + "fact_text": "What diseases have affected the leaves in the picture -> Soybean mosaic disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "wheat longlegged spider mite 26", + "fact_text": "Is there any bristles on the back in the picture Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4617", + "fact_text": "What type of crop is shown in this picture -> The crop shown in the image belongs to the potato category.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "corn amsacta lactinea 3", + "fact_text": "What is the name of the insect in the picture -> Amsacta lactinea", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image510", + "fact_text": "Under what conditions do fungal nuclei germinate -> Fungal nuclei will germinate under suitable temperature and humidity conditions, usually requiring temperatures above 15 ℃ and relative humidity above 85%.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image4687", + "fact_text": "Will this pest cause diseases in crops -> Yes, this type of pest not only causes crops to wither and fail to grow normally, but also may spread wheat yellow dwarf disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5109", + "fact_text": "What is the status of crop roots in the image -> The image shows that the roots of the crops are clearly decaying, with black brown damage to the root tail and root body. The texture of the entire root looks very unhealthy, and some parts even have depressions or cavities.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3591", + "fact_text": "Is this root problem common, or does it only affect a few plants -> The impact seems to be quite common, with most plant roots showing symptoms of decay.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5435", + "fact_text": "Does this pest have an impact on the human body -> Yes, contact with the venomous hairs of insects can cause dermatitis and sometimes even lymphatic inflammation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "lemon canker 130", + "fact_text": "What diseases have affected the leaves in the picture Answer: Lemon canker", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "citrus phyllocoptes oleiverus ashmead 96", + "fact_text": "The key to preventing and treating this situation is in the early stages, right Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image950", + "fact_text": "What is the recommended handling method for this situation -> It is recommended to carry out seed pretreatment. In addition, implementing good agricultural management measures, such as crop rotation and the use of disease resistant varieties, can effectively reduce the occurrence and spread of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1445", + "fact_text": "Does the crop stem in the image appear to have any abnormal phenomena -> The base of the crop stem in the image shows a light brown water stain like change, and there may be basal rot phenomenon in the later stage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4664", + "fact_text": "Is there any method to prevent and control this disease and pest -> (1) Early and late rice seedling fields should be sprayed with pesticides 5 days before seedling pulling, which has a significant effect on reducing the number of insect infestations in the later stage. (2) Honda's prevention and control should be carried out in a timely manner according to the pest situation, and the types and amounts of medication should refer to the black tailed leafhopper", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image41", + "fact_text": "What methods can prevent this situation from happening -> Agricultural measures such as selecting seeds can be taken to prevent the mixing of seeds containing such linear objects, as well as to suppress the germination of their seeds by deep plowing. In addition, removing and burning or burying already growing linear objects is also an effective method.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image293", + "fact_text": "How will this situation affect the overall growth of tomatoes -> This can lead to tomato collapse, mainly due to softening and necrotic spots on the stem, affecting plant stability and nutrient transport.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5333", + "fact_text": "What are the morphological characteristics of the pests that cause this situation -> The insect pests in the image are similar to those of the cabbage butterfly, but there are 3-5 triangular black spots on the outer edges of the front and rear wings. Its larvae are similar to cabbage worms, with a dark green body and dark green round spots around the black brown hair nodules on the back of the body. Its pupa is similar to that of the vegetable noodle butterfly pupa, but the central protrusion in front of the head is tubular and long.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3063", + "fact_text": "Is this type of verticillium wilt easy to observe with the naked eye -> Yes, the symptoms of this wilt disease are very obvious, especially when the entire plant begins to wilt, which can be easily observed by the naked eye.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "lemon canker 22", + "fact_text": "What disease is the fruit in the picture suffering from Answer: Lemon canker", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image5068", + "fact_text": "What are the possible ways of transmission for crops infected with diseases in the image -> This disease may be left in the soil or attached to seeds through mycelium to overwinter. When the temperature and humidity conditions are suitable, conidia will sprout and infect, spreading by splashing from wind or rain. The conidia produced by the diseased area may undergo re infection. The occurrence period of this disease is mainly affected by temperature, but the severity of the disease is influenced by the amount of rainfall during the appropriate temperature period and the frequency of rainfall. It belongs to the high temperature and high humidity type of disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4691", + "fact_text": "What are the significant morphological characteristics of this pest -> The body length of the wingless parthenogenetic aphid is ovoid, 1.8-2.2mm in length. The live insect is dark green, covered in thin white powder, with black appendages and reddish brown compound eyes. The 7th section of the abdomen has black hair patches, the 8th section has a transverse band on the back, and there are mesh patterns on the surface of the body. The antennae, beak, feet, abdominal canal, and tail are black. The winged parthenogenetic aphid is oval shaped, with a body length of 1.6-1.8mm. Its head and chest are shiny black, and its abdomen is yellow red to dark green.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4051", + "fact_text": "What other special suggestions are there for cultural management -> It is recommended to strengthen water and fertilizer management in cultural management to avoid excessive nutrition during the seedling stage. Apply compound fertilizer and organic fertilizer in moderation, while paying attention to the dry and wet conditions of the soil, to optimize the healthy development of roots and reduce the generation of deformed fruits. After planting, timely watering and adjusting the fertilizer ratio, especially increasing the use of phosphorus and potassium fertilizers.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "mango dasineura sp 106", + "fact_text": "What is the reason for the abnormal phenomenon in the picture Answer: Dasineura sp", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4478", + "fact_text": "What kind of impact will this disease have on production -> This disease is prone to occur and spread under high humidity and rainy conditions, especially in low-lying areas. In severe cases, due to the early withering of leaves, large areas of early death may occur in high-altitude production areas, causing a significant impact on agricultural production.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4763", + "fact_text": "When is this pest usually most active -> This type of pest prefers to move around in the morning and evening. In the northern spring valley area, the lifespan of female adult flies can reach 41-46 days, while that of male flies is 31 days. In the hot summer valley area, the duration of each insect state is shortened, and the amount of eggs laid is also reduced.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1125", + "fact_text": "What are the developmental stages of disease formation -> Initially, it was a light brown waterlogged lesion, with white hyphae growing on the surface during high humidity. Subsequently, the diseased epidermis may rupture and reveal a fibrous appearance, similar to hemp silk. The plant will eventually wither and die.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3507", + "fact_text": "What is the cause of this disease -> It is caused by a fungus called Rhizoctoniasolani, which initially produces colorless hyphae, but gradually changes color and constricts as the condition worsens.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image80", + "fact_text": "Is there any special manifestation on these lesions when the humidity is high -> When humidity is high, pink mucus may form in the middle of the lesion.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image2745", + "fact_text": "So, how much will the shelf life of the fruit be affected in this situation -> This type of disease can significantly shorten the shelf life of fruits, leading to rapid spoilage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3937", + "fact_text": "How will the growth rate of shiitake mushrooms be affected in such an environment -> In this high carbon dioxide and high humidity environment, the growth rate of shiitake mushrooms significantly slows down because the fruiting body cannot differentiate and develop normally, resulting in the inability to form a complete shiitake body.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2782", + "fact_text": "How does the fruit look -> The fruit may show signs of discoloration before maturity, turning dark brown, and surface wrinkling.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5564", + "fact_text": "What pathogen is causing this situation -> This is caused by a fungus called Staphylococcus ellipticus, which belongs to the subphylum of Actinobacteria and has light brown to brown conidia. The stem is upright and branches at the top, supporting many conidia.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image5011", + "fact_text": "Is there any effective prevention and control method that can be displayed in the image -> Although images may not directly display prevention and control measures, disease prevention can be achieved by improving management level, drainage and reducing field humidity, increasing phosphorus and potassium fertilizer application, and avoiding biased nitrogen fertilizer application. In addition, some specific spraying drugs such as 25% triazolone wettable powder and 60% Anti mold Bao 2 water-soluble powder can also be used for early disease prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4477", + "fact_text": "What is the cause of this problem -> The cause of this problem is a fungus called Gloeocercosporasorghi, which is a phylum of fungi belonging to the subfamily Hemimonas. Its conidiophores are multi rooted, solitary, colorless, with a septum and a size of 6-20 Γ— 1.5-2.5 (um); Conidia grow in clusters of orange red sticky substrates, linear, colorless, slightly pointed at the tip, with 4-8 indistinct septa and sizes of 32-112 Γ— 3-4 (um).", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "grape downy mildew 1", + "fact_text": "What disease is causing the anomaly in the picture -> Grape Downy Mildew", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4779", + "fact_text": "Do you have any suggestions for preventing and controlling this pest -> As shown in the image, there are several prevention and control suggestions: first, immediately clean up the weeds in the fields and edges after harvesting sweet potatoes, which can eliminate some overwintering insect sources. Secondly, as the number of adult insects increases, spraying pesticides such as 1200 times the concentration of% crystal trichlorfon or 1500 times the concentration of 40% dimethoate emulsion can be started at dusk.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4663", + "fact_text": "What are the prevention and control methods for this organism -> The prevention and control methods include selecting insect resistant varieties, protecting and utilizing natural enemies such as insects and predatory spiders, timely monitoring of insect infestation, and rational use of insecticides.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5682", + "fact_text": "How did this condition spread -> The disease is mainly caused by the overwintering and survival of soil pathogens, especially in the form of oospores. Germs can germinate under suitable conditions and invade the host through zoospores or directly growing bud tubes. The speed of transmission may increase with the splashing of irrigation water or rainwater.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image3534", + "fact_text": "Is there any special phenomenon on the surface of the lesion -> In a humid environment, the surface of the lesion may produce a faintly visible dark brown mold layer. This is formed by the conidial stem and conidia of the pathogen.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5230", + "fact_text": "What is the impact of this pest on the growth and yield of cotton -> This type of pest can seriously affect the growth and yield of cotton, as the larvae feed on the seeds and fibers in cotton buds and bolls, causing the bolls to not develop properly and resulting in reduced yields. A larva can harm more than ten cotton buds and bolls during its life cycle.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "cucumber downy mildew 2", + "fact_text": "What disease is the leaf in the picture suffering from -> Cucumber Downy Mildew", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image795", + "fact_text": "Are there any other shaped lesions on plant leaves -> There are also spindle shaped to oval shaped lesions on the leaves, with the central area darker than the surrounding area and the patches appearing concave.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "wheat english grain aphid 427", + "fact_text": "What is the name of the insect in the picture -> English grain aphid", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4660", + "fact_text": "Can you see in the image that these pests have strong mobility -> Yes, this type of insect has a long winged shape, indicating strong flight ability, especially for females who have migratory characteristics. When the population density is high, they will migrate and transfer.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4445", + "fact_text": "I can see abnormalities in the roots of the crops. Can you provide a detailed explanation -> The crop roots in the image have been affected by diseases, resulting in a decrease in the number of roots and the occurrence of tumors and rotting roots. One type of nematode can cause root tumors, another type of nematode can cause brown spots on the roots, and the most severe can rot.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4471", + "fact_text": "What type of crop is displayed in the image -> The crop on the image is corn.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "wheat spindle streak mosaic disease 2", + "fact_text": "Can the toxic disease of Wheat Spindle Stream Mosaic Disease be transmitted through flowing water Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4790", + "fact_text": "Does the crop in the image appear healthy -> In the image, a type of pest appeared on leguminous crops, and due to the impact of the pest, the leaves and pods of the plants appeared yellow in the image.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3650", + "fact_text": "What impact do these spots have on the leaves -> As the disease spreads, the spots on the leaves will become dense, ultimately leading to rapid necrosis and withering of the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5603", + "fact_text": "Can you tell me how to prevent this disease when planting water chestnuts -> To effectively prevent this disease, implementing crop rotation, especially in old production areas for more than 3 years, is an economical and effective strategy. In addition, selecting disease resistant varieties and strengthening management, such as keeping the field small and separate irrigation and drainage, can reduce the spread and spread of diseases. Proper chemical treatment of seedlings before planting is also a recommended practice.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4264", + "fact_text": "So how did this disease spread and develop -> There are various ways of dissemination and development. The seed carrying rate is 59.7%, and the pathogen can invade the glume and rice grains, and can survive on the seeds until August September of the following year. Pathogens can also spread through rice straw, field water, and even organisms such as brown planthoppers, aphids, and leaf mites. They can invade through the growth points after seed germination and then expand; It can invade through wounds or natural openings such as pores and water holes. The optimal temperature for bacterial invasion and expansion is 30 ℃. The disease is severe under conditions such as imbalanced nitrogen phosphorus potassium ratio, excessive nitrogen fertilizer, too late or insufficient phosphorus, and insufficient fertilizer in the field.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4453", + "fact_text": "How to prevent and treat such nitrogen deficiency phenomena -> Nitrogen deficiency can be prevented and controlled by applying an appropriate amount of nitrogen fertilizer. At the same time, timely fertilization should be carried out based on soil testing results to ensure that plants receive sufficient nitrogen supply.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "corn leaf beetle 3", + "fact_text": "Does the insect's back shell in the picture have luster Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5244", + "fact_text": "What are its activity habits -> This insect is a widely distributed omnivorous pest. They overwinter on their host as pupae, and adults come out to move at night, exhibiting phototaxis. They mainly cause damage in the cotton areas of southern China from March to July, while in the cotton areas of northern China, they mainly cause damage in August.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image163", + "fact_text": "What are the manifestations of diseases at the roots -> Cloud streaks may appear at the root and stem, with dark brown edges and a light brown to light yellow color in the middle. These lesions may develop gray mold layers in high humidity environments.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5418", + "fact_text": "Are there any effective prevention and control methods -> There are two main methods of prevention and control. One way is by timely picking tea or peanuts, which can directly remove some eggs and nymphs, reduce their diet, and thus inhibit their development. Another method is to spray pesticides with insecticidal effects during the peak period of nymphs, such as dimethoate emulsion, phoxim emulsion, etc. It should be noted that prevention and control should be carried out as early as possible to avoid the occurrence of a large number of pests.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2639", + "fact_text": "What do these changes in leaves mean -> This indicates that cucumbers are experiencing nutrient deficiencies, specifically nitrogen deficiency, which can lead to changes in leaf color and slower growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4047", + "fact_text": "What preventive measures can be taken for this situation -> To prevent this situation, it is recommended to choose varieties that are resistant to low temperatures and weak light, control water and fertilizer management, especially reduce the use of nitrogen fertilizer, and maintain suitable night and day temperatures to promote normal differentiation of flower buds. At the same time, ensure that the planting soil is neither dry nor wet, especially under low temperature conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image1135", + "fact_text": "How to effectively prevent and control this disease -> Effective prevention and control methods include improving drainage and ventilation conditions, selecting disease resistant varieties reasonably, and adopting appropriate chemical and cultural measures, such as applying phosphorus and potassium fertilizers and selecting appropriate pesticides for spraying or root irrigation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "rice bacterial streak spot disease 3", + "fact_text": "What disease is causing the stripes on the leaves in the picture -> Rice bacterial stream spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "wheat powdery mildew 1", + "fact_text": "Which part of wheat is usually harmed by wheat powdery mildew Answer: Blades", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5243", + "fact_text": "What are the morphological characteristics of this pest -> The adult has a body length of 8-10mm and a wingspan of 19-25mm. Grayish brown with black spots on the head and chest. The front wings are grayish brown, with only double black stripes visible in the front section of the baseline; The inner horizontal line is double black, with a wavy outer slant; The sword pattern is a black stripe; Circular pink with black edges; Renal stripes are pink yellow, with a central brown color and black edges; Middle horizontal line black, wavy; The outer horizontal line is double black and serrated, with white lines between the front and rear ends; The Asian border line is white., Sawtooth shaped, with black dots on both sides, and a larger black dot on the outside at Ml; The edge line is a row of black dots, with white lining on the inside of each point. The hind wings are white, and the veins and edges are black brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4924", + "fact_text": "Do these diseases have any impact on the back of the leaves -> Yes, this disease causes the appearance of many white frost like conidiophores and conidia on the back of the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5407", + "fact_text": "Is there any way to prevent or treat this disease and pest -> For this type of pest and disease, we can use specific pesticides for spraying. For example, 50% acephate emulsion at 1000 times or 25% insecticidal water repellent at 400 times can be used for prevention and control. Other effective pesticides include 2.5% deltamethrin emulsion 2000-2500 times solution, 10% Doraemon suspension 1000 times solution, and 10% imidacloprid wettable powder 1000-1500 times solution.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "rice sheath blight 3", + "fact_text": "What factors are causing the spots in the picture -> Rice Sheath Flight", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5240", + "fact_text": "What are the morphological characteristics of insect pests -> The adult insect has a body length of about 20mm, wings spread 40-50mm, all white, with a silky luster, and black and white ring patterns on the tibia and appendages of the foot. Egg Mantou shaped, gray white, stacked in blocks, covered with foam like white glue. The last instar larvae have a body length of about 50mm and a gray black mixed with yellow on their back; The back line is brown, with black brown on both sides, and each section of the body has nodular protrusions, on which clusters of yellow white long hair grow. The pupa is 20mm long, black brown in color, and has light yellow fine hairs on top.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5198", + "fact_text": "Under what conditions will this situation worsen -> This situation is usually more severe during the hot summer season, especially from July to August. In addition, excessive use of nitrogen fertilizer can lead to more serious diseases in mulberry orchards.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image4949", + "fact_text": "How is this disease caused -> This disease is caused by southern root knot nematodes. This type of nematode is dioecious, and its larvae are slender and worm like. Male adults are relatively small, with a slightly round tail and colorless transparency. Female adults are larger, and each female nematode can lay 300-800 eggs. Most of the time, they are buried in the host tissue. When in contact with a suitable host, nematodes invade the root tips of the host, and their secretions stimulate the expansion of root cells, causing the formation of giant cells in the roots, which is what we see as root nodules.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3510", + "fact_text": "Can you describe the environmental conditions under which the disease occurred in the following picture -> The occurrence of diseases shown in the image tends to intensify under high temperature and humid conditions. Especially in the middle and later stages of plant growth, if encountering frequent weather such as rain, dew, and fog, it will be conducive to the expansion and spread of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image668", + "fact_text": "What are the common ways of transmission of this disease -> This disease is spread through spores splashed by rainwater.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1076", + "fact_text": "Is there a treatment method that can alleviate this condition -> Cultivation measures such as crop rotation and timely drainage can be adopted. At the same time, regular spray treatment of leaves at the beginning of the disease will help control the disease development.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "wheat english grain aphid 518", + "fact_text": "Which part of the insect in the picture is red Answer: Eyes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image709", + "fact_text": "Can you see other parts of the plants in the picture -> Part of the stem can be seen, and there may also be similar irregular spots or bacterial film covering the stem.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato yellow leaf curl virus 555", + "fact_text": "Is tomato yellow leaf curl virus disease contagious Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5278", + "fact_text": "What crops will be affected by this pest in the image -> This type of pest mainly affects crops such as password, xanthium, hops, etc.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2176", + "fact_text": "What are the symptoms of the aboveground parts of the plants in the image -> The growth of the aboveground parts of the plant gradually weakens, and the leaves gradually turn yellow and wither from bottom to top, with a decrease in the number of fruits and a smaller fruit volume.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4463", + "fact_text": "What factors may be causing this situation -> These symptoms may be caused by the use of pesticides or herbicides exceeding a certain concentration, or by excessive application of fertilizers or insecticides during sowing. In addition, excessive soluble nitrogen, potassium and other fertilizers can also inhibit seed germination when they approach the seeds.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "vitis erythroneura apicalis 53", + "fact_text": "What is the white creature on the leaves in the picture -> Grape Two Star Leaf Cicada", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4179", + "fact_text": "How will these spots affect the overall morphology of the leaves -> These spots may develop into long black brown spots along the leaf veins during the expansion process, which can cause the leaves to distort or shrink. In severe cases, leaves may experience yellowing and early wilting.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "beet spot flies 299", + "fact_text": "Is the appearance of the insect in the picture a long oval shape Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image3759", + "fact_text": "What are the preventive measures for this situation -> Effective preventive measures include using disease-free species of Platycodon grandiflorus, sowing at appropriate times, treating seeds before sowing, and strengthening management and increasing potassium fertilizer application during growth to improve plant disease resistance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5270", + "fact_text": "What kind of damage will this insect cause to crops -> In the image, this organism can cause significant harm to cotton seedlings, and in severe cases, they can bite off the petioles and erode the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "corn mole cricket 14", + "fact_text": "What is the name of the insect in the picture Answer: Mole cracket", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image13", + "fact_text": "How can we prevent and treat this pest -> We can adopt a combination of agricultural and chemical methods for prevention and control. In terms of agricultural prevention and control, we need to pay attention to cleaning up orchards and overwintering areas outside the orchard. In terms of pesticide control, we can apply 25 % phoxim capsule or 50 % phoxim emulsion 0.8 - 1 kg each time from mid June to mid July. Add 50 - 90 times water and spray evenly under the tree crown, or mix 5 times water with 300 times fine soil to make toxic soil, sprinkle it under the tree crown, and rake the soil in time to prevent photodegradation after application. During the period of larval emergence, the best effect is to apply the pesticide 2 - 3 days after encountering rainfall. During the peak spawning period after adult emergence, timely spraying is also necessary. Generally, spraying should be done once from mid to late July to early August, using 2.5 % Kung Fu emulsion 3000 - 4000 times liquid or 2.5 % Dichlor emulsion 3000 - 4000 times liquid.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3605", + "fact_text": "How do the leaves of scallions look -> The leaves start yellowing from the top and gradually wither downwards.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4741", + "fact_text": "At which time of the year is this pest most active -> Usually, larvae appear in June and July and continue until August to September. In some years, if the population of insects is large, adults inhabit sugar beets, soybeans, flax, and alfalfa fields or forage for nectar.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4771", + "fact_text": "How does this insect reproduce in different geopictureical regions -> This type of insect has different reproductive cycles in different geopictureical regions. The area north of Beijing usually gives birth to one generation every year. In the Bohai Bay, the lower reaches of the Yellow River, and the Yangtze River basin, two generations are born each year, and in a few years, even three generations may be born. In Guangxi, Guangdong, and Taiwan, three generations are born each year, while in Hainan, four generations may be born. Insects in all regions spend the winter in the soil with their eggs.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3701", + "fact_text": "What are the methods for preventing and controlling this disease -> Effective methods include selecting resistant varieties, timely removing diseased plants, and using the recommended pesticide spray at the beginning of the disease, such as 69% Anke manganese zinc wettable powder.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "tomato mosaic virus 1476", + "fact_text": "Are there uneven green spots on the leaves in the picture Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "mango flat beak 15", + "fact_text": "Is this creature in the picture gnawing on leaves Answer: No", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2536", + "fact_text": "Do the melon crops in the image show any unusual signs -> The crops in the image exhibit dark green waterlogged changes in their young stems and leaves, which quickly show signs of decay.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image1130", + "fact_text": "What are the unfavorable factors that affect the growth of eggplants -> Adverse factors include large temperature fluctuations, excessive use of nitrogen fertilizers, and inappropriate water management.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4518", + "fact_text": "What is the plant shown in the image -> The image shows a type of miscellaneous grain called sorghum.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4520", + "fact_text": "What are the specific measures for early disease control -> In the early stages of the disease, specific pesticides can be sprayed, such as 500 times solution of 58% Metformin Β· Manganese Zinc wettable powder or 600-700 times solution of 75% Chlorothalonil wettable powder, every 7 days, and prevention and control should be carried out once or twice according to the situation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5676", + "fact_text": "Under what conditions are these nematodes usually active -> This type of nematode is very active when soil moisture is suitable, especially at temperatures between 25 and 30 degrees Celsius. But their activity will be restricted when the temperature is above 40 degrees Celsius or below 5 degrees Celsius.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image906", + "fact_text": "Will this situation have any different manifestations when the environment changes -> Yes, in environments with high humidity, these lesions will produce a gray green mold layer.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2482", + "fact_text": "What are the manifestations of the petioles and stems of plants -> The petiole and base of the stem are covered with light brown disease spots, showing watery characteristics, indicating that the disease has begun to spread downwards.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2548", + "fact_text": "Are there any other symptoms in the image indicating that the plant has been compressed or affected by adverse environmental conditions -> The zucchini plants in the image may exhibit overall growth restriction and poor fruit development, possibly due to inhibition of root respiration or poor ventilation and light transmission.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4751", + "fact_text": "What is the texture of the crops in the image -> Crops that have been damaged by the double squad leader Peng Yingye beetle may exhibit changes in texture. Before heading, normal foxtail millet is only affected by the double squad leader, the firefly beetle, which gnaws on the leaf flesh and leaves the epidermis, which may result in the texture of the affected part being rougher than that of the unaffected part. On the other hand, this pest infestation mainly concentrates on the ear after heading, and the tender ear may induce bending, forming unusual texture or cracking.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4194", + "fact_text": "At what time period are the leaves in the image more prone to this situation -> Usually in August, this situation enters the peak period of the disease, as the activity of the bacteria increases during this period.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "cucumber target spot 1", + "fact_text": "What diseases have affected the leaves in the picture -> Cucumber target spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2825", + "fact_text": "What are the characteristics of the soil types in the picture that may lead to potassium deficiency -> The soil in the picture may belong to sandy soil, where potassium is easily leached out, resulting in low available potassium content and causing potassium deficiency symptoms in the plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4408", + "fact_text": "How does the barley in the image look -> The image shows that crops are facing some problems, which appear to be symptoms of nutrient deficiency.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2159", + "fact_text": "What preventive measures can be taken for this situation -> When using relevant chemical substances to treat crops, the concentration should be strictly controlled and attention should be paid to the spraying method, especially to avoid liquid contact with the heart leaves to reduce this impact.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4703", + "fact_text": "Are there any objects in the image that are destructive to crops -> Yes, the barley in the image has been affected by pests, especially the damage caused by the wheat concave shin jump beetle.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato canker 18", + "fact_text": "Will there be \"bird eye like\" spots on the surface of tomatoes infected with Tomato Canker Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3399", + "fact_text": "What are the preventive measures for this situation -> Prevention and control measures include using disease-free soil for seedling cultivation, deep plowing and high-temperature disinfection of severely affected plots, and using chemical treatments to control the growth and reproduction of nematodes in the soil.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4736", + "fact_text": "Can you describe the impact caused by this pest -> Adults and nymphs of this pest infestation feed on the tender parts of crops, and in severe cases, it can cause shrinkage of tender leaves and shoots, affecting crop growth. In some areas, the damage caused by this pest is indeed very serious.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image4705", + "fact_text": "Under what conditions does this pest overwinter -> This type of pest chooses to overwinter at the base of Acanthopanax splendens (a type of weed). When the wheat matures, it will fly back to the overwintering weeds and begin to hibernate around October.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4951", + "fact_text": "Under what conditions is this disease more likely to occur -> When encountering hot and humid weather, or in low-lying areas, this disease is more prone to occur. At the same time, excessive application of nitrogen fertilizer or in long-term continuous cropping fields can also make the disease more prone to occur.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5805", + "fact_text": "Is there any obvious damage or abnormality on the crop leaves in the image -> There are significant signs of invasion on the main trunk and larger branches of the crops in the image, which appear to be tunnel damage caused by insect infestation, accompanied by the overflow of some resin.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5268", + "fact_text": "How to prevent and deal with this pest -> There are multiple ways to prevent and deal with this pest. Firstly, ensure thorough disinfection during seedling cultivation and remove all pests before planting. Secondly, when pest infestations first appear, specific drugs can be used for treatment, such as glyphosate and methamphetamine. For crops in greenhouses, it is also feasible to use smoke emitters to release smoke agents. Of course, the best prevention and control method is to avoid the entry of crop seeds and cuttings carrying pests and diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image447", + "fact_text": "How will this disease develop in humid climate conditions -> In warm and humid weather, this disease is prone to occur and accelerate its development, as these conditions facilitate the growth and spread of pathogens.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tea brown blight 92", + "fact_text": "What factors are causing the abnormal phenomenon on the surface of the blade in the picture -> Tea brown light", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "wheat stem rust 355", + "fact_text": "Does the prevalence of Wheat stem rust mainly depend on the influence of environmental conditions and farming systems Answer: No", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5712", + "fact_text": "What effective methods are there to prevent this problem -> Effective methods include timely eradication of aphids, especially during their migration, using specific pesticides for continuous spraying to control aphid numbers, and strengthening overall plant management, such as regularly using pesticides to enhance plant growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1005", + "fact_text": "What methods are commonly used to treat this condition -> Common treatment methods include timely removal of diseased plants, avoiding excessively humid conditions, and using specific pesticides such as carbendazim for spraying.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2309", + "fact_text": "How to prevent and deal with this situation -> Disease tolerant or resistant varieties should be selected, and co cropping with other crops with high calcium requirements should be avoided. Inject water in moderation and keep the soil moist. Reasonably apply nitrogen, phosphorus, and potassium fertilizers, and increase the application of organic fertilizers to improve soil organic matter content. Spray calcium and manganese fertilizers on the leaves, and use calcium containing granular fertilizers in moderation during the heading period.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image3649", + "fact_text": "How did this situation arise -> Diseases are mainly caused by the infection of thick walled spores or mycelium produced by pathogens in the soil, especially on soil with immature organic fertilizers or heavy soil viscosity.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1802", + "fact_text": "What are the additional phenomena of disease spots on leaf stems under high humidity conditions -> In high humidity conditions, red sticky substances will appear on the surface of the disease spots on the leaf stems.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image1499", + "fact_text": "So what is the pathogen of this disease -> This disease is caused by a bacterium called the edge pathogenic variant of Pseudomonas aeruginosa, which is aerobic and can produce green fluorescence on specific culture media.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image1123", + "fact_text": "What is this white cotton like thing in the picture -> That is white hyphae, indicating that the infected area of the plant is actively developing pathogens.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4959", + "fact_text": "Is there any way to prevent and treat this disease -> Effective measures can be taken to prevent this condition. For example, selecting varieties with disease resistance and high yield, such as Xiangzhu 2, Heipi Dou, Hongpi Xiaoma, etc., can be promoted according to local conditions in various regions. When expanding new varieties of ramie, asexual reproductive materials such as disease-free roots, ramets, and tender shoots are used. It is strictly prohibited for diseased plants and seedlings to enter the disease-free area. Strengthen the management of hemp fields, appropriately increase the application of phosphorus and potassium fertilizers, and avoid excessive application of nitrogen fertilizers. During the peak period of nymphs in cicadas (July September), relevant insecticides are sprayed to achieve the effect of pest control and disease prevention.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5354", + "fact_text": "Can we see specific traces of pest infestation -> Yes, in the image, there are obvious symptoms of the root and surrounding vegetable edges being eroded. The affected vegetable plants have poor development, deformities or shedding of the outer lining, resulting in reduced yield and inferior quality. If the pest infestation is severe, it may even cause the roots to be completely eroded and withered.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image1989", + "fact_text": "What causes excessive growth -> Overgrowth may be caused by excessive planting density or excessive fertilization, especially nitrogen fertilizer, which allows plants to compete for sunlight and grow too high and fragile.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4743", + "fact_text": "So what are the effective methods for preventing and controlling this pest -> The methods for preventing and controlling pests include: optimizing sowing time to avoid the peak breeding period of pests; Identify the types and periods of medication based on prediction and pest control; Use specific pesticides to soak and mix seeds for pest control during seedling stage. In addition, when corn enters the jointing stage or central aphid plants are found, special pesticides can be sprayed for control. If it is severe, toxic sand can be sprayed for whole field treatment, or specific chemicals can be used to irrigate the corn heart or horn mouth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5357", + "fact_text": "Where is its damage to crops mainly reflected -> The adults of this pest will feed on leaves, and specific damage can be found in the yellow striped flea beetle.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1024", + "fact_text": "Under what conditions does this situation usually worsen -> Under conditions of high humidity and high numbers of whiteflies, this situation is prone to exacerbation. Adverse weather conditions and the presence of disease vectors can promote the spread and spread of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image3489", + "fact_text": "What are the characteristics of the fleshy part on the surface of the diseased potato block -> The subcutaneous flesh of the diseased part of the potato block appears light brown to dark brown, which may eventually cause the potato block to rot.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4076", + "fact_text": "Does nutrient element have an impact on tomato cracking in the image -> Indeed, if there is insufficient supply of calcium and boron in the soil in the image, it will affect the fruit's crack resistance, so it is necessary to supplement these nutrients appropriately.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image4689", + "fact_text": "What specific type of pest is that -> I cannot provide a specific pest name, but this type of pest has a body length of approximately 1.9mm, is ovoid in width, has no wings, but has long and black antennae, with a length exceeding half of its body length. The living body is black green, embedded with yellow green stripes, and covered with thin powder. There are rust colored lines around the base of its abdomen.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3061", + "fact_text": "When is this situation most common in a year -> This situation is more common when the temperature is low, especially between 5 and 28 degrees Celsius, where 11 to 23 degrees Celsius is the suitable temperature range for disease outbreaks.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5079", + "fact_text": "What type of problem is image display -> This image mainly shows the problem of phosphorus deficiency in plants. Phosphorus deficiency can darken leaves, hinder the development of leaves and stems, and affect the overall growth of plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3164", + "fact_text": "What impact will this situation have on the commercial value of corms -> The cracks and abnormal growth of this type of bulb will significantly reduce its commercial value, as it not only affects its appearance, but may also affect its internal quality and taste.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tea bird eye spot 402", + "fact_text": "Which organ of the tea tree does tea bird eye spot mainly occur on Answer: Blades", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2358", + "fact_text": "Can plants recover in the event of such diseases -> As shown in the picture, if wilting symptoms occur frequently and repeatedly, cucumber plants may eventually be unable to return to normal growth and may die due to the inability to maintain normal water and nutrient transport.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5364", + "fact_text": "How should we prevent and control this pest -> After harvesting cruciferous vegetables, immediate tillage and weeding should be carried out to destroy and expose the source of pests. Planting some vulnerable crops early can also help avoid periods when larvae appear in large numbers. If pest infestation is found, appropriate pesticides can be sprayed during the larval stage, such as 50% phoxim emulsion at 1500 times, 35% phoxim emulsion, or 50% malathion emulsion at 1000 times, to prevent further damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5395", + "fact_text": "What does the adult insect in the picture look like -> Adults are deep purple black, with a body length of approximately 3.2 to 3.5 millimeters, and have filamentous brown antennae and light grayish brown forewings. The front wings are covered with gray black fur, which may give them a special shine under light.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "wheat penthaleus major 54", + "fact_text": "How many generations can the insect in the picture reproduce in a year Answer: Generation 2-3", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "citrus nipaecoccus vastalor 7", + "fact_text": "What is the color of the insect in the picture Answer: White", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image1154", + "fact_text": "What is the plant growth environment in the image -> The plants in the image grow in environments that may have poor drainage and excessive use of nitrogen fertilizer, which promote the occurrence of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5520", + "fact_text": "What is the lifecycle of this pest -> This type of insect is born once a year, with females overwintering on tea tree branches. They start laying eggs in late May of the following year, and nymphs begin to appear in early June. It is not until late August to early September that male adults begin to emerge.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image1957", + "fact_text": "What is the reason for this situation -> This is caused by a lack of calcium in the plant body, and excessive use of nitrogen fertilizer can also inhibit the plant's absorption of calcium.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4747", + "fact_text": "Does the image display the harm of pests and diseases on crops -> The information provided by structured knowledge indicates that the harmful characteristics of this pest include feeding on the epidermal tissue of seedling leaves. In addition, when it occurs seriously, it may cause seedling deficiency, ridge breakage, and even seed destruction. Therefore, if the image shows damaged crops, we can infer the harm of the pests and diseases displayed in the image on the crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5387", + "fact_text": "What is the condition of damaged pods in this image -> After the pod in the image is invaded by insect larvae, obvious boreholes and silk sacs produced by the larvae can be seen. This kind of damage is mainly caused by the larvae moving inside the pods and biting the seeds, affecting the normal development of the pods and ultimately causing adverse effects on yield and quality.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5361", + "fact_text": "What are the morphological features of this insect in the image -> The insect in the image has a body length of 5-6 millimeters and a width of 3-3.5 millimeters, with an elongated circular shape ranging from brown yellow to brown red. There is a longitudinal band in the center of the head, and the middle part of the chest and back plate, the small shield, most of the central part of its Coleoptera, the middle of the abdomen, the back chest and belly plate, and the feet are all blue black with a slight copper green luster. The antennae are black, with a slight red base. Its head is arched, with deeper and denser markings. The antennae are longer and extend backwards beyond the base of the Coleoptera. The third segment is slightly longer than the fourth segment, and the end 6 segments of the antennae are significantly thickened and slightly shorter. The width of the anterior chest and back plate is about twice the length, with the base slightly arched backwards and the side edges straightened; The surface has quite thick and deep grooves, with a slightly sparse black spot in the middle and dense on both sides. The small shield is tongue shaped and has almost no notches. The marks on the Coleoptera are quite thick, dense, and chaotic.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4665", + "fact_text": "How to prevent and control this pest -> The prevention and control methods include removing fallen leaves and weeds to reduce the source of pests. After mastering the migration of adult insects and the peak hatching period of each generation of nymphs, relevant pesticides should be sprayed in a timely manner, such as 20% Yechan San emulsion 800 times solution or 25% Sumitovir wettable powder 600-800 times solution.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tea algal leaf 338", + "fact_text": "What disease has invaded the leaves in the picture -> Tea algae leaf spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5556", + "fact_text": "What is the color of the plant leaves in the image -> In the image, there are yellow white lesions on the leaves of the plant, with less obvious edges.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5289", + "fact_text": "What do the creatures in the image look like -> The creature in the image is a pest of cotton and linen. The length of the insect body is approximately 14 to 16mm, with wings spread between 25 and 38mm, and the overall appearance is grayish brown. The features of the forewings are prominent, with brown dotted markings and large kidney shaped spots. The hind wings have significant black patches and wide black bands.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image25", + "fact_text": "Are there any preventive measures for this disease -> Yes, some measures can be taken to prevent and control this disease. Agricultural prevention and control mainly includes strengthening fertilizer and water management, enhancing tree vigor, and timely disinfection of pruning tools after use. For trees with severe illnesses, it is better to promptly remove them instead of letting them continue to infect other healthy trees. In addition, some chemical agents can also be used to prevent and control diseases, such as spraying 1.5 % Phytophthora flavescens emulsion 1000 times solution during leaf expansion, or 20 % Hydrochloric Acid Metformin? Copper wettable powder 4000 times liquid, or 0.05%~0.1 % rare earth nitrate, sprayed every 15 - 20 days for 2 - 3 consecutive times. Spraying the fruit again before harvesting also has a good disease prevention effect.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4691", + "fact_text": "How does this pest affect crop growth -> Insect infestation mainly occurs by piercing and sucking on plant tissue sap, disrupting normal plant growth, causing leaf discoloration, and even affecting crop photosynthesis and grain weight, reducing crop yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1555", + "fact_text": "What chemicals are recommended for preventing and treating this disease -> It is recommended to use pesticides such as chlorpyrifos, tektor (thiamethoxazole), or chlorothalonil. Attention should be paid to the rotation of pesticides to reduce the development of drug resistance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4728", + "fact_text": "Can the corn in this image continue to grow -> For the situation in the image, it is necessary to observe the crops on site to determine whether they can still recover their growth. However, from the perspective of typical insect infestations, crops in this situation may not be able to recover normal growth because damage caused by eating the stem marrow is often fatal.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4431", + "fact_text": "Can we determine the possible transmission route of this disease based on images -> Based on the given knowledge, the bacteria mainly overwinter on diseased seeds or straw using their conidia, and the following year produce conidia that spread with the wind. But it is not directly known from the images that these are all based on the analysis of symptoms and known information.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image3104", + "fact_text": "How does boron deficiency in soil occur -> The deficiency of boron in soil may be caused by soil acidification, excessive leaching of boron, or excessive application of lime. Meanwhile, if the soil is in a dry state, or if there is insufficient application of organic fertilizer or excessive use of potassium fertilizer, it may lead to insufficient boron absorption.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image828", + "fact_text": "What are the transmission pathways of plants in the image -> Pathogens may overwinter in the soil through diseased residues, and then spread in spring through rainwater splashing, affecting new plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5384", + "fact_text": "Do these insects have any special behavioral habits -> Yes, this type of insect is most active from 21 to 22 in the evening and 7 to 8 in the morning. They also come out and move on cloudy days, exhibiting negative phototaxis and pseudostillness. When frightened, they will curl up into a spherical shape.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2219", + "fact_text": "Under what environmental conditions do the plants in the picture grow -> The plants in the image may grow in high temperature and rainy environments, which can contribute to the development of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image187", + "fact_text": "So, how to prevent and control this situation -> An effective prevention and control method is to promptly remove and destroy disease residues to prevent pathogenic bacteria from remaining in the soil. In addition, appropriate crop rotation and increased application of potassium fertilizer can also enhance plant disease resistance. If necessary, specific pesticides can also be sprayed to control diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3118", + "fact_text": "So what is the possible impact of the field environment in the image on this situation -> If the environmental conditions in the field depicted in the image are harsh, such as drought, low rainfall, and high soil temperature, coupled with weak plant growth or root damage, it may promote the occurrence of this symptom.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3021", + "fact_text": "Do the plants in the picture look firm -> No, the plant looks very unstable and may collapse upon slight contact, usually due to severe rot at the base of the stem.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5263", + "fact_text": "What is the annual activity cycle of this pest -> This type of pest produces 5 generations per year and winters with eggs in the dead branches and pulp of various plants. The eggs begin to hatch in the following spring, and the nymphs begin to damage the young shoots or leaves of overwintering hosts. They then transfer to other crops and weeds for feeding, and gradually expand to harm the hemp fields. After early September, the hemp plants aged, and the adults migrated to overwintering hosts to lay eggs.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4774", + "fact_text": "Can you provide some methods on how to prevent this pest -> Of course you can. There are several methods to prevent this type of pest: (1) eradicate nearby weeds such as small pods and fragrant silk grass, and remove residual host plants and fruits from the melon and vegetable fields. (2) During the damage period, especially during the peak damage period, if a \"small ant hill\" is found in the area or leaf blight is first seen, immediately spray the area with a 1500 fold solution of 25% chlorpyrifos emulsion; Once every 10 days or so, use three times in a row. (3) Using \"Bee Killing Cockroach (Armor) Ant Medicine\", abbreviated as \"Cockroach Killing Medicine\", 1-3 tubes are used every 15m, with 2g per tube, divided into 10 to 30 piles. In areas with high humidity, the medicine can be placed on the inside of glass bottles to lure and kill ants for a long time, and can also be used to treat bee cockroaches. (4) Pour 90% crystal trichlorfon and lime in a 1:1 ratio of 4000 times water solution, and pour 0.6kg of the right medicine solution into each nest. The prevention effect is 100%. Stop using the medicine 7 days before harvesting.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1736", + "fact_text": "What are the possible reasons for this situation to occur -> This may be due to prolonged high temperature and drought, which reduces the disease resistance of Chinese cabbage, coupled with the invasion of viruses.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4987", + "fact_text": "What does the peanut plant in the image look like -> The base of the peanut plant in the image begins to show some sunken yellow brown spots, while the edges are brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "citrus toxoptera aurantii 134", + "fact_text": "What is the scientific name of the insect in the picture -> Toxoptera aurantii", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3988", + "fact_text": "What are the effects of these color changes on chicken leg mushrooms -> This color change may be a pathological indicator, as the disease progresses, the mushroom body can become stiff and the quality may decrease, seriously affecting its product quality.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5375", + "fact_text": "What are the methods for preventing and controlling this pest -> Adults can be lured and killed by timely removing weeds in mulberry orchards, installing black light lamps or using attractants. The newly hatched larvae should be promptly eradicated, and chemical insecticides should be used appropriately to control the number of pests.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4979", + "fact_text": "So how do we prevent and deal with this disease -> There are several methods to prevent and treat this disease: (1) implement rotation for more than 3 years, (2) timely remove diseased residues after harvest, and deep plow in a timely manner, (3) in the early stage of the disease, spray 50% benzimidazole wettable powder 1500 times solution, 36% methylthiophanate suspension 600 times solution, and 50% carbendazim wettable powder 800 times solution.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5331", + "fact_text": "Are there any effective preventive measures -> Generally speaking, biological control, chemical control, and physiological control methods can be used. Biological control mainly uses bacterial insecticides; Corresponding drugs can be selected for chemical prevention and control; Physiological control mainly uses insect growth regulators, which have a slow effect and usually cause death to pests when the insect age changes. Therefore, early spraying is necessary.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image386", + "fact_text": "Will curling of leaves occur naturally during seasonal changes -> The situation in the figure shows that it may mainly occur in the later stage of growth, especially in situations of high temperature, water shortage, or improper field management.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3934", + "fact_text": "What are the characteristics of the mushroom cap -> This type of mushroom has a smaller cap, and due to overcrowding, their shape is often not very regular, and the edges may appear somewhat uneven or curly.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "rice leaf smut 2", + "fact_text": "What kind of disease has invaded the leaves in the picture -> Rice leaf smut disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4649", + "fact_text": "So are there any effective prevention and control methods -> For the prevention measures of this insect, you can refer to the prevention and control measures of rice thorn edge melting.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5170", + "fact_text": "Are there any other marks or spots on these leaves -> Yes, some leaves can be seen to have brown spots, and in severe cases, white spots may even begin to form.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image3463", + "fact_text": "What impact will this necrotic spot have on plants -> This type of necrotic spot can cause the petioles to gradually rot, seriously affecting the nutrient delivery of plants and causing damage to their overall health.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4785", + "fact_text": "How to prevent and control this pest -> Firstly, in agricultural prevention and control, attention should be paid to clearing weeds in the field and at the edge of the field. This can be achieved by utilizing their tendency towards black light lamps and sex attractants, and setting up equipment to attract adult insects in the field to ensure that selective treatment is carried out during the local occurrence stage before the third instar. In addition, medication can also be used for prevention and treatment, such as using 5% Yitaibao emulsion at a ratio of 2000 to 2500 times or 5% Carboxycycline emulsion at a ratio of 2000 to 2500 times. It can be used alone or alternately.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4706", + "fact_text": "What preventive method do you recommend to deal with this pest problem -> For this type of pest, chemical control can be used. You can choose to spray 20% of the 2000 fold solution of Mizumab emulsion, or 50% of the 2000 fold solution of the super wettable powder of Mizumab, or 40.7% of the 1500 fold solution of Lesbourne emulsion, as well as 50% of the 1500 fold solution of Phoxim emulsion and 2.5% of the 2500 fold solution of Baode emulsion.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "rice leaf smut 3", + "fact_text": "What kind of disease has affected the leaves in the picture -> Rice leaf smut disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4339", + "fact_text": "What are the transmission routes and preventive measures for this disease -> The pathogens in the winter wheat area mainly overwinter on the diseased residues of wheat, and also infect the wheat seedlings sown in autumn. To prevent and control this disease, one can choose wheat varieties that are resistant to disease or disease, such as Yangmai 1, Niumi Te, Hezuo 2, 3, 4, etc. In addition, deep tillage and crop removal, removal of diseased residues, avoidance of premature sowing of winter wheat, use of decomposed organic fertilizers and phosphorus and potassium fertilizers, and proper rotation are also necessary agricultural prevention and control measures. If necessary, appropriate pesticides can also be used for prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4451", + "fact_text": "How will these symptoms affect the overall health of plants -> These symptoms usually indicate problems with nutrient absorption in plants, which may lead to growth inhibition and weakened disease resistance in the long run, thereby affecting yield and overall crop quality.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4313", + "fact_text": "What is the situation where the rice leaves in the image appear yellow green and relatively short -> This situation is usually related to nitrogen deficiency in rice. Rice leaves appear yellow green and the plants are short, usually due to a lack of nitrogen fertilizer.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tea bird eye spot 401", + "fact_text": "How does a Tea bird eye spot spread Answer: Wind and rain", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image20", + "fact_text": "What is the cause of this disease -> This disease is caused by a bacterium called Acrospermum viticola IKata, which belongs to the subfamily Ascomycota and the genus Actinobacteria. This pathogen can form conidia and ascospores. Conidia originate from the mycelium on the disease spot, and in the later stage, the pathogen generally invades from the stomata on the back of the leaves. After the onset of the disease, conidia are produced for re infection.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "citrus toxoptera aurantii 134", + "fact_text": "Is there any insect present in this picture Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato verticulium wilt 506", + "fact_text": "Can Tomato verticillium wilt be spread through seeds Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5367", + "fact_text": "How should we deal with this pest -> According to the suggestions, we should adopt a comprehensive approach of coordinating rational drug use with the protection and utilization of natural enemies, using agents with different mechanisms of action, alternating without cross resistance, and mixing insecticides and synergists for prevention and control. In addition, it is important to strictly limit the frequency and dosage of application of new pesticides to prevent insect resistance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5405", + "fact_text": "Can these insects also affect the flowers or pods of crops -> Yes, the insects in the picture can also damage the flowers and pods of crops in certain situations, leading to a decrease in the number of pods.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image17", + "fact_text": "What are the conditions for the onset of this disease -> After planting in winter and spring, sugarcane often suffers from plant deficiency due to slow germination, weak disease resistance, and high humidity caused by low temperature, cloudy and rainy conditions. When the soil moisture is high or the weather is dry, sugarcane is prone to injury, which is conducive to the invasion of pathogens. The ratio of nitrogen, phosphorus, and potassium in soil can affect the occurrence of sugarcane red rot, and the disease index increases with the increase of nitrogen ratio and decreases with the increase of phosphorus ratio. Severe infestations by borers and planthoppers are prone to disease, and areas with frequent storms or acidic soil are also prone to severe diseases.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image1152", + "fact_text": "When is this disease usually more likely to occur -> This type of disease is more common in humid environments, especially during continuous rainy seasons or when drainage is not timely after irrigation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image484", + "fact_text": "Will these small spots on the leaves affect the structure of the entire leaf -> Yes, these spots are small, numerous, and may cause thinning of the leaves, which can easily lead to leaf rupture, perforation, or detachment in the later stage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5337", + "fact_text": "What are the activity habits of this organism -> It is mainly distributed in the northwest and southwest regions of China, especially in Xinjiang where the pest situation is more severe. The development cycle of its eggs, larvae, and pupae varies with season and temperature, and the growth process mainly occurs during the day. The eggs of this organism will be laid in clusters on the leaf surface, and each female organism can produce 2-3 clusters, with 50-80 grains per cluster. When they are still newly hatched larvae, they gather together to damage crops and then disperse to surrounding vegetable plants for feeding. After maturity, these larvae will pupate on the leaves or stems of the host plant and overwinter.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4667", + "fact_text": "Can you see specific insect infestations in the image -> Yes, the specific effects of this pest can be observed in the image. The leaves caused by pests and diseases show yellowish white fine spots, and the two wings of the leaf tip curl inward, resulting in yellowing of the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "corn grub 698", + "fact_text": "Is the crop in the picture in a Healthy state Answer: No", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image1919", + "fact_text": "What type of leaves are the crops in the image -> The crop in the image belongs to the cabbage class, specifically, it is mustard.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4688", + "fact_text": "How can we prevent and control this pest -> The main prevention and control methods include: prediction and prediction, and immediate prevention and control after the average insect population of one hundred plants reaches a certain amount. We can also adjust the sowing mode, choose insect resistant varieties, and fertilize and water reasonably. Furthermore, we can use natural enemies such as ladybugs, aphids, grasshoppers, and aphid cocoons for biological control. If the above methods are ineffective, chemical pesticides can be used appropriately, but attention should be paid to protecting crops and the surrounding environment.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image473", + "fact_text": "How to prevent similar diseases when cultivating this crop -> Preventive measures include using new soil for seedling cultivation, crop rotation with non Solanaceae crops, controlling cultivation density, and enhancing ventilation, especially in low temperature and high humidity weather conditions. In addition, timely removal of diseased branches, leaves, and fruits is necessary to further control the spread of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image361", + "fact_text": "Is this phenomenon related to climate -> It has a significant relationship. For example, continuous rainy and high humidity climates can affect the absorption of nutrients, especially potassium and boron, thereby inducing this situation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4462", + "fact_text": "What solutions can alleviate or prevent this situation from happening -> There are multiple methods to prevent this disease, including selecting areas with high terrain and good drainage performance to plant crops. If in areas with high rainfall and easy flooding, a good field drainage system should be established. In addition, basic fertilizers can be applied to improve the flood resistance of crops, and flood tolerant crop varieties can also be selected for planting. If waterlogging has already occurred, immediately cultivate and loosen the soil and apply quick acting nitrogen fertilizer to help crops recover growth as soon as possible.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1319", + "fact_text": "How do the tender stems and tendrils in the image appear -> In the early stage, tender stems may appear watery green fading, and later turn into dark green elongated lesions, which may be concave and cracked. The tendrils will turn brown and rot.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4705", + "fact_text": "Is there anything special about their reproduction and living habits -> This type of pest can produce 2-3 generations a year, and the adults overwinter at the base of the withered grass. It usually starts to move in late April and migrates to wheat fields in early May. Adults usually lay eggs on the lower leaf tips of wheat seedlings or on the remaining leaves of withered tree branches on the ground. Each egg sac has approximately 11-12 eggs, and they hatch into nymphs in mid May.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4804", + "fact_text": "What do the antennae of insects look like -> The antennae of insects are hammer shaped, with a total of 11 segments, and the last three segments of the hammer end are significantly enlarged.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "grape powdery mildew 215", + "fact_text": "What disease is causing this -> Grape powder mildew", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4670", + "fact_text": "What are the characteristics of pest activity on crops -> Pests often move within the heart and leaves of the host plant, and when feeding on extended leaves, they often feed on the front of the leaves, resulting in patches of silver gray spots on the leaves. If there are numerous pests, severe damage may cause a large number of dead seedlings.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image734", + "fact_text": "Are there any effective prevention methods -> Effective prevention methods include centralized planting in large areas, timely sowing to cultivate strong seedlings, and intercropping with garlic to avoid aphids and prevent diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5053", + "fact_text": "What color changes do the plants in the image exhibit -> The leaves and tender pods of the plants in the image show a gradually yellowing phenomenon from bottom to top, and exhibit a burnt like withered yellow color.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image728", + "fact_text": "What is the overall growth status of cowpea plants -> By observing the images, the overall growth of cowpea plants appears to be relatively loose, possibly due to poor ventilation caused by excessive planting.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2564", + "fact_text": "What special measures should be taken during the growth period of this crop -> During the growth period, it is necessary to ensure that watering is done in an appropriate manner, with a small amount and multiple times, and timely drainage should be carried out after rain to avoid waterlogging in the field. Meanwhile, excessive use of quick acting nitrogen fertilizers should be avoided.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4539", + "fact_text": "Are there any effective prevention and control methods -> One method is to rotate with grasses for 2-3 years, and pay attention to timely intercropping, weeding, and sowing density to prevent moisture retention and worsen the condition. In terms of fertilization, it is recommended to use formula fertilization technology to avoid biased or excessive application of nitrogen fertilizer, and increase the use of phosphorus, potassium fertilizer, and lime. And strengthen field management, such as timely drainage after rain, to prevent excessive humidity in the field. The use of preventive and therapeutic drugs is also an important means, for example, spraying medication containing specific active ingredients in the early stages of the disease to control its occurrence.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5739", + "fact_text": "How do the plants in the image look -> The plants in the image exhibit slight curling of the top leaves and pale leaf color.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image130", + "fact_text": "What preventive measures are usually recommended in this situation -> To prevent similar diseases, it is usually recommended to improve ventilation and light conditions, avoid dense plants, and drain water in a timely manner after rain. Fertilizers containing nitrogen, phosphorus, and potassium should be applied appropriately, and attention should be paid not to water in humid conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image5148", + "fact_text": "How does this bacterium spread and survive on tobacco -> Bacteria can survive in soil or on plants. When a plant has wounds, bacteria will invade the injured thin-walled cells and rapidly multiply, spreading through these pathways. A high temperature and humidity environment can accelerate the spread and spread of the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1578", + "fact_text": "What are the methods for preventing and treating this disease in this situation -> Some effective prevention methods include seed treatment, adopting appropriate cultivation measures such as crop rotation, timely field management, and appropriate spray control. Ensuring appropriate cultivation and irrigation methods are also crucial.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image4431", + "fact_text": "What is the cause of the disease in the image -> The pathogen of this disease is a fungus called Bipolarismaydis (NisikadoetMiyake) Shoem, which belongs to the subphylum Hemimonas. This fungus is caused by the T-race of corn flat navel worm, mainly infecting T-type male sterile lines of corn.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5356", + "fact_text": "What are the prevention and control methods for this pest -> There are several methods to prevent and control this type of insect. Firstly, the occurrence of pests can be prevented by rotating rapeseed with non cruciferous vegetables. Secondly, when adults appear, crops can be sprayed with 2% cypermethrin powder. If the previous crop is not a cruciferous crop, a 10m wide insecticide strip can also be sprayed around the field to prevent the invasion of foreign adults. If adult insects have been discovered, early prevention and treatment can be carried out, with a focus on eliminating them. Timely spray some special pesticides, such as 2.5% deltamethrin emulsion at 3000 times, 40% pyrethroid or chrysanthemum horse emulsion at 2000 times, 80% dichlorvos emulsion at 1000 times, etc.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4960", + "fact_text": "How to prevent and treat this disease -> Firstly, plants can be guided to enhance their disease resistance through reasonable dense planting, scientific fertilization, and attention to the reasonable ratio of nitrogen, phosphorus, and potassium. Secondly, strengthening management can improve the ventilation and light transmission of hemp fields. After rain, timely trenching and drainage can prevent moisture retention and reduce the incidence of diseases. In addition, spraying specific chemical agents during the early stages of the disease is also a method of prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1419", + "fact_text": "Can you see any abnormalities in the color of the leaves from the picture -> You can see that the leaves have some uneven spots, and there is also a phenomenon of downward curling of the leaf edges.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "corn fall armyworm 365", + "fact_text": "What is the cause of the abnormal phenomenon in the picture Answer: Insect bites", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2140", + "fact_text": "How does this disease spread -> The disease is mainly transmitted through wind driven spores and re infects other healthy fruits under suitable humidity and temperature conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image5618", + "fact_text": "What should be noted when managing this type of plant -> Attention should be paid to appropriate pruning, removing weak branches and infected leaves, while reducing the use of nitrogen fertilizer and increasing phosphorus and potassium fertilizer to improve the plant's disease resistance. Ensure good ventilation and sufficient sunlight, especially after rain, timely drainage to prevent moisture retention.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4545", + "fact_text": "What factors may cause this situation to occur -> This situation may be caused by a fungus called Ascochytapinides. This pathogen can overwinter within seeds or on diseased residues, and then spread through wind, rain, or irrigation water, invading through stomata, water holes, or wounds, causing crop diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image5746", + "fact_text": "What are the prevention and control measures for this disease -> Some effective prevention and control measures include crop rotation, using nutrient bowls to reduce root wounds, using appropriate pesticides to treat roots, timely removal of diseased plants, and disinfecting diseased holes with lime.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3326", + "fact_text": "Is there anything unusual about the leaves in the image -> There are some circular or nearly circular dots on the leaves in the image, which gradually turn yellow and then brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4731", + "fact_text": "What is the impact of this pest -> The larvae of this pest can feed on leaves, causing notches or holes to appear on the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "beet fly 37", + "fact_text": "What is the name of the insect in this image Answer: Beet fly", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2911", + "fact_text": "Based on the image, what chemicals should be used to address this issue -> You can choose 25% triazolone emulsion 2000x solution or 75% chlorothalonil wettable powder 600x solution, etc., and spray regularly to control the condition.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5379", + "fact_text": "How many generations does this type of insect produce per year -> In Hangzhou, this type of insect has 4 generations per year, 6 generations in Hunan, and 7 generations in Guangzhou.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4783", + "fact_text": "How can this pest be prevented -> For the prevention and control of this pest, it is recommended to refer to the prevention and control methods of sweet potato leaf beetle.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2122", + "fact_text": "What possible problems do these phenomena suggest -> These phenomena may be caused by insufficient nitrogen nutrient supply in the soil.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4855", + "fact_text": "How do the leaves of this plant look in the image -> In the image, the leaves of the plant are basal and appear shorter than the stem, with reddish brown leaf sheaths and a darker overall color.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "tomato verticulium wilt 357", + "fact_text": "Does the blade in the picture show any abnormal appearance Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4705", + "fact_text": "How should we prevent and control this pest -> Firstly, before resuming the activity of overwintering insects, it is necessary to remove the English grass near the wheat field and bury or burn it deeply to reduce the source of insects. Secondly, if necessary, use 1kg of 2.5% trichlorfon powder, mix with 20kg of fine sand, and sprinkle into the grass. Thirdly, during the peak period of adult pest infestation, 2.5% trichlorfon powder can be sprayed onto wheat seedlings or Acanthopanax splendens, with a dosage of 1.5-2kg per 667m. Spray again after 10 days to eliminate newly hatched nymphs. Fourthly, if necessary, it is also possible to spray 2500 times the 2.5% preserved emulsion.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2964", + "fact_text": "The roots in the image seem to split into several parts, what's going on -> The roots shown in the image, due to certain inhibitory factors, such as poor soil conditions or seed quality issues, cause the originally neat roots to split into multiple parts.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image407", + "fact_text": "How will this situation affect the leaves of plants -> Affected plants may have yellowing or wilting of their leaves, starting from the lower leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1011", + "fact_text": "Will this situation affect the overall growth of the fruit -> There will be certain impacts, especially for fruits severely affected by the disease, which may develop poorly, mature prematurely, or partially wither.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4646", + "fact_text": "What are the effective methods for preventing and controlling this pest -> Effective prevention and control can be achieved through the strategies of cutting the first generation, selecting the second generation, and skillfully managing the rice paddies. It is appropriate to prevent and control adults and eggs in the peak period. Some special pesticides can be used, such as 80% dichlorvos emulsifiable concentrates or 50% fenitrothion emulsifiable concentrates, or 40% dimethoate emulsifiable concentrates or 50% fenitrothion emulsifiable concentrates can be used for spray prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1879", + "fact_text": "Are there any other changes in the leaves -> Yes, in addition to spots, the growth of leaves will also slow down and wrinkling will occur on the leaf surface. If humidity increases, the spots will turn into oil stains, and the color may deepen from brown to dark brown, with irregular or polygonal shapes.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "beet army worm 997", + "fact_text": "What is the color of the insect's front wings in the picture Answer: Yellow brown", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3510", + "fact_text": "As shown in the figure, have any preventive measures been taken -> From the image content, it can be inferred that preventive measures may include using pesticides to treat pre planted sweet potatoes, as well as selecting good soil quality and improving field management quality, such as avoiding poor drainage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4803", + "fact_text": "What methods are commonly used to prevent and control this pest -> For this type of pest, common prevention and control methods include the use of aluminum phosphide fumigation. This requires drying the grain to the specified moisture content before fumigation, and then sealing the warehouse for fumigation. After processing, it is necessary to undergo ventilation treatment to ensure that pesticide residues are reduced to below safety standards.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "cowpea rust 2", + "fact_text": "What kind of disease formed the spores in the picture Answer: Cowpea rust", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4055", + "fact_text": "What are the impacts of climate factors on this situation -> Under conditions of low night temperature and excessive use of nitrogen fertilizer, this abnormal growth of fruits is more likely to occur.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5321", + "fact_text": "Is there any display of the adult morphology of this insect in the image -> The adult body in the image is grayish brown in color, with obvious dark brown spots on the front wings and light yellow stripes on the outer edge of the wings. A large rectangular yellow white spot can be seen in the center, which is one of its identification features.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4691", + "fact_text": "Is there any reliable method to prevent this pest -> One possible method is to use the intercropping of wheat and corn cultivation method. This method is 10-15 days earlier than corn sown after wheat, which can avoid the peak period of aphid reproduction and reduce damage. In addition, based on the prediction and forecasting, it is also a feasible method to determine the type and period of medication based on the percentage of natural enemy units in the aphid population, climate conditions, and the occurrence of the aphid.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3210", + "fact_text": "What is the impact of humidity changes on these lesions -> When the environmental humidity is high, the back of these lesions will produce a gray white mold like substance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "apple powdery mildew 261", + "fact_text": "Is the white substance on the leaves in the picture caused by diseases Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4357", + "fact_text": "What are the typical transmission pathways of this disease -> The main source of infection for this disease is winter spores or winter spore clusters that are located in the soil or attached to the surface of seeds and fertilizers. After the germination of winter spores, the pathogen invades the growth site through the sheath, causing systematic infection of the disease. It is a seedling disease that has not been re infected.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5009", + "fact_text": "What are the special characteristics of this pathogen -> This pathogenic fungus is a special type of fungus called sesame shell spore. Its conidia can survive in the diseased tissue of the host and then break through the epidermis to expose. The sporangium itself is spherical to nearly spherical, light brown in size, ranging from 84 to 104 ΞΌ Between m. Some conidia are cylindrical to elliptical in shape, colorless and transparent, mostly twin, with a slight constriction at the middle diaphragm, and some are single celled, with a size of 6-11 Γ— 2-4( ΞΌ m) Between.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image4743", + "fact_text": "What are the main problems caused by this pest infestation -> Insect infestation can sting and suck on the juice of plant tissue, causing the leaves to turn yellow or red, further affecting the growth and development of plants. Severe conditions can lead to plant death. In addition, this type of pest can also secrete nectar, causing the appearance of black mold like substances.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image593", + "fact_text": "How does this situation affect the growth of plants -> This situation will cause the aboveground parts of plants to gradually wither and seriously affect their normal growth and yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "citrus phyllocnistis citrella stainton 387", + "fact_text": "What insects have affected the leaves in the picture -> Citrus leafminer", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5120", + "fact_text": "What impact does this abnormal situation have on the overall crop -> In severe cases, this abnormality can cause the sugarcane stems of crops to bend, even causing shoot rot, softening and browning of tissues around the growth point, necrosis of the heart leaves, and ultimately leading to the death of the entire crop.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4810", + "fact_text": "What are the special features of insect eggs in the image -> Insect eggs appear to be elongated and slightly curved. One end is pointed, the other end is blunt and round, with many small spikes on the surface.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1023", + "fact_text": "Is there any abnormal phenomenon on the surface of the fruit in the image -> The surface of the fruit in the image shows water soaked brown lesions, with a slight depression in the center and black dots arranged in a concentric circle pattern.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5282", + "fact_text": "What is its shape and color -> This type of insect infestation has an oval shaped body, typically with antennae that are equal to or slightly longer than the length of the body. As for the color, its chest and back panel are light green with two circular black spots on top. As for the Coleoptera, there are light green and black spots on it.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4604", + "fact_text": "How does this disease arise -> This disease is caused by a fungus called Rhizopus stolonifer, which initially appears colorless and later turns dark brown. It forms a large amount of mold on the surface of crops, making it look like a black mold. In addition, this fungus can also penetrate through the air or attach to diseased plants, or overwinter during storage, and then invade through wounds.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4956", + "fact_text": "What are the ways to prevent or treat this disease -> There are multiple methods to prevent and control this disease. Firstly, disease resistant or tolerant varieties can be selected based on geopictureical conditions, such as Heipi Dou, Anren Dou Ma, Huangjin Dou, Xiangzhu 3, etc. Secondly, choose fields with higher terrain and good drainage and irrigation conditions for planting. If there is rain, timely drainage should be carried out to prevent moisture retention. When fertilizing, the base fertilizer should be sufficient, and phosphorus and potassium fertilizers should be added to avoid excessive application of nitrogen fertilizer. Finally, planting should be done reasonably, and if necessary, spraying control agents should be carried out in the early stages of the disease. Spray once every 7-10 days and continuously 2-3 times.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2926", + "fact_text": "What are the main growth stages of crops affected by this -> It mainly affects the growth of the roots and the nutrient absorption capacity of the entire plant, leading to inhibition of the growth of the entire plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image759", + "fact_text": "Is there any abnormality in the root area of the plant -> The root area of the plant can be seen as an accumulation of black sheet-like structures in the image.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4075", + "fact_text": "What methods can reduce or avoid the occurrence of cracks -> By improving cultivation conditions, such as adjusting watering frequency and intensity reasonably, providing a balanced nutrient supply, and selecting tomato varieties with strong crack resistance, crack occurrence can be effectively reduced or avoided.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "citrus parlatoria zizyphus lucus 26", + "fact_text": "Will insects on the surface of this fruit cause harm to the fruit Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image22", + "fact_text": "What are the prevention and control methods for this disease -> Agricultural prevention and control measures can be taken, such as flushing with water in areas with conditions and strengthening the management of orange orchards. At the same time, chemical control can also be used, such as spraying with 40 % clotriman wettable powder 400 times liquid, 40 % sterilized dane wettable powder 400 times liquid, or 0.5:1:100 times Bordeaux liquid. At the same time, it is also necessary to timely prevent and control insect pests such as crustaceans, whiteflies, Aphids, and other stinging mouthparts.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image235", + "fact_text": "What causes this bottom-up withering -> This is mainly caused by pathogenic bacteria invading from lower parts of the plant and gradually spreading upwards.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5801", + "fact_text": "How to effectively prevent and control the invasion of this insect -> Prevention and control can be achieved by pruning the affected branches, using a small knife to remove insect eggs and larvae from the bark, shaking the branches during the peak of adult emergence to catch them on the ground, or injecting dichlorvos emulsion into the boreholes.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1172", + "fact_text": "Can you describe the overall health status of winter melon in the image -> The winter melon in the image shows some pathological features near the ground, especially the stem and fruit parts are severely affected.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4383", + "fact_text": "How does the root system of crops appear in the image -> Unhealthy root system performance, significant root hair necrosis and root rot are usually related to poor nutrient absorption.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image354", + "fact_text": "Where do these voids usually occur -> Usually, this type of cavity occurs in the area of the ventricles within the fruit, between the fruit peel and the adjacent wall.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4673", + "fact_text": "What are the treatment measures for this pest infestation -> When there are 15 insects per square meter in rice paddies, we can spray pesticides such as dichlorvos, cypermethrin, or sulfur and phosphorus before the third instar of the larvae. You can also spray powder with dichlorvos or marathon powder. In addition, it can also be made into granules for spraying, and the effect is also very good.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image676", + "fact_text": "Will this situation spread from the pod to other parts -> Indeed, from the affected pods, the disease spot can extend to the young stem, and in severe cases, it can cause partial death of plants above the diseased part.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "beet army worm 988", + "fact_text": "What color is the appearance of the insect in the picture Answer: Brown", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4822", + "fact_text": "Have any special behaviors or signs of activity been observed on the soil surface -> Indeed, the figure shows signs of tunnels on the soil surface, which are caused by insect infestations beneath plants and may lead to seedling death.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3272", + "fact_text": "What impact does this situation have on the entire plant -> The entire plant will be severely affected, manifested as a transition from yellow brown to dark brown, accompanied by a foul odor.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4636", + "fact_text": "So, what are the symptoms of rice being affected by this pest in the image -> The manifestation of rice pest infestation is that the larvae burrow into the stem, often burrowing into the first section of the stem from the gaps in the sheath of the rice sword leaves, crawling to the white and tender tissue to feed on it, and may transfer to cause damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2703", + "fact_text": "In what environment is this disease most severe -> In warm and humid environments, the progression of the disease is particularly rapid, especially when the temperature is between 20 and 24 degrees Celsius, and under high humidity conditions, the disease spreads rapidly.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image5103", + "fact_text": "What changes occur on the leaves when humidity is high -> In high humidity, the diseased parts of the leaves will grow white cotton like material, which is the appearance of the fungal hyphae.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image3476", + "fact_text": "What are the good methods to prevent and control this situation -> The prevention and control of this situation can be achieved by increasing the application of phosphorus and potassium fertilizers, strengthening field management, and timely watering to avoid waterlogging. If necessary, appropriate fungicides can be used for spraying, such as 50% dichlorvos wettable powder or 70% methyl tobuzin wettable powder, and prevention and control should be carried out every 10 to 15 days. Depending on the severity of the disease, prevention and control may need to be carried out 1 to 3 times.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image932", + "fact_text": "When does this situation usually occur -> This situation can occur during the seedling and adult stages, especially in high temperature and humidity environments.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5080", + "fact_text": "What type of disease is an image -> The disease shown in the image is caused by potassium deficiency in plants. When plants lack potassium, it can affect their normal growth and development, manifested by changes in leaf size and color, thin and weak stems, and poor fruit development.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3998", + "fact_text": "What are the characteristics of the overall color changes of the culture medium -> The colonies on the culture medium start from white, and as the disease progresses, the color gradually turns light green and finally dark green.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image324", + "fact_text": "So how should this situation be prevented -> Preventive measures include maintaining a reasonable nighttime temperature in the greenhouse, avoiding significant temperature changes, applying fertilizers reasonably, especially controlling the use of nitrogen and potassium fertilizers, and supplementing calcium and trace elements such as boron in a timely manner.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "soybean bacterial spotted disease 1", + "fact_text": "What disease has invaded the leaves in the picture -> Soybean bacterial spot disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4717", + "fact_text": "What symptoms will this pest cause -> Its symptoms mainly include larvae rolling rice leaves vertically, forming white stripes, which may lead to a decrease in crop thousand grain weight, an increase in withered grains, and a decrease in yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4948", + "fact_text": "So, are there any ways to prevent this disease -> Yes, prevention methods include selecting disease resistant varieties, disinfecting seeds, spraying effective pesticides in a timely manner when entering the disease season, strictly managing the hemp field, such as timely drainage after rain, preventing moisture retention, avoiding excessive application of nitrogen fertilizer, and appropriately increasing potassium fertilizer to improve the disease resistance of crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1441", + "fact_text": "What are the shapes of these brown lesions -> These spots have an irregular shape and the edges may be relatively clear.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4343", + "fact_text": "What are the symptoms -> In the image, we can see eye shaped disease spots on the leaf sheaths and stem bases of the crops. These lesions initially appear light yellow with brown edges, and then the middle part will turn black. These eye shaped lesions are about 4cm long and can also produce black insect like feces in the upper part. When the condition is severe, the lesion will penetrate the leaf sheath and extend to the stem, which may cause white spikes or stem breakage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image5266", + "fact_text": "What are the habits of this insect -> This type of pest mainly operates at night and can grow for 3 to 4 generations annually in certain areas. They overwinter in dead plant stems, weed stems, and crop petioles with their eggs. On average, each female lays 78 eggs, mainly on smooth tender stems or petioles.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2304", + "fact_text": "Does the root of the image display any special markings -> You can see the roots turning black and shrinking, which is a clear sign of infection.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4657", + "fact_text": "What specific effects will these black spots and yellowing areas have on the plants -> These symptoms usually indicate that the plant is being subjected to insect stings and sap suction, causing the plant to lose water, affecting rice photosynthesis and respiration, and ultimately leading to rice plant withering.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5615", + "fact_text": "Can you describe the overall impact of disease progression on the fruit -> As the disease progresses, the fruit will lose its original color and structure, become dry and soft, covered with black spore organs on the surface, seriously affecting its commercial value and food safety.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5278", + "fact_text": "What are the activity habits of pests in the image -> This type of pest occurs in the Shihezi area of Xinjiang, mixed with the soybean stem borer, mainly causing damage to cannabis. This is similar to the living habits of the bean stem borer.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4413", + "fact_text": "What is the cause of this disease -> Buckwheat wilt disease is caused by a fungus called Rhizoctonia solani K ΓΌ hn, which forms a thin layer of waxy or white pink network in the soil to form a net like fruiting layer.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4376", + "fact_text": "How much impact does this disease have on crops -> This disease can cause the affected wheat to become shorter and have larger stems after the booting stage; In severe cases, plants may not be able to tassel, and some may tassel but not bear fruit and turn into galls, seriously affecting wheat yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image566", + "fact_text": "How will these pathological features develop during storage -> If the storage conditions meet the requirements of humidity and temperature, the disease may continue to develop during storage, exacerbating fruit decay.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "corn grub 698", + "fact_text": "What is the reason for the abnormal crop in the picture Answer: Grub", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5080", + "fact_text": "So, how did this problem arise -> This problem may be caused by the low potassium content in the soil. Potassium is very important for the growth and development of plants. If the content of available potassium in the soil is too low, such problems may occur. This situation may occur in soils with lower fertility.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5430", + "fact_text": "What are the effective prevention and control methods -> The prevention and control methods include selecting insect resistant varieties with hard, thick, and smooth fruit shells; Eliminate overwintering hosts and reduce overwintering insect sources; Using black light lamps, high-pressure mercury lamps, etc. to lure and kill adult insects; Spray specific pesticides during the oviposition period of adult insects to prevent and control both adult and newly hatched larvae.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4701", + "fact_text": "How many rounds can this type of pest occur within a year -> In places like North China, this pest infestation may occur in four rounds. But in some years, a fifth round may occur, and this fifth round may not be uniform.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "apple Brown spot 34", + "fact_text": "What disease is the abnormal phenomenon in the picture affected by -> Apple brown spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4492", + "fact_text": "Are there any recommended prevention and control methods -> The methods for preventing and treating this disease include: first, timely removal of diseased residues after harvest, concentrated deep burial or burning to reduce bacterial sources. Then, it can be rotated with rice and wheat. In addition, compost made by fermenting bacteria can also be applied, and attention should be paid to increasing the application of potassium fertilizer to enhance the host's disease resistance. If necessary, specific pesticides can also be sprayed for prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4700", + "fact_text": "Is there any way to prevent the occurrence of this pest -> Yes, this image also provides some prevention and control methods. For example, large-scale crop rotation can effectively prevent the occurrence of pests. In addition, planting high variety seeds with thick or hard stem walls can also increase the crop's insect resistance. Moreover, specific types of pesticides can also be sprayed during the peak period of adult infestation, such as 90% crystal dichlorvos 900 fold solution or 80% dichlorvos emulsion 1000-1200 fold solution.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2488", + "fact_text": "What should be paid attention to in field management to prevent the development of this disease -> Attention should be paid to drainage and ventilation to avoid excessive cultivation density, reduce continuous cropping, and timely remove diseased plants and leaves. In addition, maintaining moderate soil moisture is also very important.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image927", + "fact_text": "How does this situation usually spread -> This type of problem is usually spread through wind and rain, and is more likely to spread in humid and warm conditions, especially in continuous rainy weather and environments with continuous condensation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4102", + "fact_text": "When should preventive measures be implemented more effectively -> From the beginning of plant planting, attention should be paid to reasonable density and appropriate row spacing to ensure good light distribution and ventilation conditions, in order to prevent the occurrence of sunburn.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1148", + "fact_text": "Is there any other treatment for severely infected plants -> It is usually recommended to promptly remove severely infected strains and sprinkle a small amount of lime in the affected area to further prevent the spread of the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image497", + "fact_text": "What are the special manifestations of this discolored stem base -> The discolored stem base appears to have lost moisture, appearing dry and tight.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4825", + "fact_text": "How do these scars and holes come about -> These scars and holes are caused by underground larvae biting and eating fine roots or underground stems, affecting plant nutrient absorption and water supply.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4511", + "fact_text": "Is there a way to prevent this low-temperature cold injury -> There are indeed some preventive measures. Firstly, early maturing and high-yield varieties can be selected; The use of plastic film covering cultivation techniques can help provide a good growth environment; Timely sowing and enhanced fertilization, especially organic fertilizer and quick acting phosphorus fertilizer, can promote early maturity and high yield; Moreover, timely field management after emergence, such as thinning, fixing seedlings, weeding, and deep loosening of farmland, is also very helpful.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image5", + "fact_text": "What factors are causing such problems to occur -> This problem is usually caused by a bacterium called Erwinia, which may invade through wounds or natural fissures, and then spread through splashes of rainwater or insect transmission. This is a disease called potato soft rot.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4354", + "fact_text": "What is the reason for this problem -> The main reason is that the thick walled spores of the pathogen attach to the surface of the seed or mix with manure or soil. When the seed sprouts, the thick walled spores will also sprout.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1026", + "fact_text": "What would happen if the situation worsens -> If the situation worsens, the disease will rapidly spread and sometimes even lead to the death of the entire leaf.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image567", + "fact_text": "What are the main manifestations of these diseases on crops -> This disease manifests on leaves, stems, and fruits. Leaves and fruits are particularly susceptible to serious impacts.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image2547", + "fact_text": "How does this shape of zucchini taste -> Due to the cracking and fragility of the flesh, this type of zucchini may have a harder taste and may not be as juicy and soft as healthy fruits.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4549", + "fact_text": "What changes have occurred to the plants in the image -> In the image, we can see small white powdery pale yellow dots on the leaves and stems of the plant, and over time, these dots will expand and present irregular powdery spots that will connect with each other. In addition, the surface of the diseased area is covered with white powder, and the back of the leaves presents brown or purple patches. After the condition worsens, this disease will affect the entire leaf, causing it to quickly wither and turn yellow. This disease can also produce small powdery spots on the stems and pods, and in severe cases, it can spread throughout the stems and pods, causing some parts of the stems to wither and turn yellow, while tender stems may shrink. In the later stage, small black spots will appear in the affected area, which is a sign of closed capsule.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5801", + "fact_text": "What specific damages does this insect cause to its host -> Mainly through larvae drilling into tree trunks, causing internal damage to plant branches and ultimately affecting the overall health of the plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "wheat stem rust 370", + "fact_text": "Will more rainfall promote the occurrence of Wheat stem rust Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4669", + "fact_text": "In what environment does this pest often occur -> This type of pest prefers the floral environment. In the south, they can have 11-14 generations throughout the year, and most of their eggs are laid in the plant tissue inside the flowers, especially on the petals.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "wheat green bug 12", + "fact_text": "What is the name of the insect in the picture Answer: Green bug", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image739", + "fact_text": "What effects will lesions have on stems and pods -> The disease spots can also infect the petioles and stems, although they do not form whorls, a depression will occur in the center. Affected pods can allow pathogens to invade the interior of seeds.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5405", + "fact_text": "What are the main manifestations of this insect attacking crops -> This type of insect mainly damages crops by gnawing on their leaves and flower clusters, causing notches or holes on the leaves and flower clusters, seriously affecting crop growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4754", + "fact_text": "What is the size and color of this pest -> In the image, you can see that the size of the pest is approximately 2-2.8 millimeters long and 1.5-2 millimeters wide. Their color is yellow brown, and their wings are all black except for the yellow ends.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2631", + "fact_text": "How to prevent such tendrils -> To prevent such problems, it is necessary to ensure sufficient water supply during the growth process of cucumbers, while also being careful not to overfertilize to avoid root damage caused by excessive fertilizer concentration.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5340", + "fact_text": "Do the pests displayed in the image have significant features -> Yes, the pest in the image has a body length of about 16mm, a wingspan of 46-56mm, and male butterfly wings are white with black veins. There is one black circular spot on the outer edge of the leading edge of the hind wing. On the back of the wings, there are yellow scales on the top corner of the front wing and the back wing, and one orange yellow spot at the base corner of the back wing.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3676", + "fact_text": "How will the disease development in the image affect the entire plant to a certain extent -> In severe cases of disease, the lesions will become densely packed, causing most of the leaves to wither and die. This large-scale withering of leaves can quickly lead to the withering and death of the entire plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4235", + "fact_text": "Can you describe the shape and size changes of the spots on the leaves -> At first, the spots are small and almost circular, but over time, these lesions will gradually expand and their shape may develop into a nearly elliptical shape, ultimately resulting in significant changes at the center and edges of the spots.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5776", + "fact_text": "In which season are these insects usually most active -> This type of insect is most active from late spring to early summer, especially from late May to mid to late July, when a large number of adults are unearthed and larvae are active.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5307", + "fact_text": "What are the characteristics of the appearance of these insects -> These insects are small in size, ranging from dark peach red to brownish red, and are covered with a layer of white powdery wax on the outside.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image181", + "fact_text": "What are the effects of these hyphae on plants -> These hyphae can interfere with the normal function of leaves, leading to impaired nutrient delivery and ultimately affecting the overall health and growth of plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image989", + "fact_text": "What are the effects of high temperature and humidity conditions on the symptoms of the affected plants in the image -> High humidity and low light conditions are conducive to the occurrence and spread of this disease, especially in environments with sustained high humidity in greenhouses.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5447", + "fact_text": "What are the abnormal phenomena of the leaves in the image -> The edges of the leaves in the image have formed notches along the edges, which appear to be caused by some insect feeding along the edges.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1217", + "fact_text": "What impact may the current climate conditions have on plants -> If the temperature is between 18 and 25 degrees Celsius and the relative humidity of the air exceeds 85%, it provides favorable conditions for the development of the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "rice sogatella 13", + "fact_text": "What is the name of the insect in the picture -> White backed plant", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5072", + "fact_text": "What kind of pathogen is causing this disease -> This disease is caused by a bacterium called Xanthomonas campestris pv. campestris. This bacterial body is rod-shaped, with a size of approximately 0.7-3.0 x 0.4-0.5( ΞΌ m) It has a single flagella and no spores. This bacterium forms approximately circular colonies on beef juice agar medium. The colonies initially appear light yellow and then turn waxy yellow. They grow in a polar manner and can tolerate environments ranging from pH 6.1 to 6.8, with an optimal pH of 6.4.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5238", + "fact_text": "Is there any abnormality in the image -> In the image, the crops seem to have been disturbed by some kind of pest.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1562", + "fact_text": "When do these symptoms usually appear -> These symptoms usually appear in the late stage of celery growth under high humidity conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4349", + "fact_text": "What pathogens may cause this symptom -> According to structured knowledge, this symptom may be caused by various pathogens, mainly including fungi such as Fusarium graminearum, Fusarium oat, and Fusarium flavum.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "apple Grey spot 27", + "fact_text": "What diseases are affecting the leaves in the picture -> Apple Grey Spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2003", + "fact_text": "Is there any abnormal odor in the pea seedlings in the image -> Yes, softening and rotting parts may release a foul odor.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "corn spot 1", + "fact_text": "What disease is causing the anomaly in the picture Answer: Corn spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5265", + "fact_text": "What kind of pests may cause these symptoms -> These symptoms are usually caused by a brown pest, with a body length of 6-7mm and longer antennae than the body. Both adults and nymphs can prick and suck crops, causing damage to the crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5355", + "fact_text": "Is there any effective prevention and control method to control the development of this pest -> There are several methods to control this pest. Some of these methods include spraying specific pesticides onto the base of crop stems and leaf axils before the adult lays eggs or when the larvae have penetrated leaf tissue; Remove the old leaves at the base of the crop before and after flowering, and bring them outside the field for deep burial or burning to eliminate a large number of larvae; It is also possible to spray specific pesticides before laying eggs in autumn to prevent pest infestation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4655", + "fact_text": "How to prevent this pest in large-scale rice fields -> Large areas of rice fields can be monitored and reported, and the migration trend of rice brown planthoppers can be analyzed in a timely manner. Reasonable layout of planting areas can be carried out to reduce pest sources. Strengthen field management, especially in terms of fertilizer and water, to avoid overgrowth and overgrowth in the later stage. In addition, varieties with insect resistance can also be selected and promoted.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5548", + "fact_text": "Is there any special symbol on the ginger leaves in the image -> In the image, there are some spindle shaped spots on the surface of the ginger leaves. These spots are initially small brown dots, but later expand and the middle part appears gray white, with light brown edges.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4691", + "fact_text": "Does the crop in the image seem to have any issues -> The barley in the image seems to have been affected by pests.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image4948", + "fact_text": "How does this disease spread -> The pathogen may overwinter in the diseased residue or inside and outside the seeds, and become a source of infection at the beginning of the following year. The molecular spores produced by the disease can be re infected through wind and rain splashing or insect transmission. In addition, the disease resistance, seed carrier rate, and climatic conditions of the variety may all affect the extent of disease spread.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1845", + "fact_text": "How to control this disease through medication -> Recommended pesticides such as streptomycin sulfate or garenon can be used for spraying before or during the onset of the disease, and regular spraying is necessary, following the guidelines for safe use of drugs.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5088", + "fact_text": "What type of pathogen is causing this disease -> The pathogen that causes this disease belongs to fungi, specifically a type of fungus in the subclass Ascomycota.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4457", + "fact_text": "What factors are causing this situation -> This situation is caused by genetic factors and is not related to environmental factors or infectious diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3292", + "fact_text": "What is the rate of development of this plant disease -> This disease develops rapidly, transitioning from primary waterlogging to soft rot and the formation of fungal nuclei in the later stages.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2609", + "fact_text": "The cucumber plants shown in the image don't look very healthy, what are the issues with the leaves -> The surface of the leaves in the picture is uneven, and the color of the spots varies from light to dark.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato yellow leaf curl virus 1031", + "fact_text": "Can tomato yellow leaf curl virus disease only be transmitted in a persistent manner by tobacco whiteflies under natural conditions Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3018", + "fact_text": "Is there any moisture or other liquid substances on the surface of the crops in the image -> Yes, the affected area in the image shows moisture and a yellow viscous substance, which is usually a typical sign of soft rot, and the affected area may have a foul odor.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "pepper root rot 199", + "fact_text": "How long is the incubation period for the onset of chili root rot disease Answer: 5-7 days", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2626", + "fact_text": "What are the good management measures in this situation -> In terms of management, the amount of nitrogen fertilizer should be reduced, watering should be reasonably controlled, and ventilation should be strengthened to achieve appropriate levels of temperature and humidity, in order to avoid excessive growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1555", + "fact_text": "Has the color of celery changed in the picture -> The infected area first becomes watery, then becomes soft, and the color may become darker, eventually turning gray.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1962", + "fact_text": "What is the reaction of the cabbage in the picture when it comes into contact with water -> After contact with water, pathogenic bacteria become more active in water transmission, increasing the likelihood of transmission and infection.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image179", + "fact_text": "Are there any signs of prevention and control measures in the image -> There are no obvious signs of prevention and control measures in the image. The ideal prevention and control measures should include using disease-free seeds, avoiding biased nitrogen fertilizer application, and spraying with recommended pesticides at appropriate times.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image204", + "fact_text": "Is there any abnormality in the stem in the picture -> The stem in the picture is upright and shows some fragility, but there is no obvious wilting phenomenon.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image2610", + "fact_text": "Is there any special pattern for this color change -> Yes, except for the green edges, most of the mesophyll between the leaf veins will turn yellow white, presenting a so-called \"green ring\" state.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5360", + "fact_text": "What are the habits of this pest and will it affect its activity patterns -> This pest only gives birth once a year in specific areas, and it winters in the form of eggs at the roots of rapeseed. It is active from late March to early May in spring, and its adults and larvae are active during the day, while they may lurk in the soil at night or on rainy days. At the same time, this type of pest prefers light and has pseudolethality. After early May, it will burrow into the soil and pupate, and after more than ten days, it will emerge as an adult and be unearthed. During the summer season, adults will infiltrate the soil and then reappear in autumn to harm seedlings.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2783", + "fact_text": "How do the plants in the image appear to grow -> Plants seem to exhibit symptoms of growth inhibition, with overall dwarfism and upright growth points.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4877", + "fact_text": "What is the approximate height of the plant -> The height of plants is roughly between 20 and 70 centimeters. This can be estimated from the proportion relationship between the image and surrounding objects.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4394", + "fact_text": "What causes root rot -> Usually, it is due to nutrient deficiency, especially phosphorus deficiency, which leads to poor root growth and root rot.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4065", + "fact_text": "What is the crack situation of the fruit in the image -> The fruit in the image is accompanied by corked cracks in the longitudinal grooves, and in severe cases, the seeds may be exposed.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1161", + "fact_text": "How obvious are these wheel shaped lesions -> Very obvious, these wheel patterns are densely arranged and easy to recognize.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5090", + "fact_text": "What type of pathogen is causing this -> These symptoms indicate that a fungus belonging to the subphylum Ascomycota is affecting plants. Its features include white mycelium and various shapes of fungal nuclei.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4625", + "fact_text": "How does it cause damage to crops -> In the image, you will see that this pest has caused damage to the stems of crops. The larvae first gather on the inner side of the leaf sheath to eat and damage, causing water stained yellow spots on the outer side of the leaf sheath. Later, the leaf sheath withers and turns yellow, and the leaves gradually die. When larvae feed into the stem, the leaf tips begin to turn yellow, and in severe cases, the heart leaves will wither and die, with holes on the affected stem.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4852", + "fact_text": "What is the color of the leaves -> The plant leaves in the picture appear green, reflecting the normal growth state of the plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "citrus phyllocnistis citrella stainton 145", + "fact_text": "What insect damage did the leaves in the picture suffer from -> Citrus leafminer", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "pepper blossom end rot 27", + "fact_text": "What kind of disease affects the surface of chili peppers in the picture -> Chili navel rot disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5324", + "fact_text": "Are there any effective prevention and control measures -> Effective prevention and control measures include timely spraying appropriate pesticides to control the number of insects in tobacco fields after the overwintering eggs on peach trees have hatched. In addition, using silver gray covering film during the seedling period can effectively reduce insect damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image955", + "fact_text": "What are the measures to prevent and treat this sudden illness -> Effective measures include selecting well drained plots as seedbeds, using disease-free soil, reducing sowing density, watering appropriately to control soil moisture, and using appropriate fungicides in a timely manner.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1097", + "fact_text": "What kind of environment would such a situation occur in planting -> Usually in high humidity environments, it is easy to induce such situations, especially in cases of poor ventilation and poor drainage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2512", + "fact_text": "Besides chemical control, what other cultural measures can help manage this disease -> Implementing high furrow mulching cultivation, moderate use of nitrogen fertilizer and increased application of phosphorus and potassium fertilizers, as well as timely cleaning of disease residues, are all very effective management measures.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato verticulium wilt 349", + "fact_text": "Will Tomato verticillium wilt occur again in the same year Answer: No", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2520", + "fact_text": "What is the condition on the back of the leaves -> There is a water immersion like appearance on the back of the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5427", + "fact_text": "What is the impact of this pest on sesame seeds -> This type of pest is caused by its larvae feeding on the leaves of sesame seeds, with a large appetite. In severe cases, the entire plant can be eaten up, and sometimes it can also harm tender stems and pods. If the quantity is too large, it can have a significant impact on yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3115", + "fact_text": "How to detect and prevent this disease in the early stages -> Disease resistant varieties should be selected and effective rotation should be carried out, while appropriate pesticides can be applied for prevention and control in the early stages of the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4620", + "fact_text": "Are there any abnormal features on the surface of rice in the image -> There are small holes on the rice stem in the image, and there is no insect feces around it, which may be caused by larvae drilling into the rice stem.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2976", + "fact_text": "So how should we prevent the occurrence of such drug damage -> To prevent such pesticide damage, the first step is to scientifically use pesticides and strictly prepare them according to the prescribed concentration and dosage. In addition, spraying should avoid strong light and high temperature periods at noon, and it is best to choose morning or afternoon to reduce the risk of pesticide damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image243", + "fact_text": "What is the mode of transmission of this disease on tomatoes -> This disease invades through wounds or stomata of plants through wind, rain, or insects, and is more likely to develop under high temperature, high humidity, and rainy weather conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "mango deporaus marginatus pascoe 164", + "fact_text": "What color is the compound eye of the insect in the picture Answer: Black", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1895", + "fact_text": "What is the overall condition of the affected plants -> In severe cases, the external leaves of the plant may wither completely, and the entire plant may wilt, especially after the pathogen enters the vascular bundle.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2639", + "fact_text": "Is there any abnormal performance in cucumber fruit -> In the image, it can be observed that the fruit has become smaller and deformed.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4689", + "fact_text": "What methods are there to prevent or reduce the impact of this pest -> To prevent this type of pest, attention should be paid to the prevention and control of aphids in the source base during the seedling or jointing stage. After reaching the panicle stage, if more than one percent of aphids in wheat meet the prevention and control targets, or if the benefit to harm ratio is less than 1:120, timely prevention and control should be carried out in clear weather without strong winds or heavy rain.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4638", + "fact_text": "What are the morphological characteristics of this pest -> The adult has a body length of 6-7mm, a wingspan of 13-19mm, and a white head, chest, and abdomen with black spots. The front wing has a black baseline and inner horizontal line, and the part from the middle chamber to the inner edge is brownish yellow. The hind wings have a sloping sub baseline from the middle chamber to the inner edge, intersecting with another diagonal line extending from the center of the leading edge at the inner edge. The Asian border line is black, and the border line is brown yellow. The egg is white, in the shape of a long lemon, with a pointed mouth at one end, a flat bottom, and a longitudinal groove on the surface. The body length of the last instar larvae is approximately 13mm, yellow white gray, smooth and hairless, with a light yellow head, a light brown front chest and back plate, and reddish brown spots. The pupa is approximately 8mm long, light yellow in color, with prominent 2-4 solar term orifice plates on the abdomen, appearing reddish brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5227", + "fact_text": "What is the reason why the plants in the image appear sparse -> In the image, plant sparsity may be caused by root infections, which affect the overall nutrient absorption and health of the plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4578", + "fact_text": "What are these white filaments caused by -> These white filamentous substances are caused by specific bacterial strains. This type of mycelium is colorless and has a diaphragm.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5651", + "fact_text": "What shape or texture changes do the leaves have -> The leaves exhibit unevenness or distortion, and the leaf surface appears wrinkled and deformed.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5424", + "fact_text": "What organism is causing this -> This situation is usually caused by insect infestation. Their larvae can harm the tender leaves, buds, flowers, and pods of crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "lemon canker 169", + "fact_text": "What kind of disease is causing the symptoms on the leaves in the picture Answer: Lemon canker", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "rice bacterial streak spot disease 3", + "fact_text": "Is it easy to treat Rice bacterial stream spot after onset Answer: It's not easy", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1445", + "fact_text": "What measures can be taken to prevent or alleviate this disease -> One effective measure is to choose varieties that are resistant to wind, rain, or cold to reduce the incidence of disease. In addition, spraying 2.5% chloramphenicol suspension 1500 times solution in the early stages of the disease is also a commonly used prevention and control method.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1351", + "fact_text": "What does tendrils represent in the image -> The tendrils are severely affected, with some showing decay and breakage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4651", + "fact_text": "What type of creature is depicted in the image -> The organisms in the image belong to the insect pest category.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1030", + "fact_text": "What color does the leaf disease area in the picture appear when it is dry -> When dry, the affected areas often appear reddish brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1033", + "fact_text": "What types of problems do these disease manifestations indicate -> The manifestations of these types of diseases suggest that plant diseases may be caused by certain fungi, which can form lesions and rot on the stems, leaves, and fruits of plants under appropriate conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "mango sternochetus frigidus 1", + "fact_text": "What insects have harmed the fruit in the picture -> Sternochetus frigidus", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3069", + "fact_text": "What preventive measures should be taken to prevent this situation -> Firstly, it is important to use disinfected seeds, and implementing crop rotation and early detection and removal of infected plants are also effective methods. Specific fungicides can also be used for spraying treatment.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4559", + "fact_text": "What will happen if effective prevention and control are not carried out -> If effective prevention and control are not carried out, crops may be at risk of wilting and early death, and the virus may further spread in the field, potentially affecting larger areas of crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4025", + "fact_text": "What other symptoms of the plant are associated with this purple leaf vein -> Purple veins are usually accompanied by abnormal yellow green mottled and distorted leaves. These symptoms indicate that the plant may have been infected with the mosaic virus.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image3169", + "fact_text": "How do they usually manage this situation to alleviate the disease -> It is important to take appropriate agricultural measures such as clearing ditches, draining water, and increasing the application of organic phosphorus and potassium fertilizers, while avoiding excessive use of nitrogen fertilizer. In the early stages of symptoms, commonly used pesticides can also be applied for spraying.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5314", + "fact_text": "What are the characteristics of insect antennae -> Their antennae are relatively short, and the stalk can reach the posterior edge of the eye. The first few segments are longer than the back ones, while the last few segments are wider than long and have a pointed end.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1853", + "fact_text": "Under what environmental conditions do diseases commonly occur -> This disease is more likely to spread during seedling periods with high humidity and humid and rainy weather conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5117", + "fact_text": "Is the yellow green color of the plant leaves in the image normal -> The yellow green leaves in the image indicate that the plant may be experiencing nutrient deficiency.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5279", + "fact_text": "If I were a farmer, how should I prevent or treat this pest -> For this type of pest, agricultural control can be used, such as in the Yellow River Basin, timely transportation of wheat outside the field after harvest, and strict prevention of the transfer of corn borers to cotton plants. Biological control can also be used to release red eyed bees during the peak spawning period of the 2nd and 3rd generations of corn borers, releasing 10000 heads per 667m2 and releasing them twice in a row. Chemical control is also an effective method, for example, if the egg mass of the second generation corn borer exceeds 3.72, the egg mass of the third generation corn borer exceeds 4.97, or the rate of new shoot damage is 3%, appropriate pesticides should be sprayed immediately during the peak period of egg hatching.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4785", + "fact_text": "What are the characteristics of the living habits of this pest -> This pest has 3-4 generations in Hebei, Shandong, Henan, Jiangsu, and Zhejiang provinces in China, 4-5 generations, 5 generations in Hubei, 6 generations in Jiangxi, 7-8 generations in Fujian, and 8-9 generations in Guangdong, with overlapping generations and overwintering as pupae in the soil. The newly hatched larvae gather on the back of the leaves to feed on the lower epidermis and mesophyll. Elderly larvae have the habit of migrating and transferring in groups to cause harm.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image3771", + "fact_text": "Does the sinking of stem nodes in the image affect the structure of the stem -> Yes, the sinking and disease spots of stem nodes can damage the structure of stem nodes, and further development may lead to necrosis and decay of the entire stem node. In severe cases, the stem structure may collapse and cause the plant to fail to grow normally.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2953", + "fact_text": "What are the methods in the image that can prevent and control this plant disease -> To prevent and control this disease, the development of the disease can be controlled by using disinfected bed soil and seeds, as well as regularly spraying suitable pesticides.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "vitis polyphagotars onemus latus 52", + "fact_text": "What is this insect in the picture -> Polyphagotars onemu latus", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4958", + "fact_text": "Are there any effective prevention and control methods -> Some effective prevention and control methods include selecting well drained plots to plant affected crops, and increasing the application of phosphorus and potassium fertilizers through formula fertilization techniques. Keeping the site clean and promptly removing diseased and disabled tissues can reduce the source of overwintering bacteria. In addition, if early symptoms are found in areas with severe illness, designated pesticides can be sprayed every 10-15 days, with two consecutive treatments.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2407", + "fact_text": "Is this situation developing rapidly -> Yes, under suitable temperature and humidity conditions, this situation can quickly spread.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4239", + "fact_text": "What measures can be taken to prevent the occurrence of this epidemic -> There are various methods to prevent this disease. Firstly, high terrain fields can be selected as rice paddies, which need to be rotated annually. Secondly, it is necessary to strengthen fertilizer and water management, irrigate shallow water frequently, prevent cross irrigation, and appropriately increase the application of phosphorus and potassium fertilizers to improve disease resistance. Finally, there is pesticide control, and relevant pesticides can be sprayed during the 3-leaf stage of seedlings.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image3989", + "fact_text": "What are the characteristics of color changes in the stem and folds of the fungus -> In the image, the fungal stalk and folds also present a red pink mold layer, indicating that the infection has spread.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2213", + "fact_text": "So what are the ways to prevent this phenomenon -> The most effective method is to choose the appropriate sowing time to avoid the plant entering the bolting stage too early. When foreseeing the impending cold weather, corresponding measures should be taken to protect plants from cold damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image4753", + "fact_text": "Do these pests have any special living habits -> This type of pest grows once a year in Liaoning and Shanxi, and 1-2 generations a year in North China. Overwintering adults overwinter in 5-6cm of soil below soil blocks, in soil crevices, crop roots, and weed rhizosphere. Has a diverse diet and prefers drought. Generally, in dry and rainy years, the likelihood of scaly leaf beetles occurring is higher. Slope land, dry fields, and sowing depth can also affect its occurrence.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1882", + "fact_text": "Does the cauliflower in the image show any signs of disease -> Yes, the cauliflower in the image shows symptoms of mosaic and mottled leaves, which are signs of disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4710", + "fact_text": "What are the general ways to treat it -> The treatment methods for this organism can be achieved through agricultural control, physical control, and chemical control. Specifically, this includes selecting insect resistant varieties, treating overwintering hosts, reducing the number of insect sources, and adapting to local conditions for cultivation and restructuring. In the event of a major outbreak, highly effective drugs can be used for prevention and treatment.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4379", + "fact_text": "So how should we prevent the occurrence of this disease -> Some suggested prevention and control methods include promoting the use of compost made from fermenting bacteria, increasing organic and phosphorus fertilizers, improving soil structure through rational fertilization, and selecting varieties that are resistant to dry heat wind damage for planting. In addition, timely watering and spraying of anti dry hot air agents is also an effective method of prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "management instructions", + "entity": "image4417", + "fact_text": "How to prevent and control this disease -> The methods for preventing and controlling this disease include strengthening field management, timely weed removal, and the use of herbicides if necessary. In addition, at the beginning of the disease, certain specific chemical agents can be used for spraying, such as 75% chlorothalonil wettable powder, 70% mancozeb wettable powder, 64% chloramphenicol wettable powder, and 50% benzimidazole wettable powder, all of which can be sprayed after adopting an appropriate dilution rate.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5106", + "fact_text": "What is the mode of disease transmission in the picture -> This disease is mainly transmitted through conidia in the air, which can spread over long distances through wind.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image5640", + "fact_text": "What is the pathway for the spread of this disease -> This disease is mainly transmitted through conidia in the air, especially under high temperature and humidity conditions, where spores can directly invade through plant wounds or epidermis.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5289", + "fact_text": "What methods can be used to control this pest -> There are multiple ways to control this pest. For example, black light lamps or sugar and vinegar pots can be used to lure and kill adults, which can control the number of pests before the larvae develop into adults. Another method is to spray insecticides accurately when the larvae are in their developmental stage (before the 3rd instar), effectively eliminating the larvae. The specific insecticides used can be 5% carbendazim powder, 2.5% phoxim powder, and 2% cypermethrin powder. 1.5-2.5 kilograms per 667 square meters is sufficient.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2060", + "fact_text": "Is there any preventive measure in place to prevent the appearance of crops in the image that their yield may be affected -> To prevent and reduce the occurrence of apical baldness, drought resistant varieties can be selected, and irrigation and fertilization plans can be arranged reasonably to avoid insufficient nutrient supply.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5526", + "fact_text": "What are the natural enemies of this insect -> Their natural enemies include several species of terrestrial bees and Beauveria bassiana, which can to some extent control their numbers.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4798", + "fact_text": "What methods can effectively prevent or control this pest -> Effective control methods include using low temperatures to reduce the temperature inside the warehouse to below 0.6 degrees Celsius for more than 7 days for freezing insecticides, or raising the temperature to 55 degrees Celsius for high-temperature insecticides. In addition, biological control methods are also feasible, such as using a certain dose of insecticide to treat wheat, which can control this pest for a long time.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image709", + "fact_text": "The leaves in this picture look abnormal in color. What is this phenomenon -> The leaves in the image exhibit uneven discoloration, and there may be spots or lesions on the surface, which is usually a physiological or pathological reaction.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image945", + "fact_text": "Do you have any branching symptoms -> Yes, the plant shows extreme abnormal growth, with too many branches, forming a condition similar to clumps.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4972", + "fact_text": "What is the reason for this -> This is caused by a strain called OidiumliniSkoric. This strain belongs to the subfamily of fungi of the phylum Pseudomonas. In addition, there is a subphylum of Ascomycota fungi called Erysiphecichoracearum DC, and Leveilulalinacearum Go10v, also known as Fusarium oxysporum, both of which are possible pathogens.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3034", + "fact_text": "What are the symptoms of the crop base area shown in the image -> In the image, it can be seen that the base of the crop is gradually rotting and turning into mud, with some foul odor.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5401", + "fact_text": "So what are the characteristics of this insect's behavioral habits -> This type of insect is most active in warmer months and usually concentrates on certain leaves, causing concentrated damage. The behavior of young larvae is particularly evident, and they then disperse to other areas to continue to harm.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image4686", + "fact_text": "What specific damage will this pest cause to crops -> This type of pest can cause damage to the flower organs of barley, feeding on the slurry of wheat grains, preventing them from filling properly, and even turning into empty grains. It can also cause damage to the protective and outer glumes of spikelets, causing them to shrink or wither, turn yellow or black brown, and be susceptible to bacterial infection, thereby inducing mold or decay.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "wheat phloeothrips 91", + "fact_text": "Is the insect body color in the picture yellow brown Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5447", + "fact_text": "How will these egg masses affect plants -> The larvae hatched from these egg blocks may burrow into the soil and begin to feed on the plant's roots, which further damages the plant's roots, affects its water absorption and nutrient absorption capacity, and ultimately leads to plant growth restriction or death.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image307", + "fact_text": "What role does the use of nitrogen fertilizer play in this -> Excessive application of nitrogen fertilizer can delay the decomposition of chlorophyll, thereby affecting the accumulation of pigments on the fruit surface and uniform coloring.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5492", + "fact_text": "How did this situation arise -> Produced by some insect larvae gnawing on leaves. These larvae generally gather together to cause damage, resulting in a more concentrated area of affected leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image573", + "fact_text": "What is the climate suitable for the spread of this disease in the image -> This disease is suitable for spreading in climates with low temperatures and high humidity, specifically when the daytime temperature is below 24 ℃, the nighttime temperature exceeds 10 ℃, and the relative humidity is maintained at 75% to 100%.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image3193", + "fact_text": "Are there any other symptoms like this in other areas -> Yes, usually when a disease occurs in an area, adjacent plants may also exhibit similar symptoms, and the disease can spread through soil, water, or tools.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5416", + "fact_text": "How should we effectively prevent and control this pest -> In spring, specific pesticides can be sprayed, such as 50% phoxim emulsion 1500 times solution or 10% imidacloprid wettable powder 2500 times solution. In addition, when pests enter peanut fields, the preferred control method should be to use 40% Qixingbao emulsion 600-800 times solution or 5% Ruijinte suspension 1500 times solution, etc.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "pepper virus disease 173", + "fact_text": "What factors are causing the phenomenon on the blades in the picture -> Chili pepper virus disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4584", + "fact_text": "So, what preventive measures can be taken to avoid the occurrence of these diseases -> Prevention methods include using virus-free seed potatoes, avoiding the cultivation of susceptible varieties, and attempting to use resistant or disease tolerant varieties. Management can also improve cultivation measures, including early removal of diseased plants, timely soil cultivation, avoiding excessive nitrogen fertilizer and increasing phosphorus and potassium fertilizer application, timely intercropping and weeding, controlling autumn water, and finally, timely prevention and control of aphids. In the early stages of the disease, appropriate pesticides can also be used for spraying.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4670", + "fact_text": "What is the color of this pest -> According to the description, the adults of this pest are brown with purple hues, while the head and chest are yellow brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2007", + "fact_text": "What is the color of these leaves -> Severely ill leaves will present a yellow green color, while severely ill leaves will turn yellow.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4737", + "fact_text": "Are there any abnormal dents or spots on the surface of the crops in the image -> Yes, there are indeed gray white or withered yellow fine spots on the leaves of crops, which are caused by insect pests squeezing the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5278", + "fact_text": "In which regions does this pest mainly occur in the image -> This type of pest mainly occurs in areas such as Shawan, Shihezi, and Manas in Xinjiang, as well as some former Soviet areas abroad.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4726", + "fact_text": "How long is the life cycle of this pest -> This type of pest can grow up to 3 to 8 generations per year depending on the region. The overwintering generation uses diapause pupae to overwinter in the soil. For example, in the Yellow River Basin, overwintering adults first appear in late April. The first generation of larvae mainly damage crops such as wheat, while the second generation of adults first appear in mid July. In addition to cotton, the third and fourth generations also damage crops such as corn, sorghum, peanuts, beans, and tomatoes.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3885", + "fact_text": "What are the effects of diseases on mushrooms in these stages -> At these stages, the disease on mushrooms manifests as irregular light brown to yellow brown patches beginning to appear.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "potato hollow heart 25", + "fact_text": "What shape does the affected area in the picture take on -> Flat mouth shape", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image2619", + "fact_text": "What type of soil in the image will affect this situation -> The soil where cucumber plants are located may contain high levels of clay and organic matter. This type of soil may cause the leaf spoon shape and yellowing of cucumbers due to the difficulty of copper absorption by plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3363", + "fact_text": "What is the soil condition in the image -> The soil appears moist and may experience compaction or waterlogging due to improper water and fertilizer management.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5219", + "fact_text": "Are fruits also affected -> The fruit is also affected, exhibiting yellow brown or gray circular lesions, and there are also gray black small dots on the lesions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image5184", + "fact_text": "When does the disease of the fruit in this impact picture become apparent within a year -> In spring, as the temperature rises and the humidity within the country increases, the impact becomes more pronounced.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5243", + "fact_text": "What happened in the image -> According to the provided information, the cotton in the image has been affected by a pest called beet armyworm.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4525", + "fact_text": "What is the mode of transmission of this disease -> The spread of this disease is mainly through the use of airflow and rainwater splashing. The bacteria overwinter on the diseased body and produce conidia in the spring of the following year for initial infection and re infection. In addition, rainy or foggy weather with high humidity, as well as poor plant growth or excessive application of nitrogen fertilizer leading to excessive crop growth, can exacerbate the occurrence of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5271", + "fact_text": "What are the activity habits of this insect -> The adults of this insect are active during the day, with the highest activity around 10 o'clock and around 16 o'clock. They feign death and land when disturbed; At night and on cloudy and rainy days, there is little activity and it often lurks between branches and leaves, as well as in soil crevices around crop roots. May to June causes the most severe damage. After feeding for a period of time, adults begin to mate and lay eggs. The spawning period is about 40 days, and each female can lay more than 200 eggs. The spawning period is 11-19 days. The larvae live in the soil and harm the underground tissues of plants. They build soil chambers to overwinter in late September.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5274", + "fact_text": "How to prevent the occurrence of such pests and diseases -> The prevention and control of this type of insect can be found in the prevention and control methods of the sesame pest, the short fronted locust. Because they all belong to the Orthoptera order, there is a certain degree of similarity. However, specific prevention and control measures need to be reasonably formulated in conjunction with local climate, conditions, and the habits of this pest.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5039", + "fact_text": "What are the plant species in the image -> The plant in the image is soybean.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "corn mole cricket 74", + "fact_text": "What is the scientific name of the insect in the picture Answer: Mole cracket", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image559", + "fact_text": "Are there any other changes on the surface of these damaged areas -> Yes, under humid conditions, you can see sparse white mold growth on the surface of the damaged area, even in cracks.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4730", + "fact_text": "So what are the living habits of this pest -> This pest occurs more frequently in the eastern region and south of Liaoning, with a clear life cycle. Generally, it begins to emerge from May to June, with adults sleeping during the day and emerging at night, exhibiting phototaxis. Eggs are laid in clumps on the back of leaves, up to hundreds. After hatching, larvae will cluster and cause damage, and after about 3 instars, they will begin to disperse and cause damage. The larvae are agile in their movements, and when they mature, they will enter shallow soil or under fallen leaves to form cocoons and pupae.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4473", + "fact_text": "Can the pathogen causing this disease be described -> Yes, the pathogen of this disease is Fusarium oxysporum. This type of fungus does not produce spores and mainly spreads and reproduces through mycelium. The primary hyphae are colorless, and later turn yellow brown with septa. Mature hyphae often form a series of barrel shaped cells. The nucleus is nearly spherical or amorphous, colorless or light brown to black brown. The sexual state of the fungus is Melon Fusarium, belonging to the phylum Basidiomycota.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3785", + "fact_text": "Does this type of necrotic spot have a tendency towards sinking -> Yes, these necrotic spots are slightly sunken.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "vitis apolygus lucorum 263", + "fact_text": "What diseases have affected the fruit in the picture -> Apolygus lucorum", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "pepper root rot 191", + "fact_text": "What disease is causing this phenomenon in the picture -> Chili root rot disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image2414", + "fact_text": "Are there any other organisms around these affected plants -> It seems that some aphid like insects can be seen in the image, which may be closely related to the spread of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5542", + "fact_text": "What measures are usually taken to prevent and control this disease -> It is usually recommended to adopt reasonable dense planting and strengthen management, such as timely cleaning of the fields after harvest to reduce bacterial sources. Once the disease occurs, it can be sprayed with a 600 fold solution of 36% methylthiophanate suspension or a 1500 fold solution of 50% benazepril wettable powder.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1483", + "fact_text": "How big are these white blister shaped spore clusters usually -> Their diameter is usually between 1 and 10 millimeters.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1624", + "fact_text": "What impact does the cultivation environment of the crops in the picture have on the diseases -> The high humidity environment in the field is very conducive to the occurrence of this disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "vitis brevipoalpus lewisi mcgregor 52", + "fact_text": "Please name the insect in the picture. -> Brevipoulpus lewisi McGregor", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4412", + "fact_text": "How much impact will the spread of diseases have on crops -> If there is a 5% mixture of elongated substances in the seeds, even precious Chinese medicinal materials cannot be used for food or feed.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4077", + "fact_text": "Is there any special handling or prevention method in this situation -> There are indeed several ways to prevent such problems. For example, selecting tomato varieties with strong crack resistance, managing water and fertilizer reasonably, ensuring suitable and stable soil moisture, and preventing soil from becoming dry and wet. In addition, calcium and boron fertilizers should be supplemented to prevent fruit cracking caused by insufficient nutrition, and some sunlight should be blocked during planting to reduce skin aging.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2130", + "fact_text": "Why do seedlings collapse -> Due to the weak structure caused by diseases at the base or middle of the stem, as well as the expansion and constriction of the diseased area, the supporting force of the seedlings is insufficient and they are prone to lodging. Minor external forces on seedlings may also lead to breakage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5375", + "fact_text": "Do the species in the image have any special habits -> This type of pest grows 4-5 generations annually in North China, 5-6 generations in the Yangtze River Basin, and 6-9 generations in Fujian. The specific period of severe damage is usually from July to October. Its adult insects are active at night and have strong flying ability. They can fly tens of meters at a time, reaching over 10 meters in height. Adults have phototaxis and have a tendency towards sugar, vinegar, wine, fermented carrots, malt, bean cakes, cow manure, etc.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5501", + "fact_text": "What color are the insects on this picture -> The insect body in the picture is black and covered with shiny pink green scales, sometimes with a small amount of gray to grayish yellow. Usually, there is also an orange yellow powder that gives them a yellow green color.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4714", + "fact_text": "What are the ways to prevent this pest -> When there are 10 pests per square meter on weeds in the field or 30 pests per 100 corn plants, immediate prevention and control measures should be taken. The specific prevention and control methods include spraying pesticides such as trichlorfon, and using 48% Lisbon emulsion can also achieve results. However, for sorghum, it should be noted that sorghum is more sensitive to certain pesticides, and improper use of drugs may cause drug damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image3879", + "fact_text": "What is the main route of transmission for this bacterial brown spot disease -> Mainly transmitted through air containing mushroom spores, insects, artificial water spraying, and unclean cultivation tools.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3259", + "fact_text": "What are the effective methods for controlling this disease -> Effective methods include using high ridge cultivation, timely drainage, timely application of appropriate medication spraying, and selecting sowing times to avoid high incidence periods.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "tea bird eye spot 401", + "fact_text": "Does tea bird eye spot cause pitting of lesions Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5445", + "fact_text": "When is this type of injury usually more severe -> The damage is usually more severe in the mature larval stage, when they disperse to different leaves for widespread feeding.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4735", + "fact_text": "When do they usually move -> This type of pest is most active at a daily temperature of 21-27 ℃, and it takes about 10 to 18 days to complete a generation at this temperature. In addition, when the daily average temperature is 17.2 ℃, adults can survive for 73 days; However, if the daily average temperature reaches 27.2 ℃, the survival period of adults will be shortened to only 20 days. In Guizhou, thrips give birth to 13 generations each year, and the overwintering adults begin their activity in the wheat field in early March of the following year, and then migrate to the rice field in early May. The rice tube thrips give birth to 8 generations every year in Guizhou. After overwintering, the adults lay eggs on rice ears or maize male ears during the wheat flowering period of the following year.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4644", + "fact_text": "What are the morphological characteristics of insect pests -> The adult insect in the image is approximately 3.5-4.8mm in length, with a mosquito like shape and a light red color. It has 15 yellow antennae, and the shape of the 3-14 antennae differs between females and males. The shape of females is approximately cylindrical, while males are gourd shaped. The forewings are transparent and have 4 veins.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1997", + "fact_text": "Specifically, what are the surface features of these patches -> The surface of these plaques shows a white mold layer, which is a manifestation of pathogen conidia.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5253", + "fact_text": "What is its shape or size -> This insect is relatively large, with an adult body length of 12-18mm and a body width of 3.5-5.5mm. In terms of shape, the characteristics of its head, chest, back panel, and front wings are very unique.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3538", + "fact_text": "Has the root of the plant also been affected -> The root is not directly displayed in the image, but it can be inferred from the condition of the bulb that the root may also be affected.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "wheat cerodonta denticornis 18", + "fact_text": "Is the phenomenon in the picture caused by biting the leaf flesh Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5446", + "fact_text": "Are there any signs of insect activity on the trees in the image -> It can be observed that there may be small filamentous objects around the damaged leaves, which may be silk left by certain insects. Insects may hide or cause more damage within the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "mango cicadellidae 1196", + "fact_text": "Does the insect in the picture have compound eyes Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2094", + "fact_text": "What is the impact of this situation on the overall plant -> When this disease is severe, it may cause the entire plant to lose vitality and die quickly, especially when the infected area is widespread.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5200", + "fact_text": "How should this situation be managed and prevented -> Management and preventive measures mainly include selecting disease resistant varieties and cultivating healthy seedlings. In addition, it is important to strengthen plant management and avoid damage and overly tight cultivation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4701", + "fact_text": "Can you describe the appearance characteristics of insect pests -> The length of the pest body displayed in the image is generally 14-18mm, with a wingspan of 30-38mm, and it is grayish brown. Its front wings have brown kidney shaped stripes and circular stripes. There are two brown stripes on the front edge veins of the kidney shaped stripes, and a wide brown horizontal band on the outer side of the kidney stripes. There are black spots between the veins in the end area. The hind wings are light brown to yellow white, with black or dark brown tips.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5275", + "fact_text": "How to prevent and control this pest -> There are three ways to deal with this pest: agricultural control, biological control, and chemical control. In agricultural prevention and control, wheat and cotton can be harvested in fields or regions, and wheat can be transported out of the field in a timely manner to prevent the transfer of corn borers to cotton plants. In biological control, red eyed bees can be released and Beauveria bassiana or B, t emulsion can be sprayed. In chemical control, 2.5% deltamethrin cheese emulsion at 2000 times or 50% parathion emulsion at 2000 times can be used.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image383", + "fact_text": "So, how can we prevent this situation from happening -> Magnesium containing fertilizers should be used reasonably and the soil pH should be kept neutral, avoiding excessive use of potassium containing fertilizers to reduce the antagonistic effect between potassium and magnesium.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image4885", + "fact_text": "Where does this weed usually grow -> This type of plum grass usually grows in damp farmland, ditches, or roadsides.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4844", + "fact_text": "What is its activity mode -> This type of animal is active during the day, especially during hot midday weather and high surface temperatures in summer, and their activity outside the cave will decrease. Their activities show two peaks in the morning and afternoon, and the interval between these two peaks will be shortened in winter. When there is snow, they will continue to dig holes under the snow.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2790", + "fact_text": "How do these symptoms affect fruit ripening -> Severe infection can lead to significant changes in ring patterns and color in mature fruits, and the fruits may also shrink, sometimes similar to navel rot, but the epidermis may turn brown and necrotic, unlike navel rot.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1172", + "fact_text": "Are there any effective preventive measures that can be taken -> Effective preventive measures include adjusting soil pH, promptly removing and destroying diseased plants, and using appropriate fungicides in the early stages.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5018", + "fact_text": "How can we prevent this situation from happening -> We can plant crops by using high ridges or in high dry plots with limited water content. In addition, timely drainage when encountering rainwater can also prevent water accumulation, thereby preventing such problems from occurring.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image503", + "fact_text": "Is it possible to cause the entire plant to die -> Yes, if this situation continues to worsen and is not effectively managed and treated, the entire plant may eventually die due to complete leaf withering.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4453", + "fact_text": "What are the effects of this nitrogen deficiency symptom on seedlings -> Nitrogen deficiency can lead to stunting and emaciation of seedlings, affecting their normal growth. Nitrogen deficiency during the seedling stage may have long-term adverse effects on the development of the entire plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1961", + "fact_text": "Does the image look abnormal -> The stem base of the cabbage in the image appears to have water soaked light brown spots, with indistinct edges, indicating that the disease has begun to develop.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4966", + "fact_text": "What is the pathogen of the disease -> The pathogen of this disease is a fungus called Macropomaabouti10mis NakataetTakim, with a conidia size of approximately 125-150 ΞΌ m. And it grows many oval shaped conidia.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4596", + "fact_text": "What is the condition of the plant roots in the image -> The roots appear short and thick, brown in color, which may be caused by certain nutrient deficiencies.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5076", + "fact_text": "How to prevent and control this problem -> The prevention and control methods include implementing rotation for more than 3 years and avoiding planting on soil that is prone to waterlogging or acidic conditions; Use disease-free soil for seedling cultivation and transplanting of crops, or disinfect the seedbed before sowing; Improve the soil by adding lime and organic fertilizer to acidic soil as much as possible; Timely drain the accumulated water in the field, carefully remove and destroy the diseased plants, and remove lime around the diseased hole to prevent the spread of pathogens; When appropriate, chemical pesticides can be used for root irrigation treatment, etc.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image2442", + "fact_text": "Is there any different expression on the back of this type of leaf -> Yes, a white layer of mold will appear on the back of the leaves in humid environments.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5251", + "fact_text": "Are there any significant insect infestations in the image -> Yes, you can see some small insect bodies on the back of the leaves, which may be the cause of leaf damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "corn potosiabre vitarsis 267", + "fact_text": "What color is the body color of the insect in the picture Answer: White", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5039", + "fact_text": "How does this disease spread? Under what conditions is it easy to explode -> This type of pathogen mainly overwinters on the diseased residue through conidia or on diseased seeds through hyphae, and then becomes a source of infection at the beginning of the following year. The occurrence and prevalence of this disease are related to the amount of rainfall during the pod setting period, and the incidence is more severe in years with more cloudy and rainy weather. In the south, August to October is the most common period, while in the north, it is more likely to occur from August to September.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1467", + "fact_text": "What methods can prevent this situation from happening -> Prevention can be achieved by timely digging out diseased plants, burying or burning them deeply, and applying fully decomposed organic fertilizers. In addition, specific pesticides can also be used for spraying, such as copper oxychloride suspension, ethylphosphoaluminum wettable powder, and agricultural streptomycin sulfate.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "cowpea rust 3", + "fact_text": "What kind of disease does the symptom in the picture indicate being infected with Answer: Cowpea rust", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4129", + "fact_text": "How is the growth of tomato plants -> The image shows that the growth of tomato growth points is stopped or inhibited, and the growth rate of the entire plant appears to be affected.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1116", + "fact_text": "Are these measures easy to implement -> Yes, by carefully monitoring environmental conditions and fertilization plans, these measures can be effectively implemented to help prevent abnormalities in eggplant fruits and plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4437", + "fact_text": "What caused this -> The crop diseases in the image may be caused by a bacterium called Erwiniachrysanthemipv. zeae (Sabet) Victoria, Arb01edaetMunoz with the synonym E. carotovoraf. sp. zeae Sabet. The bacterial body is rod-shaped, bluntly round at both ends, solitary, and occasionally double stranded.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4282", + "fact_text": "Is there any prevention and control method for this disease -> The prevention and control methods include implementing quarantine to prevent bacteria from entering disease-free areas; Implement rotation for more than 2 years; Before sowing, use salt water to select seeds, remove diseased seeds, and then disinfect the seeds; Avoid using too much nitrogen fertilizer; Apply resistant varieties and other methods. Spraying pesticides once each during the flowering and early flowering stages in areas or years with severe diseases is also an effective method of prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "wheat septoria 5", + "fact_text": "Will Wheat Leaf Blotch harm the stems and ears of wheat Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "wheat chillella leaf blight 2", + "fact_text": "What is the pathogen of wheat snow rot and leaf blight -> Snow rot Grignard mold", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1920", + "fact_text": "What are the current methods to alleviate these symptoms -> There are several ways to alleviate symptoms: selecting disease resistant varieties, timely sowing and planting to avoid aphid infestation and low temperature periods; Timely prevention and control of aphids, and use recommended pesticides for spraying in the early stages of the disease, such as 5% bacterial toxin clear powder or 20% virus Ning water-soluble powder.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4907", + "fact_text": "Is it possible for this condition to recover naturally -> It is unlikely that once wilt disease spreads in cotton plants, it is difficult to solve through natural recovery and usually requires appropriate disease management and prevention measures to control and treat it.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4758", + "fact_text": "What color do the insects in the image look like -> The body of the insect is bright green or light green, with 4 antennae and red, so it is called the red bearded bug.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4726", + "fact_text": "Do the pests in the image have any natural enemies -> The natural enemies of this pest include over 60 species, including red eyed bees, woolly cocoon bees, cocoon bees, wasps, parasitoids, spiders, grasshoppers, ladybugs, praying mantis, and small flower bugs.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image5418", + "fact_text": "Which part of the plant is most severely affected by this pest and disease -> This type of pest and disease has the most serious impact on the tender leaves of plants. The initial sign of the disease is the appearance of reddish brown streaks on both sides of the leaf veins, and the leaf surface will bulge. If the disease and pest infestation are severe, brown spots will appear on the back of the leaves, the buds and leaves will shrink, and the leaves will curl inward, becoming stiff and fragile.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4775", + "fact_text": "When did these larvae affect crops -> This type of larva can produce 3-9 generations per year, with the highest occurrence occurring from July to August. They will start causing harm when new yam sprouts and lay their eggs near the middle ribs of tender leaves, so that they can start feeding directly after hatching.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "tomato yellow leaf curl virus 539", + "fact_text": "Can tomato yellowing and curling virus disease cause thickening and hardening of leaves Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image430", + "fact_text": "What specific problems will intensive planting lead to -> Intensive planting may lead to poor air circulation and high humidity, which can create favorable conditions for the occurrence and spread of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "mango deporaus marginatus pascoe 28", + "fact_text": "Does the insect in the picture have four pairs of legs Answer: No", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "corn amsacta lactinea 2", + "fact_text": "What is the insect in the picture called -> Amsacta lactinea", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4393", + "fact_text": "What are the common reasons for this color change -> This color may be caused by a lack of nitrogen in plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "management instructions", + "entity": "image5363", + "fact_text": "How should we prevent and deal with this pest in the future -> An effective prevention method is to cultivate and weed cruciferous vegetables in a timely manner after harvest to reduce the source of pests. It is possible to sow some vulnerable crops early, such as rapeseed, cabbage, and radish, to avoid the period of larval infestation. For diseases that have already occurred, relevant pesticides can be sprayed during the larval stage, such as 50% phoxim emulsion at 1500 times, 35% phoxim emulsion, or 50% malathion emulsion at 1000 times.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4739", + "fact_text": "What are the prevention and control measures for this pest -> The main prevention and control measures include removing empty grains from sorghum and corn before winter, and promptly dealing with the host's straw, cobs, etc. During the peak spawning period, spraying with phosphorus amine solution, Bacillus thuringiensis solution, or cyanobacterium solution can be chosen.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4314", + "fact_text": "What is the curling form of the affected leaves in the image -> The leaves are curled longitudinally by the larvae into a cylindrical structure, forming what is called insect bracts, which is the way the larvae protect themselves and their feeding grounds.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3416", + "fact_text": "Is this type of problem common in the region -> Yes, this disease is quite common in certain areas, especially in autumn, and often has a high infection rate, sometimes affecting plants throughout the entire area.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image25", + "fact_text": "What is the pattern of occurrence of this disease -> ( 1 ) Variety factors. There are significant differences in susceptibility among different apple varieties. ( 2 ) Climate factors. High temperature and rainy weather, when the temperature is between 10 - 20 ℃ and there is strong sunlight, the symptoms are more severe. ( 3 ) Tree vigor. When the tree is weak, the symptoms are more severe, and young trees are more susceptible to disease than adults. ( 4 ) Cultivation factors. When the soil is dry and there is insufficient water and fertilizer, the disease becomes severe.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5329", + "fact_text": "How is this kind of damage mainly caused -> Damage is caused by certain insects piercing and sucking sap from tender leaves, stems, and other parts of plants, and in severe cases, it can lead to partial leaf death.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5326", + "fact_text": "What kind of damage will crop pests cause to it -> In the image, this pest can cause damage to flax sprouts, leaves, and capsules, resulting in irregular gaps in the affected capsules.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "rice koji disease 3", + "fact_text": "What disease has affected this spore in the picture -> Rice smut disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2810", + "fact_text": "How did this situation arise -> This is usually caused by the excessive use of ethylene glycol ripening treatment, which can be caused by high concentration or excessive single fruit adhesion solution.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5268", + "fact_text": "What are the habits of this pest -> This pest can produce 10-12 generations per year in subtropical regions, with a population peak almost every month. The growth cycle of this insect varies with temperature. It stops developing below 12 ℃ and begins laying eggs above 14.5 ℃. Adults love windless and warm weather very much, and have a tendency towards light sources.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4592", + "fact_text": "May the soil type in the picture affect the absorption of these nutrients by plants -> Yes, soil type has a significant impact on nutrient availability. For example, lightweight soil may lead to plant phosphorus deficiency due to low natural phosphorus content; Plants on heavy soil may become unavailable for phosphorus due to soil consolidation. In addition, sandy soil has low organic matter content, and acidity may inhibit nitrification, leading to nitrogen deficiency.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5417", + "fact_text": "Are there any prevention and control methods to prevent crops from being more severely damaged -> Some, as early as the spring when the large thrips began to concentrate in crop fields, specific pesticides such as 50% phoxim emulsion 1500 times solution or 10% imidacloprid wettable powder 2500 times solution should be sprayed. In addition, once they enter the peanut field, effective prevention and control products such as 40% Qixingbao emulsion 600-800 times liquid, 5% Ruijinte suspension 1500 times liquid, and 10% Depleted emulsion 2000 times liquid should be used immediately.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1345", + "fact_text": "Is this situation attributed to external environmental factors -> Yes, this may be due to sudden changes in the high temperature and humidity environment, such as blade dehydration caused by sudden wind release.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4795", + "fact_text": "So what are the characteristics of its lifestyle habits -> The main host of this pest is soybeans, which can occur multiple generations within a year. In Guangdong, there can be 7 generations per year without any obvious overwintering phenomenon. The duration of its damage may vary depending on the season and host species. Therefore, we can believe that its lifestyle is closely related to environmental factors.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image4859", + "fact_text": "What type of plant does the image look like -> The plant in the image is a weed with an upright stem that can grow alone or in clusters, with several distinct nodes.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2766", + "fact_text": "What is the overall condition of the leaves -> After infection, the affected area of the leaf may become thinner and eventually rupture and perforation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "cowpea rust 1", + "fact_text": "What kind of disease has affected the leaves in the picture Answer: Cowpea rust", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1449", + "fact_text": "Under what conditions do these symptoms typically occur -> This situation is mainly due to the soil being excessively wet for a long time, lacking good air permeability, leading to root hypoxia.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2100", + "fact_text": "What is the overall performance of the leaves in the case of severe infection -> In severe cases, multiple lesions can merge into patches, leading to overall leaf drying.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image1259", + "fact_text": "What are the commonly used methods for controlling this disease -> An effective method is to use pesticides for spraying, such as 40% methyl copper wettable powder, while also improving field management, such as optimizing drainage and reducing nitrogen fertilizer use.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4808", + "fact_text": "Where does this adult usually emerge -> This type of adult prefers to emerge in the early morning, usually directly penetrating the top of the film in the grain for emergence.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2057", + "fact_text": "Are the stripes on these leaves widely distributed -> The stripes are mainly distributed along the leaf veins and are relatively concentrated, not widely distributed throughout the entire leaf surface.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2410", + "fact_text": "How is this disease usually prevented and treated -> Effective prevention and control methods include seed treatment, crop rotation, timely sowing, and deep plowing in autumn to reduce bacterial sources. In addition, removing and destroying diseased ears is also one of the important measures to prevent and control the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "tomato leaf miner 22", + "fact_text": "What insect is causing the white cave in the picture Answer: Leaf miner", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4635", + "fact_text": "At what stages are these pests usually more active -> Depending on the season, this type of pest becomes active from the end of April, especially between May and June when adults begin to appear and their activity increases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5792", + "fact_text": "What are the main damages caused by these larvae -> Larvae mainly cause damage by consuming tender buds and leaves, and larger larvae may even completely consume the leaves, leaving only the petioles, which has a particularly serious impact on seedlings and young trees.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1526", + "fact_text": "What changes will these spots cause in the leaves and stems -> The affected leaves and stems will gradually necrosis, and in severe cases, the disease can lead to the death of the entire leaf or stem tissue, seriously affecting the overall growth and yield of celery.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image4877", + "fact_text": "Why is this plant usually considered in agriculture -> This plant is usually considered a weed in agriculture. Due to its growth in wetlands and low-lying areas, it may compete with crops for growth resources and is therefore considered a plant that is not conducive to crop growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4135", + "fact_text": "What are the characteristics of leaf color changes -> In addition to the basic color of the leaves changing from green to purple infrared, it is also noticed that the veins of the leaves will undergo color changes, turning into purple red, which is a typical feature of phosphorus deficiency.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5375", + "fact_text": "What other plants are generally affected by this pest -> In addition to mulberry trees, this pest can also cause damage to cotton, corn, sweet potatoes, taro, lotus roots, and many other vegetables.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2825", + "fact_text": "What are the main reasons for the emergence of these problems -> These problems are mainly due to a lack of sufficient potassium in the soil, especially during the rapid expansion stage of tomato fruits, when the potassium demand increases significantly.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "mango cicadellidae 1196", + "fact_text": "Can leafhoppers spread viruses Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "tomato leaf miner 55", + "fact_text": "Is the white underground passage in the picture caused by the bite of the leaf flesh Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5410", + "fact_text": "Is there any effective method to deal with this type of insect -> Effective management methods include using appropriate pesticides for spraying and implementing appropriate agricultural management measures to reduce their impact.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "corn southern leaf blight 1", + "fact_text": "What disease is the leaf in the picture suffering from -> Corn southern leaf light", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5300", + "fact_text": "Where do these insects usually move around -> The insects shown in the image usually inhabit sugarcane leaves or leaf sheaths during the day and only begin to move after dusk.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4819", + "fact_text": "What are the effective methods to combat this pest -> Effective strategies include autumn or spring plowing to kill eggs, early sowing and timely removal of weeds, and using sugar and vinegar or other fermented foods to attract adults for trapping and killing. Chemical control can use specific emulsions or granules for treatment during the weaker larval stage of the insect.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1073", + "fact_text": "Are there effective preventive measures in place -> Adopting appropriate cultivation measures, such as selecting disease resistant varieties and appropriate soil management, can effectively prevent diseases. In addition, according to climatic conditions, spraying appropriate pesticides before the rainy season is also an effective prevention method.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image843", + "fact_text": "Under what climatic conditions does this situation usually occur -> This situation often occurs in warm and humid environments, especially when the humidity gradually increases at night and the leaves are prone to condensation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "tomato leaf miner 22", + "fact_text": "What color is the acupoint in the picture Answer: White", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image4871", + "fact_text": "Where does this plant usually grow -> This type of plant prefers to grow in drier areas on slopes or roadsides, and is commonly found as a weed on the ground and in nurseries.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5429", + "fact_text": "How to prevent and control this pest -> Agricultural prevention and control measures can be taken, such as in areas with severe occurrence of short frontal locusts, removing soil and weeds more than 5 centimeters from the fields and edges of the land in autumn or spring, exposing the egg masses to sunlight to dry, or causing them to be frostbitten at low temperatures. In addition, natural enemies of pests such as sparrows, frogs, and large parasitic flies can also be utilized for biological control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2605", + "fact_text": "Is there any special method to alleviate or prevent this situation -> Indeed, adjusting the temperature and light appropriately, watering and fertilizing in a timely manner, especially using boron containing compound micro fertilizers for spraying, can alleviate this situation to a certain extent. However, the use of gibberellin for treatment should be avoided as it may bring about another extreme situation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4775", + "fact_text": "What is the difference between the colored parts on the surface of crops and other parts -> The colored part of the crop surface is the damage caused by insects on the crop surface. These marks are curved scars, forming a sharp contrast with the smooth texture of the healthy potato surface and leaf surface.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2004", + "fact_text": "What is their surface texture like -> In the image, slight white mold can be seen on the surface of some pea seedlings, which is a manifestation of the initial disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5427", + "fact_text": "What are the living habits of pests -> This type of pest has a different life cycle in different regions, such as one generation per year in Henan, Hubei, and other regions, and three generations per year in the south of Guangdong; The last generation pupae overwinter in soil chambers 6-10cm deep underground in various regions. The larvae feed day and night, and their leaves are often eaten up. Adults sleep during the day and emerge at night, exhibiting phototaxis. When startled, friction between abdominal segments can cause squeaking sounds.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4751", + "fact_text": "How should we prevent and control this pest -> The prevention and control methods for this pest can refer to the prevention and control methods of the double spotted firefly beetle.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "potato early blight 4", + "fact_text": "What factors are causing the phenomenon on the blades in the picture -> Potato early brightness", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1836", + "fact_text": "Is the range of plants affected in the picture large -> The image shows that although it mainly harms the leaves of lentils, if the conditions are suitable, such as warm and humid weather, the disease may affect more leaves and even the entire plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4436", + "fact_text": "What is the cause of this abnormal phenomenon -> This phenomenon is believed to be associated with a pathogen called Ascomyctazeae Stout. This is a fungus belonging to the subphylum Pseudomonas, whose conidia are buried in diseased leaves or stem tissues, which may be the main cause of the aforementioned diseases. In addition, this disease is related to the clustering of aphids within the leaf sheath, especially when the weather turns cold, the behavior of aphids may accelerate the occurrence of the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4721", + "fact_text": "Is there any insect infestation found in the image -> Yes, the broad beans in the image have pest problems, specifically a type of insect called red leaf mite.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4024", + "fact_text": "What environmental factors will exacerbate this situation -> The development of mosaic virus is closely related to temperature, especially in environments of 20-25 ℃. In addition, poor cultivation conditions, such as dense planting and lack of necessary nutrients such as calcium, potassium, and phosphorus, can also exacerbate the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2105", + "fact_text": "How to prevent and treat these symptoms from further developing in this situation -> The countermeasures include using copper containing suspension agents for spraying, such as 27% copper noble suspension agent 500 times liquid or 78% Kebo wettable powder 500 times liquid, and 20% Longke bacteria suspension agent 500 times liquid, spraying every 7 days, continuously for one to two times.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image367", + "fact_text": "What is the texture of the fruit peel -> The area where brown spots appear will have a harder skin due to corkification on the surface.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4091", + "fact_text": "Do the tomato leaves in the image show signs of nutrient deficiency -> Yes, some parts of the leaves seen in the image show yellow spots, but the veins are still green. This situation looks like magnesium deficiency, but in reality, it is not.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3182", + "fact_text": "Is the development speed of this disease fast -> Once the conditions are suitable, such as high temperature and humidity, the development of diseases will be rapid.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image4885", + "fact_text": "What type of plant does the image look like -> The plant in the image is a weed with upright stems and slender leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2126", + "fact_text": "Does the cucumber leaf in the image look normal -> The cucumber leaves in the image exhibit deformities and irregular shapes compared to normal leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1934", + "fact_text": "How does the seed of cauliflower reflect the symptoms of disease in the image -> The seeds themselves are not visually displayed in the image, but infected plants may cause the seeds to carry pathogens.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4139", + "fact_text": "What is the general reason for this situation -> Although the phosphorus content in the soil may not be low, due to soil compaction or other unsuitable growth conditions, such as drought or low humidity, it may hinder the absorption of phosphorus by the roots, causing these symptoms.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2866", + "fact_text": "Under what conditions does this phenomenon usually occur -> This phenomenon often occurs in greenhouses in winter and early spring. If seedlings grow under low temperatures of about 5 ℃ to 7 ℃, it may cause this situation. At the same time, excessive nitrogen fertilizer or watering, as well as insufficient calcium nutrition, can also increase the likelihood of occurrence.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image1972", + "fact_text": "What consequences will the dense distribution of disease spots on this type of leaf lead to -> If the leaves are densely covered with disease spots, it will seriously affect the photosynthesis function of the leaves, leading to damage to the overall health of the crop, and in severe cases, may cause the entire leaves to wither.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5257", + "fact_text": "Is there any abnormal behavior on the leaves in the image -> The leaves in the image show symptoms of yellowing and curling, and some of these leaves also show signs of shedding.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tea algal leaf 120", + "fact_text": "What factors have affected the leaves in the picture -> Tea algae leaf spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4314", + "fact_text": "Why do the rice leaves in the image have reddish brown spots -> This usually indicates that rice is experiencing potassium deficiency and red brown spots on the leaves are one of the typical symptoms.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2669", + "fact_text": "How to prevent this situation through agricultural measures -> Appropriate agricultural measures include the use of disease-free seeds, timely late sowing to avoid hot and rainy seasons, applying sufficient manure and increasing phosphorus and potassium fertilizers, and timely drainage after rain.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5251", + "fact_text": "Are there any insects in the image -> Yes, there should be insect infestations visible in the image. This type of insect has a body length of about 3 millimeters and may be yellow green or yellow brown to reddish brown in color. Some insects may have 2 small black dots at the front edge of the head crown and a small black dot near the end of the claw plate.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5362", + "fact_text": "Is there a guest of honor in the picture -> Yes, the subject in the image is a type of rapeseed, which has been affected by pests.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5803", + "fact_text": "How long does this type of insect last -> The lifespan of adults is approximately 7 to 10 days, which is sufficient to complete the process of mating and egg laying.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1689", + "fact_text": "What is the condition of the roots of the plants in the picture -> From the image, the roots of the plant may indicate insufficient health, which may be related to a lack of sufficient cold resistance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4615", + "fact_text": "What preventive measures can be taken to prevent the recurrence of crop diseases for this problem -> There are several preventive measures that can be taken: first, use formula fertilization technology and fully decomposed organic fertilizer. Secondly, it is necessary to determine the application method and time of potassium fertilizer reasonably based on the amount of fertilization and soil supply. Thirdly, supplement wood ash and spray calcium superphosphate. Fourthly, use compound organic active liquid fertilizer or add fertilizer, etc., for 2-3 sprays.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2077", + "fact_text": "Is there any difference between the lesions on the leaf sheath and the lesions on the leaves -> The lesions on the leaf sheaths are usually large and oval shaped, with a purple red color. Compared to the spots on the leaves, it usually does not produce a mold layer.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1228", + "fact_text": "What are the commonly used chemical treatment methods in the management of such diseases -> Common chemotherapy methods include spray with specific wettable powder or emulsifiable concentrates, and sulfur fumigation in the shed when necessary.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image1232", + "fact_text": "What are the transmission pathways of this type of disease -> Diseases overwinter on diseased bodies and seeds, and spread through stomata through airflow and rainwater, invading crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4647", + "fact_text": "What color is this insect -> In the image, the body color of this insect is gray and dark, with black antennae and bright red wings.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image1329", + "fact_text": "Are there any obvious damages or color differences on these leaves in terms of details -> Yes, there are signs of uneven color on the leaves, which may indicate that nutrient absorption is hindered, which affects the natural color and health status of the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image5424", + "fact_text": "What are the habits of this pest infestation -> This type of pest is highly active in environments with moderate temperature and humidity. For example, in North China and the Yellow River Basin, they reproduce 4 generations per year, while in South China, they can reproduce 6-8 generations. They usually choose to stagnate in the soil during winter. In addition, this pest can also pose a threat to other crops, including corn, sorghum, wheat, rice, tomatoes, etc.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4753", + "fact_text": "So how to prevent and control this pest -> The following measures can be taken to prevent this pest: deep plowing in autumn, clearing weeds on the edge of the field, as well as removing crop roots and fallen leaves in the field. Before sowing, specific pesticides of 0.2% of the seed weight can be used for prevention and control. After the pest activity begins, investigate the pest situation in a timely manner. If 4-5 pests are found per meter, pesticide treatment should be used as soon as possible. Pesticides can also be sprayed if necessary.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "beet fly 41", + "fact_text": "Which part of the insect's body in the picture is colored red Answer: Eyes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5430", + "fact_text": "Is there any effective prevention and control method to deal with the organisms in the image -> The prevention and control methods include hanging bottles on nearby sunflowers or corn when this organism first appears. Put 2-3 of these creatures in the bottle, and when the creatures in the field fly onto the bottle, they will fall into the bottle. Every 667 square meters, 40-50 bottles can be hung to catch and kill this creature, which is very effective.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "corn grub 523", + "fact_text": "Which part of the crop in the picture has been damaged Answer: Leaves", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image225", + "fact_text": "What will the stem look like after spreading -> The stem will turn black and soften, becoming sticky, and sometimes contracting into a linear shape.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5740", + "fact_text": "What are the common causes of these symptoms -> This type of symptom is usually associated with viral infection, where specific viruses can attack the leaves and growth points of plants, leading to phenomena such as lighter leaf color, flower leaf and abnormal development.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4407", + "fact_text": "What color do their leaves appear -> The leaf color is light yellow green, and when the leaf tips dry up, the entire leaf will wither and turn yellow. Some barley have slender and upright stems, sometimes appearing light purple, with few tillers and small spikes.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4459", + "fact_text": "What effective prevention and control methods can alleviate the impact of this disease on corn -> Some effective prevention and control measures include selecting corn varieties that are resistant to low temperatures, and scientifically determining the sowing period based on climate to meet the temperature requirements of each growth stage. The application of phosphorus fertilizer can also improve the growth environment of corn and reduce low-temperature cold damage. If conditions permit, using seedling cultivation and transplantation is also an effective method. In addition, it is advocated to use corn mulching cultivation method to replicate the growth delay caused by low temperature. While ensuring complete and robust seedlings, it is important to control the appropriate time for uncovering the film. Advocate the use of photodegradable and biodegradable films.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2976", + "fact_text": "If drug damage has already occurred, are there any remedial measures -> Some minor pesticide damage can be promoted by timely tillage, loosening the soil, applying an appropriate amount of nitrogen fertilizer, and timely watering to promote plant recovery. For severe pesticide damage, it is necessary to irrigate and apply phosphorus and potassium fertilizers in a timely manner, cultivate and loosen the soil, promote the development of roots, and enhance the recovery ability of plants. Various foliar fertilizers can also be sprayed to help with recovery.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image1115", + "fact_text": "How should we improve our cultivation methods -> Suggest controlling the use of nitrogen fertilizer and water, maintaining appropriate light and temperature to promote healthy plant and fruit growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4674", + "fact_text": "What are the living habits of this insect -> In areas north of Zhejiang and Hunan, this insect produces one generation per year, while in areas south of these areas, it produces two generations per year. They overwinter in soil such as fields, wastelands, embankments, etc. at a depth of 1.5-4cm, or in the rhizosphere of weeds or between rice stubble plants. Starting from 15-45 days after emergence, mating can occur multiple times in a lifetime, and there is a habit of flapping lights during hot and humid nights. Eggs are laid in chunks under the soil, mostly on the field ridges, with 1-3 eggs laid per female. The newly hatched nymphs first feed on weeds, and after 3 instars, they spread to harm English white, rice, or beans. Natural enemies include Qingxi, Mantis, Frog, Spider, Bird, etc.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image5625", + "fact_text": "In which season is this situation usually more common -> This situation often occurs in autumn, especially during the rainy period after autumn, and the condition may worsen due to humid environmental conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1728", + "fact_text": "Will this symptom spread to the entire cabbage -> Yes, if not controlled, this symptom will develop over time to more leaves and stems, ultimately affecting the entire plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4838", + "fact_text": "How do the animals in the picture move -> Animals are usually more active at night and exhibit particular activity in the morning and evening.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2589", + "fact_text": "Do these leaves have any other color changes -> Yes, in addition to whitening or yellowing at the edges, leaf veins also show signs of chlorosis.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "vitis polyphagotars onemus latus 9", + "fact_text": "Is the body color of this creature in the picture light yellow to yellow green Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "beet sericaorient alismots chulsky 70", + "fact_text": "Does the insect in the picture have a large head Answer: No", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image552", + "fact_text": "Can you see mold growth on the fruit in the image -> Yes, it can be observed that some fruits have white moldy growth on their surface.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5312", + "fact_text": "Is there a simple way to prevent such damage -> An effective prevention method is to evenly distribute specific pesticides in the planting ditch during plant planting to reduce the probability of pest damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4708", + "fact_text": "So, if encountering such insects, how should the plants seen in the image be protected -> Firstly, implementing crop rotation between wheat and non cereal crops is an effective protective method. Secondly, the application of 3% methyl isocarbophos granules for soil treatment before sowing is actually very effective. In addition, the use of 2.5% methyl isocarbophos or other organic phosphorus pesticide powders sprayed at noon can also provide a certain protective effect.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4689", + "fact_text": "What are the morphological features of this pest in the image -> This type of pest has a longer body shape and an oval shape. Their body color is dark green with black stripes.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4542", + "fact_text": "What kind of crops are displayed in the image -> In the image, the crop we can see is a type of legume, specifically fava beans.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4835", + "fact_text": "Is there any visible damage on the leaves in the image -> There are notches or holes on the surface of the leaves in the image, which may be caused by insect bites at night.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5348", + "fact_text": "What are the specific signs on these leaves -> There are obvious white insect passages on the leaves, which appear convoluted and tortuous. These are caused by the larvae lurking and feeding inside the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3476", + "fact_text": "Is there any difference on the other side of the blade -> When the humidity is high, dark gray to black mold like substances can be seen on both sides of the disease spots on the leaves, which are the conidia and stem of the pathogenic bacteria.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5258", + "fact_text": "How long does this type of pest usually occur -> In the north, this pest can produce about 10 generations per year, while in Taiwan, it can produce 21 generations per year. The expected developmental cycle for each generation is 41 days.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5263", + "fact_text": "How should we prevent and control this situation -> Prevention and control measures include clearing cotton fields and nearby weeds in early spring before hatching overwintering eggs to reduce overwintering insect sources. At the same time, specific pesticides such as 50% methamidophos emulsion or 50% methyl parathion 1500 fold solution can be used for spraying treatment to effectively reduce the number of pests.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "management instructions", + "entity": "image5138", + "fact_text": "How to reduce the losses caused by crop diseases -> Multiple strategies can be adopted to reduce losses, including planting disease resistant varieties, improving field management such as timely cultivation and intercropping for weed control, and using pesticides for disease management. Especially during humid or rainy seasons, it is particularly important to pay attention to humidity control in the field.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1578", + "fact_text": "How do these lesions affect the productivity of plants -> Severe lesions can lead to leaf detachment, which in turn affects the photosynthesis and growth of the entire plant, ultimately significantly reducing yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5029", + "fact_text": "Is there a pattern in the changes of lesions? For example, which part of the plant does it start from -> This type of lesion usually first occurs in the lower part of the stem, and then gradually spreads to the upper part of the stem. The disease on the stem is most obvious and easily recognizable from the time the plant leaves to the time of harvest.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image30", + "fact_text": "How does the lesion in the picture affect root growth -> Due to the disease causing root rot, plants are unable to grow new roots normally, thereby affecting the growth and nutrient absorption capacity of the entire plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3061", + "fact_text": "What's special about these spots -> The spot gradually expands into a circular or nearly circular shape, with a green edge and a gray white to yellow white central area. The affected area is slightly concave and thinner, making it easy to rupture.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4277", + "fact_text": "Are there any methods to prevent or reduce this disease -> There are many methods to prevent and control this crop disease. Firstly, we can strengthen the quarantine of seeds to prevent diseases from entering disease-free areas. Secondly, choosing the type of disease resistance is also an effective preventive measure. In addition, timely and moderate sun drying of the field, sufficient organic fertilizer should be applied during the tillering stage, and phosphorus, potassium, and silicon fertilizers should be increased. Water management in rice fields is also important. In the later stage of growth, it is necessary to maintain dry and wet rotation, and cultivation should not be too dense to reduce field humidity. Finally, chemical control is also a very effective method.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "apple alternaria leaf spot 4", + "fact_text": "What diseases are affecting the leaves in the picture -> Apple Alternaria Leaf Spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image903", + "fact_text": "Under what conditions does this problem often occur -> This situation is often more common in high-temperature and humid environments. In addition, if water bamboo is continuously cultivated or lacks specific nutrients such as potassium and zinc, the plant's resistance will weaken and it is more susceptible to the impact of this problem.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "grape rhizopus stolnifer 60", + "fact_text": "What factors are causing the abnormal phenomenon in the picture -> Rhizopus stolnifer", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4705", + "fact_text": "What are the specific characteristics of the pests that cause this situation -> The adult insects that cause this condition have a yellow brown body shape and black and white vertical stripes, with a body length of approximately 9-11mm. Their heads tilt downwards, and the front end is pointed and split. Especially, the small shield of this insect pest is particularly developed, shaped like a tongue, and longer than the central part of the insect body.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image4887", + "fact_text": "What crops will be affected by the plants in the picture -> The plants in the picture mainly harm cotton, beans, wheat, vegetables, and fruit trees. Its widespread distribution and strong regenerative ability make it a common weed in farmland.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image1050", + "fact_text": "What measures can be taken to prevent this phenomenon from occurring -> By selecting low temperature resistant varieties, early or delayed cultivation can be carried out to increase temperature and keep warm, and ensure that the ground temperature exceeds 10 ℃. In addition, apply more farmyard manure to improve the effective supply of phosphorus in the soil, and pay attention to the application of magnesium fertilizer, as magnesium deficiency will inhibit the absorption of phosphorus. Spraying potassium dihydrogen phosphate solution in a timely manner during the fruit growth period is also an effective preventive measure.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image285", + "fact_text": "What are the recommended methods for preventing and treating this disease -> It is recommended to use disease resistant varieties and use irrigation methods such as drip irrigation or furrow irrigation to avoid sprinkler irrigation. During the early stages of the disease, spraying is commonly used with pesticides such as 72% neophytomycin 4000 fold solution and 77% wettable powder 500 fold solution.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "corn potosiabre vitarsis 290", + "fact_text": "What is the scientific name of the insect in the picture -> Potosiabere vitality", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5239", + "fact_text": "Is there any effective way to prevent and control this pest at present -> There are various measures to prevent and control this pest, including timely disposal of crop straw such as corn and sorghum before the Qingming Festival, reducing the emergence and egg laying of overwintering larvae; Taking advantage of the Asian corn borer's habit of laying eggs on banana roots, plant banana roots around or near the hemp field to lure and kill the insect; Enhance the prevention and control of corn borers by adding 500 milliliters of 50% parathion emulsion per 667 square meters, diluted with 10 liters of water, and mixed with 25 kilograms of screened coal residue particles; If necessary, during the peak incubation period of corn borer, spray 30 to 35 ml of 5% Regent suspension or 40 ml of 20% fenvalerate buttermilk emulsion every 667 square meters, and 50 liters of water spray.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4460", + "fact_text": "What is the impact of this soil problem on plants -> The salinity and pH of the soil can cause salt alkali damage to plants. This pest usually causes the plant to grow weakly during the seedling stage, and in severe cases, it appears withered. In addition, excessive soil salinity can also affect the growth of plant young roots and buds. Mild cases can lead to an increase in empty stems and an increased likelihood of lodging; In severe cases, it can lead to a shortage of seedlings and broken ridges in plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3559", + "fact_text": "What caused this situation -> This is caused by a type of fungus, specifically an actinomycete, which has a filamentous structure and a spiral like tip.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5267", + "fact_text": "Can you describe the habits of pests in the image -> The adult insect usually pricks the leaves with its ovipositor and sucks on the juice. Female insects lay their eggs under the partially damaged epidermis. The eggs hatch for 2-5 days and the larval stage lasts for 4-7 days. The last instar larvae will bite through the leaf epidermis and pupate outside the leaves or under the soil surface. The pupae will feather into adults after 7-14 days. This type of pest has a short generation and strong reproductive ability.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4706", + "fact_text": "What is the body color of the insect in the image -> The insects in the image are mainly brownish yellow or reddish brown in color, and have black spots on their bodies.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2846", + "fact_text": "How to prevent or improve this situation displayed in images -> To prevent excessive growth, growth inhibitors can be used during the seedling period, and water management should be adjusted and nitrogen fertilizer use should be reduced, especially in conditions of insufficient sunlight.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tea brown blight 334", + "fact_text": "What kind of disease is causing the symptoms exhibited by the leaves in the picture -> Tea brown light", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4674", + "fact_text": "What are the prevention and control methods for this type of insect -> There are various prevention and control methods for insects in the image. One is to organize manpower in areas where they are heavily affected to excavate and turn over ridges, which can kill insect eggs. The second is to protect the natural enemies of insects, such as cicadas, mantis, frogs, spiders, and birds, which can effectively suppress the occurrence of insects. The third is to seize the characteristics of insects gathering on the ridges, edges, and channels to feed on tender leaves before the age of 3, and carry out targeted prevention and control. When they enter the age of 3-4 and there are more than 10 insects in a hundred plants in the field, insecticides should be sprayed in a timely manner. Aircraft should be used for prevention and control during large-scale incidents.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image4883", + "fact_text": "What impact will this plant have on the surrounding crops -> This plant is a weed that mainly affects dry crops and may compete with crops for nutrients and light.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4557", + "fact_text": "How do these viruses spread -> These viruses mainly rely on the host organism for survival and overwintering, and then transmit through sap. In addition to turnip mosaic virus, these viruses may also be transmitted through aphids, and seeds may also transmit viruses, but the transmission rate varies. It is worth noting that the soil cannot transmit these viruses", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "vitis parathrene regalis 25", + "fact_text": "What is the name of the insect in the picture -> Parathrene regalis", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "tomato leaf miner 55", + "fact_text": "What insect is causing the white curvature on the leaves in the picture Answer: Leaf miner", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "grape powdery mildew 196", + "fact_text": "What disease is causing the symptoms in the picture -> Grape powder mildew", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4790", + "fact_text": "Are there any effective prevention and control methods for this type of pest -> To control the pest shown in the diagram, specific pesticides can be sprayed. For example, 20% Kangfuduo concentrated solvent 4000 times solution or 2.5% Baode emulsion 2000 times solution, or 50% aphid repellent wettable powder 2000 times solution or 10% imidacloprid wettable powder 2500 times solution can be used. Spraying these drugs can effectively prevent and control this pest.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2470", + "fact_text": "Are there any signs of other organisms on the stem or leaves -> A gray mold layer can be seen on the surface of the stem and leaves, which is a clear sign caused by fungi.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2793", + "fact_text": "Does this condition make the fruit easy to fall off -> Yes, due to the effects of these diseases, the fruit is more prone to shedding. In severe cases, the fruit may all shrink.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image2896", + "fact_text": "What is this black small lump -> These black small clumps are actually fungal nuclei, which are structures formed by pathogens under specific conditions. They can survive in soil and become active again under appropriate conditions, causing diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5269", + "fact_text": "What long-term impact will this situation have on the growth of the entire plant -> This type of pest affects the photosynthetic capacity of plants, and long-term damage may lead to slow plant growth, seriously affecting overall health and yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image5682", + "fact_text": "What methods can alleviate the impact of this disease -> For areas with severe seedling diseases, a unified method of seedling cultivation and supply can be adopted, strictly selecting nutrient soil, avoiding the use of soil with bacteria, and avoiding low temperature and high humidity conditions through rapid seedling cultivation and seedbed management. Specific pesticides can also be used for treatment.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4265", + "fact_text": "What type of influence is present in the image -> The crops in the image have disease problems.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image1622", + "fact_text": "What preventive measures should be taken to control this disease -> To control this disease, it is recommended to use appropriate planting density to avoid excessive watering and excessive nitrogen fertilizer application. In addition, specific pesticides such as 75% chlorothalonil plus 70% methylthiophanate and 40% polysulfide suspension can be sprayed every 7 to 10 days for continuous prevention and control for 2 to 3 times.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1195", + "fact_text": "What measures should be taken to prevent and control this situation -> Firstly, it is important to avoid handling winter melon under damp conditions to reduce the occurrence of wounds; Secondly, appropriate fungicides should be used for spraying treatment, and infected fruits should be promptly removed to reduce the spread of pathogens.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4173", + "fact_text": "When does this situation usually begin to manifest -> Usually, this type of disease begins to appear in October and can continue until March to April of the following year.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3951", + "fact_text": "What does the mushroom in the image look like -> The shiitake mushrooms in the image show some brown sunken lesions and white mold layers, indicating that they have been affected by a disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "vitis pseudococcus comstocki kuwana 1", + "fact_text": "What is the name of the insect in the picture -> Pseudofocus comstocki Kuwait", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4672", + "fact_text": "Are there any special habits that make them more likely to cause damage to crops -> This type of aphid can adapt to different climates and environments to a large extent. The overwintering aphids in rice growing areas start to move from March to April and reach their peak in early May. After wheat and barley mature, aphids begin to migrate to early rice fields, seriously affecting the growth of rice. In addition, after entering the rainy season, the number of aphids begins to decrease, and the majority of aphids will increase again from September to October, causing serious impacts on late rice.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4719", + "fact_text": "What does the larva look like -> At the final stage of larval development, the body length is between 15-23 millimeters, with a reddish brown or black brown head and a yellow white chest. There are five purple brown vertical lines on the back of the body, and the middle line is relatively thin.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1784", + "fact_text": "Can you see anything else in the image -> You can see some small black granular structures, usually distributed around the white hyphal area.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "vitis colomerus vitis 181", + "fact_text": "Why is the trunk of the insect in the picture colored -> Light yellow brown", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5436", + "fact_text": "Will pests in the image have an impact on the surrounding environment -> Yes, the venomous hairs of this pest are not only harmful to the human body, but may also spread to other plants through contact, expanding the scope of damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "grape mosaic virus disease 1", + "fact_text": "What disease is causing the symptoms on the leaves in the picture -> Grape Mosaic virus disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4333", + "fact_text": "What is the pathogen of this disease -> The pathogen of this disease is a species called SelenophomatiriciLiu, GuoetH G. Liu's fungus has its conidia buried in the stomatal cavity of the host. This fungus grows at a suitable temperature, with an optimal growth temperature of 15 ℃. Temperatures above 25 ℃ will inhibit its growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1816", + "fact_text": "Are there any particularly observed changes at the edges of these leaves -> Yes, there are no significant changes on the edges of the leaves except for the diseased spots, but when the environmental conditions are moist, the diseased spots on the edges may exhibit growth of brown mold or black mold.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5241", + "fact_text": "What may be the cause of these symptoms in the image -> These symptoms are usually the result of certain pests. Specifically, based on structured knowledge, it is possible that the larvae of a moth have nibbled and eaten crops. The newly hatched larvae first invade the tender head and leaves, and then eat the buds and flowers. As the larvae grow, they begin to eat the newly formed cotton bolls containing fiber and cotton seeds.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4430", + "fact_text": "What causes this disease -> This disease is caused by a fungus called pink terminal spore. The colony initially appears white and gradually turns pink. Its conidia stem is upright and unbranched. The conidia are light orange red, inverted pear shaped, and mature with a 1-septum.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2240", + "fact_text": "Is this situation related to the season -> Yes, according to the image information, sowing too early or in seasons with suitable temperature and frequent aphid activity is more prone to disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image896", + "fact_text": "What is the condition of the stem in the image -> The stem may have brown constrictions at the base or other parts, making it appear unhealthy on the surface.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5259", + "fact_text": "Does the cotton plant in the image look healthy -> Unfortunately, the cotton plants in the image do not appear very healthy as they have been affected by a pest infestation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4728", + "fact_text": "How did this problem arise -> This is caused by the behavior of a larva that eats the heart, leaves, stems, and marrow of corn. Due to being eaten by it, the heart leaves lose a large amount of nutrients, making it difficult to maintain normal growth, resulting in wilting and even whole plant death.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4863", + "fact_text": "What type of plant does the image look like -> The plant in the image is a perennial herbaceous plant that can reach a height of 50 to 100 centimeters. Its stem is upright and has branches at the top.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4755", + "fact_text": "What are the characteristics of insects in the image -> The insects in the image have an adult male body length of 8-9 millimeters and a female body length of 9-10 millimeters. The main color is black, but the front end of the head and part of the outer surface of the chest are dark yellow. They have a light yellow brown vertical line in the center of their chest and back panels. The anterior corner of the chest back plate is long and slightly curved, extending forward. Their small shield ends are far from the abdomen, and there are small yellow spots on each base angle. Black dots and fine hairs are distributed on the body wall. In specific environments, adults often become covered in soil and appear black brown. The abdominal end of the female insect is blunt and circular, while the abdominal end of the male insect has a protrusion that extends backwards.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image7", + "fact_text": "How to prevent and control this pest -> The key to preventing and controlling this type of pest is to focus on the prevention and control during the early spring hibernation stage. You can choose to use microcapsules or organophosphorus preparations, such as 25 % phoxim microcapsules in a 1000 - fold solution or 80 % dichlorvos emulsion in a 1500 - fold solution. Commonly use pyrethroid insecticides and formulations can also be used.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "apple powdery mildew 196", + "fact_text": "What medium does Apple powdery mildew spread through Answer: Air", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1284", + "fact_text": "How is leaf curling manifested -> Reverse curling is characterized by inward curling of leaf edges, usually caused by pathological reactions during the process of plant disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "corn spodoptera exigua huner 2", + "fact_text": "What insect is in the picture -> Spodoptera exigua Huner", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3270", + "fact_text": "When is the peak period for this type of disease -> This kind of disease often occurs in open fields in summer and autumn, especially in rainy years in autumn, where the occurrence of the disease will be more severe.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2235", + "fact_text": "Is there any special change in the leaves when the humidity is high -> In environments with high humidity, the damaged leaves will grow thick white mold like substances.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5425", + "fact_text": "What does the crop in the image look like -> The crop in the image is sesame, and there is a type of noctuidae insect on the leaves, which should have been disturbed by this pest.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4779", + "fact_text": "Where is this bug most common -> In the image, the species is widely distributed in many places in China, from north to south, including Jiangsu, Henan, Gansu, to Taiwan, Hainan, Guangdong, Guangxi, Yunnan, east to coastal, west to Sichuan, Xizang.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4461", + "fact_text": "So what methods are there to prevent or reduce this disease -> There are several methods to prevent and control this disease, including building water conservancy, selecting drought resistant varieties, and timely watering. In addition, during periods of high temperature and drought, as the natural dispersal and pollination ability of pollen decreases, auxiliary pollination can be adopted. In addition, urea, potassium dihydrogen phosphate aqueous solution, etc. can also be used for root spraying to cool down and increase humidity while providing necessary nutrients.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4647", + "fact_text": "What impact do insects have on crops in images -> In the image, you can see that the leaves of the crop wither prematurely, and there are straight or irregular hidden passages formed between the inner and outer bark tissues of the leaf sheaths or leaves. These are all symptoms of damage caused by this insect. In severe cases, it may result in crops not being able to tassel or empty grains.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4319", + "fact_text": "What may be the cause of this change in leaf morphology -> The change in leaf morphology may be caused by phosphorus deficiency. Phosphorus deficiency can cause the leaves to become thinner, stand upright without shedding, and may result in slight curling.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image5174", + "fact_text": "So, can you introduce some methods for preventing and treating this disease -> The methods for preventing and treating this disease include selecting resistant varieties, strengthening field management, and avoiding low temperature and high humidity conditions. Meanwhile, reasonable watering and fertilization are necessary, and timely drainage should be carried out in case of rain to prevent the occurrence of disease conditions. When necessary, professional pesticides can be sprayed, such as: 50% chlorhexidine wettable powder 1500 times liquid, 50% Succulent wettable powder 2000 times liquid, 65% Methomyl wettable powder 800 times liquid.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5321", + "fact_text": "What are the characteristics of visible insects in the image -> The insect bodies in the picture are light green, transparent, and approximately 17mm long. They have a spindle shaped body shape, with two thin ends and a thick center.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4938", + "fact_text": "Is there any obvious visual manifestation of this symptom -> Yes, the symptoms of nutrient deficiency mainly manifest as slow growth, short and weak stems, and the color of the leaves turning from green to light yellow. In severe cases, there may also be phenomena such as leaf fading and withering.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5259", + "fact_text": "What is the pest damage to cotton in the image -> The main pest that cotton is affected by is the truncated leaf mite, a very small, deep red insect that gathers on the leaves of cotton.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5523", + "fact_text": "What is the yellow dot like structure on the leaves caused by -> These yellow dot like structures may be caused by the activity of a small insect. These insects usually attach themselves to the leaves and suck up plant sap.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4645", + "fact_text": "What are the impacts and damages of pests on crops -> Insect infested larvae will feed on the juice of the growth points of rice, causing the base of the affected rice seedlings to swell, forming the so-called \"scallions\". Severely damaged rice seedlings cannot tassel and will only form \"green onion\" or become twisted and unable to bear fruit.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5081", + "fact_text": "Is there any abnormal performance of the plant leaves in the image -> Yes, the image shows that the leaves of the plant exhibit obvious symptoms of nutrient deficiency. The leaves show a green deficiency, but the veins remain green. The main impact is the yellowing of the old leaves at the base of the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image1604", + "fact_text": "What is the pattern of these symptoms occurring -> Symptoms may be caused by the spread of sap, insects, or seeds, especially under favorable weather conditions for pest activity.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3820", + "fact_text": "What is the condition on the back of the blade -> The back of the leaf is where this disease first appears, and you will see a white frost like mold layer first forming there, especially in high humidity environments.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4691", + "fact_text": "What type of crop does the crop in this image appear to be -> The crop in the image is barley.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4836", + "fact_text": "When is this situation usually most severe -> Usually at night, pests are more active and come out to search for food, which can lead to more severe damage to plant leaves and tender buds.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4181", + "fact_text": "What is the spread of spots like -> When the spots extend along the stem and wrap around the entire circumference, it can be seen that the stems and leaves above this area begin to wilt, and the color gradually changes to dark brown to black brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image3093", + "fact_text": "Are there any other factors that can affect the formation of flower buds, except for climatic conditions -> Yes, if excessive nitrogen fertilizer is applied to cauliflower during nutritional growth, it can also lead to elongation of stems and leaves, which results in most of the nutrients being used for stem and leaf growth, while flower bulbs cannot form due to insufficient nutrition.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "corn leaf beetle 435", + "fact_text": "How many segments are the antennae of insects in the picture Answer: Section 11", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "potato hollow heart 2", + "fact_text": "What factors are causing the abnormal phenomenon on the potatoes in the picture -> Potato tube hollow disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1855", + "fact_text": "Is this situation developing rapidly -> Yes, the development is quite rapid, especially in high temperature and humidity environments.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image2392", + "fact_text": "What changes will occur in these white structures in the later stage -> In the later stage, these white mycelium clusters will further develop, forming small, mouse fecal like solid structures called fungal nuclei.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image4830", + "fact_text": "What specific effects do the insects in the image have on plants -> This type of insect mainly damages the roots of plants, causing root damage such as biting gaps or holes, which in turn causes root rot or plant death.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3678", + "fact_text": "Is there any physical method besides medication that can control this disease -> Indeed, planting fennel in high beds or ridges can reduce the occurrence of diseases. In addition, timely removal of accumulated water in the field is also an effective means of controlling the spread of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1099", + "fact_text": "Will the changes in the blades expand upwards -> Yes, this situation will gradually expand upwards, with some leaves on the branches turning yellow and dying, which may ultimately affect the entire plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4768", + "fact_text": "Do the organisms in the image have any special visual markers -> Yes, the organisms in the image have some special visual markings. For example, each of its wings has 5 longitudinal ribs raised, and there are dense and uniformly sized notches between the longitudinal ribs, which are covered with gray white fuzz. For example, there are triangular white spots on the sides of each of the 1-5 segments of the abdomen. These characteristics make this organism significantly different from other derived species of the family Lamiaceae.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4048", + "fact_text": "How to effectively prevent this situation from happening -> Effective preventive measures include selecting varieties that are resistant to low temperatures, controlling night temperatures appropriately, avoiding early and premature planting, while controlling nutrient supply, avoiding excessive application of nitrogen fertilizer, and strengthening water and fertilizer management.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "alfalfa seed chalcid 1", + "fact_text": "What is the black creature on the flower in the picture -> Alfalfa seed chalcid", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5351", + "fact_text": "Are there any effective prevention and control methods -> Firstly, strict quarantine is required to prevent the spread of pests. In areas heavily affected by the spotted miner, consider vegetable layout and crop rotation that is not favored by this insect. Secondly, fly killing paper can be used to lure and kill adult insects, and scientific medication can be used. When there are larvae on the affected crops, spray insecticides in a timely manner. Finally, biological control methods such as parasitic wasps can also be used.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image12", + "fact_text": "What effective measures can be taken to control this insect -> Three prevention and control measures can be taken. Firstly, agricultural prevention and control: such as clearing overwintering sites, uprooting other wild host plants, clearing nightshade weeds at the edges of fields, inspecting overwintering sites, and hunting overwintering adults. Secondly, biological control: release using Beauveria bassiana or artificially raised ladybirds, such as the double ridged wasp. Thirdly, pesticide prevention and control: Spray corresponding pesticides at the appropriate time, such as using insecticides.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4635", + "fact_text": "Is there any way to improve this situation -> This situation can be improved by supplementing with appropriate amounts of essential nutrients such as nitrogen, potassium, zinc, etc. Meanwhile, enhancing field management such as timely intercropping and appropriate irrigation can also help restore plant growth and promote root health.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2058", + "fact_text": "What is the reason why the top of the crop in the image appears incomplete -> In the image, the top of the crop is not sturdy, showing a bald or pointed state, mainly due to insufficient nutrient supply from the small flowers or fertilized embryos at the top.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image235", + "fact_text": "Are there any signs of prevention and control measures shown in the image -> There are no obvious signs of external prevention and control measures in the image, mainly showing the natural development status of the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4919", + "fact_text": "What does the crop in the image look like -> The crops in the image are not very healthy and exhibit symptoms of a certain disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image5246", + "fact_text": "So, what prevention and control measures can we take -> For this type of pest, we can use black light lamps or high-pressure mercury lamps to lure and kill adults. We also need to do a good job in monitoring and strengthening the prevention and control of cotton field larvae. Specifically, when there are 100 larvae per 100 cotton plants from the late hatching stage to the 3rd instar stage, we can spray organic phosphorus pesticides such as dichlorvos and malathion or other related pesticides for control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3260", + "fact_text": "Is there any significant climate factor visible in the image -> The image may show a post rain environment, which can exacerbate the progression of the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image3344", + "fact_text": "What impact do these nodular structures have on plants -> These structures may hinder the normal nutrient absorption of plants and exacerbate the phenomenon of aboveground withering.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4690", + "fact_text": "What are the preventive measures for this pest -> There are multiple methods to prevent this pest. Generally, this includes selecting varieties with low infection rates for planting, using varieties with higher infection rates for trapping, limiting the movement of grass seedlings in the Poaceae family to prevent the spread of pests, and spraying pesticides if necessary.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image195", + "fact_text": "What are the environmental conditions under which these symptoms occur -> The occurrence of this disease is related to the rainy summer or autumn environment with high dew, because the germination of pathogens requires a water film, and the suitable temperature is 16-22 ℃, which is conducive to the development of the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2422", + "fact_text": "What growth strategies are asparagus attempting to adopt under the conditions of this disease -> Under high nitrogen fertilizer use and poor drainage conditions, plants may experience overgrowth and overdensity, which in turn increases the occurrence of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5466", + "fact_text": "Are there any preventive measures for this kind of damage -> There are several prevention and control measures that can be taken. This includes capturing adults from June to August, stabbing larvae inside the bark, burning dead trees, ensuring that newly planted saplings receive adequate care, especially timely killing of larvae inside the trees. In addition, chemical control measures can be taken by using specific chemicals to treat trees, such as using insecticides.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "citrus bactrocera tsuneonis 13", + "fact_text": "Are there any insects in the picture Answer: No", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4452", + "fact_text": "Besides yellowing at the leaf tips, is there any abnormality in the corn ears in the image -> If the leaves show symptoms of potassium deficiency, the ear may also exhibit characteristics of miniaturization and poor top development, as potassium deficiency affects the nutritional status of the entire plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4873", + "fact_text": "Where does this plant usually grow -> This type of plant usually grows in farmland, ditches, or roadside areas.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image17", + "fact_text": "How does this disease spread -> The pathogen overwinters in the diseased parts of sugarcane seeds and plants through hyphae, conidia, and chlamydospores, which are the main primary sources of infection for this disease. The conidia and thick walled spores on the diseased leaves are important bacterial sources of repeated infection in the same year. Spores spread through wind, rain, fog, dew, insects, and flowing water, and pathogens mainly invade through wounds.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2266", + "fact_text": "Is this disease severe on cabbage -> Yes, it can quickly spread to the entire leaf or even the entire plant, causing serious withering and death.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image430", + "fact_text": "What is the density of tomato seedlings in the image -> The tomato seedlings in the image are planted relatively densely, which may increase the risk of disease transmission.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4693", + "fact_text": "What is the impact of this pest on wheat -> The pests in the image mainly cause damage to the heart leaves or young ears of wheat. The parts affected by this pest will wither, and if they are currently in the tillering stage of wheat, this damage will be more severe.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image336", + "fact_text": "How should the crops in the picture be managed to prevent such problems -> In addition to using low temperature resistant varieties, it is also necessary to strengthen seedling management, control night temperature, and timely and appropriate watering.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "management instructions", + "entity": "image4955", + "fact_text": "How can we prevent the occurrence and spread of this disease -> Firstly, waterlogging is a good method. In areas with conditions, irrigating a soil layer of 10cm or deeper on the surface for several months can effectively prevent the infection, reproduction, and growth of root knot nematodes. Secondly, in fields with severe root knot nematode outbreaks, implementing water drought rotation has a good control effect. In areas lacking water sources, rotating crops such as grasses and cotton with hemp can also reduce damage. At the same time, it is necessary to deeply cultivate and improve the soil, break through ridges and replace ditches, frequently cultivate and weed, timely irrigate to resist drought, and apply fertilizer reasonably. If necessary, using 10% Li Man Ku granules can also achieve good results.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4488", + "fact_text": "Under what conditions will this disease be more likely to occur -> This disease is more prone to occur under relatively humid conditions, especially during the rainy season from July to August each year. As sorghum approaches harvest, the spread of the disease will accelerate.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5173", + "fact_text": "What impact will this change in the ball flower have on the entire plant -> This disease mainly affects the bulbs, and in severe cases, it can cause them to all wither and die, negatively affecting the growth and reproductive potential of the entire plant, reducing crop yield and quality.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4652", + "fact_text": "Where did it cause its impact -> The insect in the image not only affects rice, but also causes damage to various crops such as sorghum, sugarcane, tea, and citrus. I think we can see it attached to the crop from the image.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5734", + "fact_text": "What is the overall health status of plants -> In the image, due to the loss of the plant's original transmission and support functions, the entire plant gradually collapses and may eventually wither and die.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4598", + "fact_text": "What nutrient deficiency is causing the withered and charred leaves observed in the image -> The withered and charred leaves may be caused by potassium deficiency. When potassium is lacking, the edges and tips of the leaves will shrink or even become charred.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image309", + "fact_text": "What impact will this abnormal root phenomenon have on plants -> The formation of lumps at the roots can affect the normal water and nutrient absorption of plants, leading to wilting, twisted leaves, and inhibited growth of aboveground plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4800", + "fact_text": "Are there any effective prevention and control methods -> Effective prevention and control methods include ensuring that stored grains such as corn are dry and intact, and controlling the moisture content between 12% and 13%. In addition, using grain insect proof packaging bags is also an effective measure. For dried mushrooms and ears, it is best to store them sealed at 3 to 5 ℃.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4104", + "fact_text": "What methods can prevent this situation -> Reasonable application of phosphorus fertilizer is crucial. If soil tests show high phosphorus, the amount of phosphorus fertilizer used should be reduced. Meanwhile, increasing the application of organic matter, such as chicken manure or rice husk manure, can help improve soil structure and enhance the plant's ability to absorb trace elements.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "citrus toxoptera citricidus 51", + "fact_text": "Can the damage caused by this insect be reduced by utilizing natural enemies Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "corn fall armyworm 330", + "fact_text": "Which part of the crop in the picture has been damaged Answer: Stem", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "apple Mosaic 21", + "fact_text": "Will this type of spot cause distortion and wrinkling of the leaves Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image3002", + "fact_text": "How can stem diseases affect plants -> The disease spots on the stem can cause the stem vines above the diseased area to wither and die, which may seriously affect plant growth and nutrient delivery.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4649", + "fact_text": "What impact did this pest have on the crops in the image -> This type of pest can cause feeding and other behaviors on rice, which will affect the growth and development of crops, leading to a decrease in yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1689", + "fact_text": "How to protect these plants from harm in winter -> In winter, soil temperature can be increased by covering with soil or spreading materials such as straw and leaves between plants. At the same time, organic fertilizer can also be applied to help increase soil temperature and enhance plant cold resistance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image3805", + "fact_text": "What is special about the cultivation method of crops in the image -> These crops are likely to be cultivated through hydroponics or substrate cultivation, which is more precise in controlling the environment and nutrient supply.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4741", + "fact_text": "What are effective prevention and control methods -> Prevention and control methods need to target the biological characteristics and habits of pests. For detailed prevention and control methods, please refer to the prevention and control measures for this pest.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2041", + "fact_text": "How was this situation caused -> This is mainly due to the lack of essential nitrogen elements in crops, especially after mid-term drought or heavy rain, which is more likely to occur.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4692", + "fact_text": "Are there any effective prevention and control methods available now to deal with this pest -> The prevention and control methods include selecting insect resistant or early maturing varieties, reasonable crop cultivation management, strengthening the prediction and prediction of wheat stem flies, and timely drug control. When it is found that the adult wheat straw fly has reached the control target, appropriate medication should be sprayed immediately. If the wheat straw fly has laid a large number of eggs, it is necessary to spray corresponding pesticides in a timely manner to control the eggs before hatching.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3110", + "fact_text": "Is the pod severely affected in the image -> Yes, some pods have cell death and small dark green spots visible on the surface.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "citrus parlatoria zizyphus lucus 1", + "fact_text": "Which organ of the crop does the abnormal phenomenon in the picture occur in Answer: Fruit", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4675", + "fact_text": "How to prevent and eliminate the impact of this organism on crops -> The impact of this organism on crops can be prevented and eliminated through agricultural prevention and chemical control. The specific methods include timely removal of weeds at the edges of fields and ditches, timely plowing of millet seedlings, and elimination of overwintering insect sources. Specific pesticides can be sprayed during the peak period of young nymphs.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5297", + "fact_text": "When do these insects primarily move -> This type of insect is mainly active at night, lurking during the day and emerging at night, with weak phototaxis.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3823", + "fact_text": "Do you see any hard objects on the petals in the picture -> Yes, in the image, it can be seen that some petals have formed brownish small granular substances in the affected area, which are called fungal nuclei.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3937", + "fact_text": "How can this situation be prevented -> To prevent this situation, an important measure is to maintain good ventilation conditions, especially in the early stages of sub entity formation. It is necessary to timely reduce the concentration of carbon dioxide on the bed surface and adjust the relative humidity of the air, such as removing covers to increase oxygen supply, and installing ventilation facilities to ensure air circulation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4391", + "fact_text": "What factors are usually associated with abnormal leaf color -> This color abnormality is usually related to nutritional deficiencies, such as a lack of key nutrients such as nitrogen, phosphorus, or potassium.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2153", + "fact_text": "Can symptoms be seen not only on the leaves, but also on the fruit body -> Yes, the fruit skin of the Chinese and Western gourds in the picture also shows similar symptoms, showing uneven yellow and green colors, but the surface is still smooth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4413", + "fact_text": "How does this disease spread -> This disease is mainly spread through the overwintering of hyphae or fungal nuclei in the soil, and this pathogen can survive in the soil for 2 to 3 years. It can spread through water flow and agricultural tools, and is most suitable for growth in an environment of 24 ℃. In addition, adverse conditions such as excessively dense seeding and high temperatures can easily lead to this disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image968", + "fact_text": "Are there any effective prevention and control measures that can be taken -> Effective prevention and control measures include seed treatment, improved cultivation measures such as timely ventilation and reasonable irrigation, and the use of specific pesticides such as methylthiophanate to control the spread and development of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4418", + "fact_text": "Looking at the image, has the structure of this crop changed -> Yes, the structure of the crops has changed. Manifested as the diseased plant being short, only half or shorter than the healthy plant height, with an earlier heading period, and the seeds of the diseased plant being filled with black powder and wrapped in a layer of gray film.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image686", + "fact_text": "If the condition has progressed to this extent, how should it be handled -> Once the disease progresses to the level shown in the image, soil treatments such as 15% triazolone powder or 50% methylglyphosate can be used to control the further spread of the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image2387", + "fact_text": "Why does this type of carrot look lighter -> The radish in the image may have reduced the weight of fleshy roots due to certain physiological diseases, which is caused by changes in the composition of the radish body.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image670", + "fact_text": "What should be noted when controlling such issues -> It is important to maintain good ventilation and moderate plant density in the field, and also pay attention to reasonable fertilization to avoid excessive dense planting and single nitrogen application.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1933", + "fact_text": "What is the special color expression of the rotten part of the flower ball -> The decaying tissue of flower buds is mainly black, which is a common manifestation after infection with diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image341", + "fact_text": "Is there any good preventive method to avoid this situation -> To prevent such situations, it is recommended to use tomato varieties that are resistant to low temperatures and weak light, while maintaining a night temperature of 12 to 16 degrees Celsius in seedling management, ensuring appropriate water and nutrient supply, and avoiding excessive application of nitrogen and phosphorus fertilizers.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "mango deporaus marginatus pascoe 16", + "fact_text": "Do the insects in the picture have small yellow spots on their bodies Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4827", + "fact_text": "What season are these insects usually most active in -> This type of insect becomes active from late spring to early summer, especially when adults begin to emerge and mate in July.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1773", + "fact_text": "What are the recommended prevention and control methods for this disease -> An effective prevention and control method is to spray pesticides such as 72% agricultural streptomycin sulfate soluble powder or neophytomycin in the early stages of the disease. Meanwhile, planting disease resistant varieties and engaging in appropriate crop rotation are also recommended prevention and control measures.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2451", + "fact_text": "So, do environmental factors have an impact on this situation -> When encountering humid environments, the heart lobe can also be infected by miscellaneous bacteria, further exacerbating the condition of decay.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image1420", + "fact_text": "Is there any measure to prevent such situations -> Several measures can be taken, such as using aphid repellent silver gray film strips, timely removing weeds, selecting well ventilated plots, and timely sowing and watering.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5458", + "fact_text": "How is this type of pest usually treated effectively -> An effective approach is to stack bricks or tiles at the base of the tree trunk to attract two instar larvae to hunt and kill them while hiding during the day, or to apply drugs with high concentrations of contact agents to the trunk to poison the larvae.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "tomato leaf miner 17", + "fact_text": "Which part of the leaf is caused by insect damage to the abnormal phenomenon in the picture Answer: Leaf flesh", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "rice leaf smut 10", + "fact_text": "What signs of disease are displayed on the leaves in the picture -> Rice leaf smut disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4834", + "fact_text": "What are the habits of the insects shown in the picture -> This type of insect usually inhabits under bricks, grasslands, vegetable gardens, orchards, or farmland. Starting in late September, eggs will be laid about 1 to 1.5 centimeters below the soil and exhibit phototaxis. Interestingly, they sometimes engage in self destructive behavior, with their vocals slightly higher in pitch compared to other similar species.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5403", + "fact_text": "What does the stem of the crop look like in this image -> In the image, the stem appears hollow and shows signs of aging, possibly due to damage caused by insect infestation inside.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato verticulium wilt 69", + "fact_text": "Is Tomato verticillium wilt contagious Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4632", + "fact_text": "What is the height of the plants in the picture? Is this related to pest infestation -> Affected plants may exhibit symptoms of elongation due to excessive application of nitrogen fertilizer or environmental conditions, making them more susceptible to pest attacks.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1750", + "fact_text": "What is the appearance of the central lobe in the image -> The central lobe is relatively small and has some semi transparent water immersion.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image407", + "fact_text": "Is there any sign of diffusion in this situation -> Yes, infections from the root or stem base can spread to nearby plants through soil cracks on the ground.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2644", + "fact_text": "What preventive measures should be taken in this situation -> It is recommended to use disease resistant varieties, cultivate in high beds or ridges, timely drainage to prevent flooding, and implement appropriate rotation to avoid continuous cropping.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1156", + "fact_text": "Will this disease spread from one fruit to another -> Diseases are mainly transmitted through infected seeds and wind and rain. If the environmental conditions are suitable, the disease may spread from one fruit to surrounding fruits.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "corn fall armyworm 126", + "fact_text": "Does the insect's head in the picture have a white inverted \"Y\" mark Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "rice koji disease 2", + "fact_text": "What factors are causing this phenomenon in the picture -> Rice smut disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2648", + "fact_text": "How should this situation be handled -> To deal with this situation, agricultural measures can be taken, such as selecting disease-free soil for seedling cultivation and reasonable rotation, thoroughly disposing of diseased residues in the field, centralized burning or deep burial, as well as appropriate chemical control and strengthening field management.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image411", + "fact_text": "What color are the spots on the crop leaves in the image -> The spots on the crop leaves in the image initially appear as small necrotic spots, gradually expanding into grayish yellow to yellowish brown, with possible purple brown wheel patterns or a yellow halo around them.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4202", + "fact_text": "In which season is this situation more common -> According to the environment and description shown in the image, this situation is more common in spring, especially on days with lower temperatures and higher humidity. Low temperatures and continuous rainy weather can intensify bacterial activity, especially in the early stages of seedling growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5520", + "fact_text": "What type of influence has the plants in the image been affected by -> The plants in the image have been affected by a pest.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4381", + "fact_text": "What are the specific symptoms of crop diseases -> The image shows that when the frost damage is severe, the main stem, large tillers, young panicles, and heart leaves of the crop freeze to death, while the rest can still grow. Crops with severe frost damage have leaves and tips that are as hard and brittle as water, and then wither or turn blue-green. The stems and young spikes shrink and die.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4607", + "fact_text": "What are the characteristics of the pathogen of the disease in the image -> The pathogen of this disease is Fusarium solani, also known as Fusarium solani specialized type of sweet potato, which is a fungus. The mycelium of this bacterium is hairy or densely fluffy to flocculent, with spindle shaped spores and 3-8 cell widths. In addition, there is also Nectriasanguea, also known as the blood red fungus, which belongs to the phylum Ascomycota. In addition, there are reports that Fusarium oxysporum is also the pathogen of this disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "wheat septoria 1", + "fact_text": "Which part of wheat is mainly affected by Wheat Leaf Blotch -> Leaves and leaf sheaths", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5079", + "fact_text": "How to solve this problem -> Applying phosphorus rich fertilizers is an effective solution to the problem of phosphorus deficiency. For example, applying encapsulated calcium magnesium phosphate fertilizer or applying superphosphate can increase the phosphorus content in the soil. Foliar spraying can also be carried out with a solution of Jifengbao liquid fertilizer No.1 or potassium dihydrogen phosphate.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4704", + "fact_text": "Are there any effective prevention and control methods -> There are several prevention and control methods: (1) The pseudolethality of the insect can be utilized, and when it is not active enough to inhabit the leaves in the morning and evening, it can be shaken and dropped into plastic bags for centralized eradication. (2) Soak the sweet potato seedlings in a 500 fold solution of 50% cypermethrin emulsion before planting, then air dry them, and then plant them to prevent damage during the seedling stage. (3) If necessary, spray medication such as 50% phoxim emulsion 1500 times or 30% oxytetracycline emulsion 3000 times, 5% cypermethrin casein emulsion 2000 times, 20% green horse emulsion 1500 times, and 0.6% matrine nicotine 1000 times. Medication should be stopped 5 days before harvesting.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5495", + "fact_text": "What color is the larva -> The larvae in the image are yellow in color, with a body length of approximately 35mm and a sky blue stripe along the back.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4731", + "fact_text": "How should I deal with this pest -> After identifying such pests, relevant literature such as the prevention and control methods of Spodoptera litura can be consulted to control and prevent them.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5499", + "fact_text": "How to handle this situation better -> Appropriate treatment methods include removing overwintering cocoons from tea bushes during winter, and using biological agents or chemical insecticides for control during peak larval hatching, such as Bacillus thuringiensis spores or spraying with specific pesticides.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5518", + "fact_text": "What impact will this pest have on plant growth -> The growth of affected plants will be restricted, mainly manifested as short and curved trunks, accompanied by the phenomenon of side branches clustering.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tea red leaf spot 500", + "fact_text": "Is tea red leaf spot contagious Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5222", + "fact_text": "What are the environmental conditions under which this disease occurs in tea trees -> This kind of disease often occurs in humid environments, especially in May when it thrives. Tea trees are prone to aging or low-lying tea gardens are particularly susceptible to disease. Poor ventilation and light transmission in tea gardens or excessive application of nitrogen fertilizer can also worsen the condition.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image1642", + "fact_text": "What are the main impacts on the crops in the image -> The main impact is the erosion and nutrient uptake of root knot nematode larvae, leading to necrosis of root tissue, and in severe cases, may cause overall plant decline and death.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3979", + "fact_text": "Are there any other abnormal phenomena in the image -> Under humid air conditions, gray white bacterial liquid may form on the fruiting body, which is a significant abnormal phenomenon.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5269", + "fact_text": "How should we prevent and treat this pest -> For this type of pest in the image, we can combine crop management and promptly remove the insect infested sac for destruction. During the peak stage of young larvae, pesticides such as 50% malathion emulsion or 90% crystal trichlorfon 1000 fold solution can be sprayed.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1615", + "fact_text": "How does this problem spread through the environment -> It spreads through wind and rain, especially when conditions are suitable, and the conidia are released from within the fungus and dispersed through wind and rain.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5382", + "fact_text": "HTTP Request Error: Expecting value: line 1 column 1 (char 0) -> This pest gives birth once a year, and the adults overwinter in the soil crevices of the rapeseed field. When rapeseed enters the bolting stage, female adults drill a small hole on the rapeseed stem with a mouthpiece and lay eggs in the hole. The newly hatched larvae feed upwards and downwards in the stem, sometimes with a few or 10-20 heads together, feeding into tunnels inside the stem. When disturbed, adults have a false death instinct and will land and flee. After harvesting rapeseed, adults will continue to harm it for a period of time from September to October, and then overwinter.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "rice flax spot 1", + "fact_text": "What disease is causing the half point on the leaf in the picture Answer: Rice Flax spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image941", + "fact_text": "What are the good prevention and control suggestions for this situation -> To prevent and control this situation, early diagnosis and use of antiviral varieties, timely spraying of recommended pesticides such as potassium permanganate solution, and management of field hygiene can be adopted to reduce the chances of virus transmission.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4647", + "fact_text": "What are the shape and structural characteristics of this insect -> In the image, the shape of this insect is a long and flat cylindrical body of the last instar larvae, with a light yellow white color and a thick black mouth hook. The pupa is about 4 millimeters long, initially yellow brown in color, with two small black protrusions at the tail end.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5664", + "fact_text": "What is the lifecycle of this insect -> This type of insect starts from a single celled egg produced by the female, which forms a first instar larva a few hours later. After peeling and hatching, it produces a second instar larva, which then moves away from the egg mass in the soil to search for new root tips to invade. During a season of growth, they can undergo multiple generations of proliferation, ultimately forming mature root nodules and laying eggs to hatch and develop, completing their life cycle.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3910", + "fact_text": "Do these cracks have any special shape or pattern -> Yes, the cracks mainly appear as fish scale radiating cracks, while the cracks on the stipe extend longitudinally and horizontally.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image237", + "fact_text": "If I see that the edges of the leaves also change color, does it mean that the overall health of the leaves is seriously threatened -> It may not necessarily pose a serious threat to overall health, but after the fusion of disease spots to form large patches, the function of leaves may be damaged, affecting plant photosynthesis and nutrient delivery.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "citrus phyllocoptes oleiverus ashmead 20", + "fact_text": "Are there any small insects in this picture Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4568", + "fact_text": "So, how did this disease spread -> This disease mainly overwinter through the fungal nuclei on diseased potatoes or left in the soil. The infected seed potatoes are the source of infection at the beginning of the following year and are also the main route of long-distance transmission. Its occurrence is related to spring cold and humid conditions, and the disease is more severe in areas where the soil temperature is lower early or after sowing.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4766", + "fact_text": "Does this pest have a certain degree of transmissibility -> Yes, this pest indeed has a certain degree of transmissibility. In addition to directly causing damage to crops, it is also the main vector insect of wheat virus disease, so timely prevention and control are needed.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3987", + "fact_text": "So, how does this bacterium spread -> This type of bacteria can spread through various pathways, including irrigation water, fertilizers, agricultural tools, etc. Sometimes wind and rain can also promote the spread of bacteria. Usually, this type of bacteria invades through plant wounds.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2675", + "fact_text": "Is there any measure to prevent this situation from happening -> By paying attention to field hygiene and timely spraying appropriate pesticides such as 40% polysulfide suspension 500 times solution, as well as avoiding biased application of nitrogen fertilizer, the plant's resistance can be strengthened to prevent this situation from occurring.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5349", + "fact_text": "So how to prevent the harm of this organism -> There are several methods to try. Firstly, spring sowing sites should be fertilized in the autumn of the previous year, which can reduce damage. Secondly, applying quick acting fertilizers during the seedling stage can accelerate growth, shorten the time of damage, and also reduce harm. Of course, prevention and control can also be carried out through chemical methods, such as spraying imidacloprid wettable powder, fly larvae cleaning powder, or SF Express emulsion.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5080", + "fact_text": "What should I do to solve this problem -> The problem of potassium deficiency can be solved by applying potassium rich fertilizers, such as using silicate bacterial bio potassium fertilizer or potassium sulfate. Meanwhile, foliar spraying of potassium dihydrogen phosphate is also an effective solution.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image213", + "fact_text": "What symptoms do the young pods in the picture show -> The young pods in the picture are also affected by red spot disease, which may cause symptoms of darkening and drying, consistent with the symptoms of the leaves and stems.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4926", + "fact_text": "So how should we prevent and control this disease from spreading -> The prevention and control measures are similar to the methods used for cotton ring rot. Specific measures should be implemented comprehensively, adopting early detection and treatment to effectively control diseases. For example, appropriate fertilization, especially paying attention to providing sufficient phosphorus and potassium fertilizers to avoid excessive nitrogen fertilizer application; Just choose resistant varieties and so on.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5411", + "fact_text": "What are the obvious appearance features of insects -> The front wings of adult insects are grayish brown in color, with special horseshoe shaped silver spots and spindle shaped silver spots, as well as silver longitudinal lines and serrated sub terminal lines, which are unique in the insect kingdom.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2550", + "fact_text": "Is there a recommended method to alleviate this situation -> Heat resistant varieties such as Xiatang 1 or Tianhe summer towel gourd can be selected. At the beginning of the disease, the corresponding virus control agent spray can be used, such as virus A wettable powder 500 times liquid.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image848", + "fact_text": "Does the leaves of Chinese and Western gourds look healthy in this picture -> Not completely healthy, with some circular or irregular light colored spots appearing.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2562", + "fact_text": "Is there anything special about the edge of the lesion -> The edge of the lesion leaves a yellow white halo, which forms a sharp contrast with the normal leaf area.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "rice leaf smut 39", + "fact_text": "What factors have affected the leaves in the picture -> Rice leaf smut disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2830", + "fact_text": "Why do the tomato plants in the image appear to be overgrown but with fewer results -> This situation is usually due to the high content of ammonium nitrogen in the soil, causing plants to grow excessively, with strong stems and few fruits.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4733", + "fact_text": "What kind of damage did the pests in the image cause to the plants -> The larvae of this pest will cross cut and feed on the leaves without leaving any middle ribs. In the early stages of their larvae, such as the 1st and 2nd instars, they will bear buds, but after the 3rd instar when they mature, they will not bear buds or only partially bear buds.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image702", + "fact_text": "Are there any preventive measures for this situation -> Rotation, use of disease resistant varieties, management of temperature and humidity, and timely application of appropriate pesticides can be adopted, such as using 50% carbendazim wettable powder for prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image3717", + "fact_text": "Is there an effective way to manage this situation -> Effective management methods include applying sufficient base fertilizer and increasing phosphorus and potassium fertilizer, avoiding biased application of nitrogen fertilizer, removing diseased leaves in time in combination with intertillage management, and spray with recommended chemicals at the initial stage of disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2832", + "fact_text": "What are the causes of these symptoms -> This is because excessive application of ammonium nitrogen fertilizer, combined with factors such as low temperature or soil disinfection, causes ammonium to accumulate in the soil, leading to excess ammonium nitrogen.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1457", + "fact_text": "How did this situation start -> The condition is caused by the fungal nuclei germinating under suitable high humidity and temperature conditions to form ascomycete discs, which produce spores for initial infection.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4715", + "fact_text": "What is the name of this pest -> Sorry, due to my inability to view actual images, I am unable to accurately identify the types of pests. But according to the information I know, this pest may be the white vein armyworm.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image5067", + "fact_text": "How do the crops in the picture prevent and control this disease -> There are various methods to prevent and control this disease. Firstly, disease resistant varieties can be selected, such as New Oil 8 Mall, No. 9, and other varieties. Secondly, the host's disease resistance can be enhanced by applying appropriate amounts of phosphorus and potassium fertilizers through formula fertilization techniques. Finally, in the early stages of the disease, Wuyi fungicide (B0-10) aqueous solution or polysulfide suspension, Fuxing emulsion, triazolone wettable powder, or green copper emulsion can be sprayed. However, it should be noted that some rapeseed varieties are more sensitive to copper agents, and the dosage should be strictly controlled to prevent drug damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image3723", + "fact_text": "How does the disease in the image affect the entire plant -> In severe cases, this disease can lead to the death of plants in patches, and the plants in the image may exhibit overall lethargy and growth inhibition. This situation is mainly due to the main nutrient transport channels being infected by diseases, which block the normal flow of nutrients.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5252", + "fact_text": "What are the plant species in the image -> The plant in the image is peanuts.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5391", + "fact_text": "Can you provide me with some methods to prevent and control this pest -> There are several methods that can be used to control this pest: (1) Winter plowing and stubble removal can be used to eliminate some overwintering adults. (2) During the period of adult and nymph infestation after flowering and podding, broad-spectrum insecticides can be used and sprayed at conventional concentrations to achieve toxic effects.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5311", + "fact_text": "What are the other characteristics of the living habits of this pest -> This type of pest has a strong attraction to black light and ultraviolet light, and with appropriate light sources, their activity may be more easily observed.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2126", + "fact_text": "How to prevent this situation from happening -> To prevent this situation, excessive use of such pesticides, especially those sensitive to cucumbers, should be avoided or reduced as much as possible.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1096", + "fact_text": "At which growth stage do these situations usually begin to manifest -> These symptoms usually begin to manifest during the seedling or adult stages and may further expand under suitable environmental conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "citrus toxoptera citricidus 176", + "fact_text": "Do you know what this insect is called -> Toxoptera citricidus", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4517", + "fact_text": "How to prevent this situation from happening again -> It is recommended to use organic fertilizer as the main fertilization method, and arrange top dressing reasonably according to the growth stage of the plant to avoid nutrient imbalance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5346", + "fact_text": "How can we effectively prevent the spread of this pest -> Several effective prevention methods include destroying insect eggs, killing adults and larvae, removing fallen leaves and weeds after harvest, and deep cultivation in autumn to reduce overwintering insect population density. If necessary, designated pesticides can also be used for prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4789", + "fact_text": "How does this pest spread -> Greenhouse whiteflies mainly overwinter and continue to harm through various adult states in the greenhouse. Adults can mate and lay eggs 1-3 days after emergence. Their eggs are inserted into leaf tissue through the stomata through the egg stalk, making it difficult to shed. Under greenhouse production conditions, one generation can be completed in approximately one month. Human factors play an important role in the transmission of whiteflies, such as through greenhouse ventilation or transplanting seedlings to open fields, which may bring whiteflies.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5399", + "fact_text": "What methods can we use to control this pest -> Firstly, insect resistant varieties can be selected. When it is discovered that the larvae are in the early stages of hatching, special medication can be sprayed to prevent the larvae from molting or deforming normally and dying. When the number of insects in a hundred plants exceeds 100, specific pesticides should be immediately sprayed to eliminate them. In addition, deep soil plowing can also effectively kill pupae.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "citrus toxoptera citricidus 176", + "fact_text": "What color is the body color of the insect in the picture Answer: Yellow white", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image4603", + "fact_text": "Can you provide a detailed description of the characteristics of this disease and insect -> This disease and insect is called Ceratocystis fimbriata, which is a fungus in the subphylum Ascomycota. It asexually produces conidia and chlamydospores, which can be generated on hyphae. The mycelium is initially colorless but turns dark brown when it matures, with a width of 3-5 ΞΌ m. It can parasitize within or between host cells.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5448", + "fact_text": "What parts of plants are pests commonly distributed in -> Pests are mainly distributed in the upper part of plants, with 4 to 7 leaves from the tip down being their main target area.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4104", + "fact_text": "What elements in the soil may be imbalanced to cause this situation -> For example, if the phosphorus content in the soil is too high, it may antagonize other essential trace elements such as zinc and iron, thereby affecting the absorption of these trace elements by plants and causing abnormal symptoms in the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato verticulium wilt 105", + "fact_text": "Does the onset of Tomato verticillium wilt occur in the early or middle to late stages of tomato growth -> Mid to late stage", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image2015", + "fact_text": "What is the pathogen of this disease -> This disease is caused by a fungus called the phylum Pseudomonas aeruginosa, the large spotted convex navel worm fungus.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5373", + "fact_text": "Is there any special way to prevent and control this pest -> Indeed, various methods such as forecasting, autumn and winter plowing, removing diseased leaves, trapping and killing adult insects, promoting biological and chemical control can all be used to control this pest.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4589", + "fact_text": "What pathogen is causing this disease -> This disease is caused by a pathogen called potato decay nematode, a plant parasitic nematode.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image5013", + "fact_text": "Will the growth point of plants be affected by this disease -> Yes, after the growth point is infected, the tender stem will shrink and turn brown, which may eventually lead to withering. In high humidity conditions, this problem is more severe and can easily lead to decay.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1775", + "fact_text": "Are there any visible brown spots on the cabbage in the image -> The cabbage leaves in the image do indeed have irregular brown spots.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4843", + "fact_text": "What are the damage features displayed in the image -> The image may show damage to crops caused by this animal, such as digging new seeds or stealing autumn grain. Flower rats have become a pest in farmland due to their behavior.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5751", + "fact_text": "What is the transmission route of this disease -> The spread is mainly achieved through conidia, which are produced by a fungus called Phyllostictasp.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2066", + "fact_text": "How are the male flowers of the plants in the image -> The images indicate that the male flowers of plants undergo premature whitening and eventually die, which is one of the obvious consequences of infection.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2857", + "fact_text": "Will the parts outside the blades be affected -> Yes, the bacteria may also infect the stems or fruits, and the diseased parts may produce a gray black to black brown mold layer similar to the leaves, and as the disease progresses, these parts will eventually turn black.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "cabbage looper 121", + "fact_text": "What is the cause of the abnormality on the crops in the picture caused by the acquisition of insects Answer: Biting food", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5386", + "fact_text": "How to prevent and deal with this pest -> The methods for preventing and treating soybean stem borer include agricultural control, biological control, and chemical control. Agricultural prevention and control mainly involves adjusting the planting layout to prevent the transfer of pests to other crops such as cotton; Biological control involves releasing red eyed bees during the peak egg laying period of the bean stem borer and applying Beauveria bassiana or B, t emulsion, while chemical control involves spraying relevant drugs during the peak egg hatching period.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3459", + "fact_text": "Is it normal for the crops in this image to have a white covering on their surface -> In the image, the root surface of the crop is covered with a white coating, indicating that the crop has been affected by a certain disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image338", + "fact_text": "Are there any preventive measures for this situation -> To prevent such problems, tomato varieties that are resistant to low temperature and weak light should be selected, and reasonable fertilization should be applied to avoid excessive nitrogen fertilizer. Controlling the temperature and moisture during the seedling stage is also crucial, such as maintaining the night temperature at 12-16 ℃.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2858", + "fact_text": "Observing this image, can you see any abnormal phenomena on the tomato fruit -> The surface of the tomato fruit in the image shows some gray black to black brown patches, which are usually manifestations of a disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5364", + "fact_text": "How severe is the impact of this pest on crops -> The larvae of leaf bees cause significant damage to the leaves, including holes and notches. In severe cases, it can even damage the flowers and tender pods of the retained plants, and a few larvae may bite the roots of the crops. When the number of leaf bees reaches a certain level, it may lead to significant losses within a few days.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4445", + "fact_text": "How did the disease on the image spread -> The spread of diseases is mainly through the scattering of larvae and eggs in the soil or manure after corn harvest, becoming the first source of infection the following year. In addition, it can also be carried and transmitted through humans, livestock, and agricultural tools, and the transmission in the field mainly relies on irrigation water and rainwater.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "mango deporaus marginatus pascoe 23", + "fact_text": "What color is the insect body in the picture Answer: Red and yellow", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "vitis colomerus vitis 159", + "fact_text": "Why do leaves have such fluffy objects -> Chromorus vitis", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5259", + "fact_text": "What is the impact of this pest on cotton -> Insect infestation mainly occurs on the back of cotton leaves, causing fine gray white or withered yellow spots on the leaves. If the damage is severe, the leaves will wither and fall off, which will affect the growth of cotton and correspondingly reduce cotton yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image1228", + "fact_text": "What is a non chemical method to reduce the occurrence of this disease -> A non chemical method is to reduce the formation of wet and stuffy environments by improving crop cultivation conditions, such as adjusting the use of nitrogen fertilizer appropriately and maintaining reasonable plant density, which helps to reduce the occurrence of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5512", + "fact_text": "Where are these wax secretions scattered throughout the leaves -> Mainly distributed on the back of leaves, these white flocculent substances are mainly secreted by the problematic insect body.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4715", + "fact_text": "What does the white vein sticky worm look like -> The adult body length of the white vein armyworm is about 11-13mm, with a wingspan of 27-29mm. The front wings are yellow brown, and the central trunk of the midrib is white and extends directly to the base of the wings. The white lines are surrounded by dark stripes. The egg is about 0.6mm long, oval to Mantou shaped, with fine surface and flocculent network. The color of the larvae changes from light blue to dirty yellow green, and the head is yellow brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1988", + "fact_text": "How may this situation affect plants -> This yellowing may lead to a decrease in the overall photosynthetic efficiency of plants, thereby affecting their growth and yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4599", + "fact_text": "Is there any upward or downward bending of the blades -> The petiole, leaflets, and leaf margins face upwards and do not unfold horizontally, which may indicate a lack of phosphorus in the plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4917", + "fact_text": "What pathogen is causing this disease -> The disease is caused by a fungus called Phytophthora boehmeriae Sawada, which has extremely strong survival ability and can survive in diseased fruits for a long time with high water tolerance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5470", + "fact_text": "What shape do the insects on the tree take on -> In the image, it can be seen that the insect is elliptical in shape, with a white powdery substance covering its surface. This appearance feature is very obvious in the image.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2812", + "fact_text": "What usually causes this situation -> This situation is usually due to insufficient availability of iron in the soil, which may be due to other factors such as soil being too alkaline or containing too much phosphorus fertilizer, which hinders the ability of the root system to absorb iron.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4745", + "fact_text": "What type of crop is in the image -> The crops in the image are of the miscellaneous grain type.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4347", + "fact_text": "Can we soak the seed solution to prevent seed infection for this disease -> Yes, soaking seeds is a good preventive measure. Seed infection can be prevented by soaking the seeds in 0.15 tobuzin solution for 10 minutes, which is an effective ingredient.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image670", + "fact_text": "What kind of climate is more conducive to the development of this symptom -> Warm and humid climate conditions are more conducive to the development of this disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4672", + "fact_text": "What measures can be taken to prevent and control this pest -> Preventive measures usually include removing weeds from fields and edges, especially in summer and autumn. Develop rice field management strategies to ensure timely heading, flowering, and filling of rice, and early maturity to reduce aphid infestation. When the aphid plant rate reaches a certain level, for example, when the aphid plant rate in late rice reaches 10% to 15%, and there are more than 5 aphids per plant, relevant pesticides should be sprayed in a timely manner.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato mosaic virus 1481", + "fact_text": "Does Tomato Mosaic virus disease cause twisted and deformed leaves Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3005", + "fact_text": "What is the impact of this environment on the roots of cowpeas -> In high humidity environments, the roots of cowpeas may be more susceptible to disease, but the specific root condition requires more detailed observation to confirm.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5808", + "fact_text": "Do the branches in the image also show any abnormalities -> Indeed, there are signs of withering on the branches, and some of them seem to have lost their vitality.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2203", + "fact_text": "How does the root condition of crops affect the aboveground eggplant -> Root lesions affect nutrient absorption, leading to atrophy and yellowing of aboveground plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1398", + "fact_text": "What is the health status of the cucumber stem in the image -> The image shows that the stem of the cucumber is relatively normal, without obvious water soaked lesions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4681", + "fact_text": "What prevention and control methods can reduce the impact of this pest -> Firstly, in agriculture, attention can be paid to removing weeds at the edges of fields and ditches, and during spring plowing and retting, more plowing and raking should be done to guide adults and larvae to surface, and then buried or burned deeply. When in severely damaged areas, relevant pesticides can be sprayed. It can also be controlled by sprinkling lime or tea cake powder, combined with methods such as farming, lime soil acidity, and enhancing soil permeability.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "grape downy mildew 5", + "fact_text": "What disease is causing the symptoms on the grapes in the picture -> Grape Downy Mildew", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4778", + "fact_text": "What is the impact of this organism on crops -> The organisms in the image, especially their larvae, mainly cause the leaves of crops to be eaten, which may affect the growth and development of crops. The impact in North China, East China and other regions has become increasingly severe in recent years.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "wheat phloeothrips 91", + "fact_text": "What is the name of the insect in the picture -> Wheat phloeothrips", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image184", + "fact_text": "Is there any moisture on the surface of the crop displayed in the image -> According to the image, although tissue decay is evident, it does not clearly indicate excessive moisture on the crop surface, which may be due to the obstruction of water transportation caused by diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "citrus nipaecoccus vastalor 66", + "fact_text": "The plants in the picture seem to have been damaged, right Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1499", + "fact_text": "Will the symptoms exhibited by the lettuce in the image spread -> Diseases may spread through soil or air, especially under suitable climatic conditions where the spread rate of diseases is accelerated.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image342", + "fact_text": "Is there a way to alleviate the severity of this situation -> It is indeed possible to reduce cracking by strengthening seedling management and using correct fertilization techniques. For example, controlling appropriate temperature and moisture, and avoiding excessive use of fertilizers, especially nitrogen and phosphorus fertilizers, at inappropriate times.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5526", + "fact_text": "How to effectively reduce damage caused by insects -> Chemical sprays such as dichlorvos emulsion can be used during insect activity, or plant leaf bait can be used to lure and kill adults, reducing their numbers and thus reducing damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image1519", + "fact_text": "Are there any visible signs of mechanical damage or insect damage on these lettuce -> The lettuce in the image does indeed exhibit leaf damage that may be caused by mechanical damage or insect damage, which are pathways leading to the invasion of pathogenic microorganisms.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1814", + "fact_text": "Can the plants in the image still be saved -> The situation seems quite serious, and if effective control measures are not taken, the plants may find it difficult to recover their health.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "alfalfa seed chalcid 143", + "fact_text": "What is the name of the creature on the leaf in the picture -> Alfalfa seed chalcid", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4467", + "fact_text": "So, how should they prevent this disease -> Firstly, in severely affected areas, planting this crop on sticky and damp soil should be avoided. In addition, attention should be paid to preventing low temperatures, and increasing the application of phosphorus and potassium fertilizers is also an effective preventive measure.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "soybean root rot 3", + "fact_text": "What diseases have invaded the crops in the picture -> Soybean root rot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1058", + "fact_text": "What are the surface features of the eggplant fruit in the image -> The surface of the fruit has formed brown spots with purple black edges, and the surface may be covered by white hyphae in humid environments.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2813", + "fact_text": "Under what soil conditions is this situation more likely to occur -> This symptom is more common in alkaline soil, and if the soil is deficient in iron or affected by excessive phosphorus fertilizer, similar yellowing phenomena can also occur.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image301", + "fact_text": "How can this phenomenon be prevented -> It is necessary to ensure the application of fully decomposed organic fertilizer and avoid excessive use of nitrogen fertilizer. Once harmful gases are detected, they should be immediately vented.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4201", + "fact_text": "How can the problems shown in the image be effectively prevented and addressed -> To prevent and treat this problem, it is recommended to choose disease resistant varieties, apply fertilizers reasonably, especially decomposed organic fertilizers, and strengthen water and nutrient management. In the early stages of the disease, high-efficiency calcium supplements can also be used for spraying treatment.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image6", + "fact_text": "Is there any abnormal phenomenon on the surface of the fruits in the image -> The melon and fruit parts in the image initially appear watery gray brown to dark gray, with surface anomalies causing noticeable color deepening.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "wheat longlegged spider mite 90", + "fact_text": "Which part of the insect in the picture is black brown Answer: Back", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5366", + "fact_text": "What does this insect look like -> The insect in the image is a small gray brown moth, with a body length of 6-7mm and a wingspan of 12-15mm. The wings are narrow and long, and the front and rear edges of the wings are yellow white with a three degree zigzag pattern. When the two wings close, they form three consecutive diamond shaped spots. The edge of the forewings is long and curled up like a chicken tail.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image3179", + "fact_text": "Is there any pattern in the distribution of this mold layer -> They usually spread at the leaf edges or on leaf surfaces with more water accumulation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3770", + "fact_text": "How do environmental conditions affect the development of this disease -> A warm and humid environment is usually conducive to the development of this disease. Specifically, when the temperature is between 20 and 30 degrees Celsius and there is more rainfall, the occurrence and development of diseases are more rapid.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image15", + "fact_text": "What impact will this pest have on plants -> This type of pest can increase the number of lateral roots in the underground part of plants, resulting in a cluster like root system and a decrease in functional roots. The root surface has spherical white female insects and brown cysts. The aboveground parts will exhibit poor growth, thinness, and yellow dwarfism. Plants with severe disease will have wilted leaves before maturity. In addition, such diseases can cause diseased plants to appear in a block like distribution in the field.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3735", + "fact_text": "How to prevent this situation from happening -> Preventive measures include selecting suitable planting areas, identifying diseased plants early, digging up and thoroughly removing them from the soil, and using specific drugs for soil disinfection to control the spread and development of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "tomato leaf miner 58", + "fact_text": "What insect is causing the phenomenon in the picture Answer: Leaf miner", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image362", + "fact_text": "Is it a disease that some of the tomatoes in the image have not turned completely red -> Not considered a disease, more precisely, it is a physiological issue related to the maturation process and nutrient absorption of plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4", + "fact_text": "What are the abnormal manifestations of the stem and vine of the melon in the image -> The stem and vine also exhibit water stained soft rot, and white flocculent mycelium clusters can be seen in the diseased area, followed by the formation of black mouse fecal shaped fungal nuclei.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "corn spot 2", + "fact_text": "What is the cause of the spots in the picture Answer: Corn spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5292", + "fact_text": "What type of crop is in the image -> The crops in the image belong to the category of cotton and hemp, and the type is hemp.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image644", + "fact_text": "Has the disease spot on the leaves affected the overall health of the leaves -> Yes, due to the fusion of lesions, larger plaques may form, leading to some leaves turning yellow and eventually falling off.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4387", + "fact_text": "Are there any other significant changes in the leaves -> Yes, in the absence of phosphorus, the leaves appear dark green with a purple red color and lack luster; Leaves lacking potassium will have yellow spots on the edges, and in severe cases, the edges will become scorched.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "corn mole cricket 74", + "fact_text": "Does the insect in the picture have tail whiskers Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4764", + "fact_text": "How to prevent and control this pest -> One method is to plant insect resistant sorghum varieties and try to sow them early at the appropriate time. Another method is to spray dichlorvos powder during the peak period of adult emergence. Meanwhile, during sowing, furrow application of Yingran Dan granules or mixing seeds with furan Dan gum suspension is also an effective way of prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3635", + "fact_text": "What parts of the leaves are mainly affected by this situation -> Mainly affecting the middle and lower leaves, the initial symptoms start from the leaf tip or edge.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4597", + "fact_text": "Why do some parts of the potato leaves in the picture turn yellow -> This may be because potatoes lack nitrogen. When nitrogen is insufficient, plant growth is hindered, and leaves first turn yellow from the base.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image5360", + "fact_text": "What crops are mainly affected by this pest -> This pest mainly affects cruciferous vegetables such as rapeseed, mustard, greens, cabbage, and radish.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5352", + "fact_text": "So what could be the cause of this change on plants in the image -> Well, due to the invasion of certain pests, the plants have undergone such changes. Especially for this type of pest, the adults lay their eggs in the leaf tissue, and the hatched larvae feed between the mesophyll and epidermis, forming such feeding marks.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4700", + "fact_text": "Do the crops in the image show any signs of being unhealthy -> Yes, the crop has been damaged by pests.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4942", + "fact_text": "Is it normal for the cotton leaves in the image to have yellow spots -> The cotton in the image shows symptoms of nutrient deficiency, and yellow spots may be an early manifestation of potassium deficiency.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "rice koji disease 1", + "fact_text": "Does the abnormal area in the picture show spore like morphology Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4734", + "fact_text": "What are the types of insects in the image -> The insect species in the image are pest types. Has a slightly dark yellow body and dark areas on the chest and abdomen (excluding some parts at the ends). The antennae are dark yellow, gradually deepening into grayish black.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2950", + "fact_text": "What are these cracks like -> They extend longitudinally along the fleshy roots, with varying depths and lengths, some even extending from the top of the root to the entire root.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image27", + "fact_text": "How to prevent and control this disease -> There are several ways to prevent and control this disease: ( 1 ) deep plowing, reducing bacterial sources, and seed cleaning and disinfection. ( 2 ) Choose resistant rice varieties for cultivation. ( 3 ) Reasonable fertilization, increased application of phosphorus and potassium fertilizers, and improved plant disease resistance. ( 4 ) Chemical prevention and control. For example, in the early stages of disease, pesticides can be sprayed on the surface of crop leaves for prevention and control.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image3084", + "fact_text": "The cabbage in the image looks somewhat unusual, why is that -> Observing the cabbage in the image, there is cracking in its leaf bulbs, which is caused by excessive water absorption and cell swelling.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image363", + "fact_text": "How should this situation be adjusted and improved -> Improvement measures can include increasing plant light and ventilation, adjusting water and fertilizer management to optimize nutrient supply, while paying attention to temperature control to avoid low or high temperatures affecting normal plant growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1990", + "fact_text": "What measures can be taken to alleviate or avoid this problem -> Reasonable irrigation and maintaining appropriate soil moisture are key, and selecting drought resistant varieties is also an effective strategy.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image449", + "fact_text": "Is this disease easy to control in soilless cultivation -> In soilless cultivation, timely replacement of nutrient solution can to some extent control the development of this disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4814", + "fact_text": "Which season are they usually most active in -> This type of insect is most active in spring and autumn, especially when the damage is more severe in spring.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2886", + "fact_text": "Is this disease seasonal -> Yes, this disease may overwinter on the diseased plants during the cold season, become active in spring, and become more severe during hot and rainy summers.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1498", + "fact_text": "Is there an effective prevention and control method -> Effective prevention and control methods include crop rotation, appropriate fertilization and cultivation methods, such as high ridge cultivation and plastic film covering, and can also be controlled through spraying.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4957", + "fact_text": "It seems that the condition is already quite serious. What may be the reason for it -> This disease is caused by a fungus called Ascochytaboehmeriae Woronich. This type of fungus has conidia that are flattened to nearly spherical in shape, black brown in color, ranging in size from 80 to 120 microns. The conidia are ovoid, colorless, and have a 1 septum, ranging in size from 10 to 21 x 4 to 5( ΞΌ m) Left and right.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "vitis apolygus lucorum 295", + "fact_text": "Does the insect in the picture have slender antennae Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1956", + "fact_text": "Is there any abnormality in the stem in the picture -> Sometimes black patches can be seen forming on the stem.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2989", + "fact_text": "What impact does this condition have on the health of the entire plant -> This situation leads to obstacles in the growth and nutrient supply of the entire plant, seriously affecting the overall growth and development of the plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4916", + "fact_text": "How to prevent and control this disease -> You can choose varieties with disease resistance, such as Zhongmian 12, while reducing the use of nitrogen fertilizer, improving drainage facilities, and avoiding excessive humidity. In addition, it is necessary to remove empty branches in a timely manner to reduce the spread of pathogens in the field. Of course, some chemical agents can also be used for prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4442", + "fact_text": "How did this disease arise -> The cause of this disease is a virus called Maizedwarfmosaicvirus. It is a part of the potato Y virus group, with linear virus particles that are very small. This virus can be stored for a long time in ultra-low temperature refrigerators and maintain its infectivity.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image3474", + "fact_text": "Is there an effective method to prevent or control the spread of this disease -> There are several methods that can effectively reduce diseases, including rotating non Solanaceae and Ginger crops, removing diseased plants from the field, increasing phosphorus and potassium fertilizer appropriately, and using appropriate pesticides for prevention and control in the early stages of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4814", + "fact_text": "What are the preventive measures for these pests -> The methods to prevent this pest include implementing rice cotton rotation, removing weeds inside and outside the field before sowing, and using irrigation to flood and kill some larvae in severely affected fields. In addition, chemical seed mixing is also a very effective preventive measure, such as using 75% methyl phosphorus emulsion to mix dry cotton seeds. During the emergence period, if the proportion of newly affected plants reaches a certain level, such as 10% before planting and 5% after planting, it is necessary to spray pesticides in a timely manner. Larvae can also be lured and killed by using toxic bait.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4932", + "fact_text": "Is there any way to prevent the occurrence of this disease -> Yes. The recommended method for preventive measures is to promptly remove diseased plant residues from the cotton field once harvesting is completed, and concentrate the diseased residues on composting or burning them. Disease resistant varieties can also be chosen, while promoting ridge breeding and scientific irrigation, as well as selecting organic fertilizers made by fermenting bacteria to avoid biased or excessive use of nitrogen fertilizer.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2725", + "fact_text": "What is the reason for this situation to occur -> This situation is usually caused by the excessive use of certain types of fertilizers, especially those containing ammonium, combined with the effects of high temperature and drought conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image276", + "fact_text": "What impact will stem decay have on the entire plant -> The decay of the stem can lead to poor water and nutrient transport, resulting in wilting and yellowing of the upper branches and leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2050", + "fact_text": "What prevention and control measures should we take for this situation -> For this disease, a comprehensive management strategy should be adopted, including selecting varieties with strong disease resistance and timely spraying with recommended fungicides. At the same time, attention should be paid to field management to ensure good drainage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image5422", + "fact_text": "What are the specific manifestations or symptoms of crop damage -> Adults and nymphs of this type of insect obtain nutrients by piercing and sucking on the cortical sap of buds, leaves, and tender shoots. Female adults lay eggs in tender shoots, which hinders the transportation of plant substances. Afterwards, the edges of the plant's leaves will turn yellow, with curled leaf tips and dark red veins. If the disease further develops, a reddish brown scorched appearance will appear at both the leaf tips and edges. The growth rate of sprouts will slow down or even stop completely.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5432", + "fact_text": "Is there any significant insect presence in the image -> Indeed, significant adult insects can be seen gathering in the tender parts of young trees and seedlings in the image. These insects are smaller in size and have a color similar to the soil, slightly gray in color.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image3658", + "fact_text": "Are there any other visible biological features on the leaves -> Yes, when the humidity is high, dark brown mold like substances can be seen on the surface of the leaves, which are the stem and spores of the pathogen.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4725", + "fact_text": "What specific damage characteristics does this pest have on corn -> The main damage to corn is the invasion of insect larvae, especially the female ears of corn. After being harmed, it will cause the fruit ears to not bear fruit and have a serious impact on yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato canker 17", + "fact_text": "Does Tomato Canker only harm fruits Answer: No", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4758", + "fact_text": "When is this type of organism usually active -> This type of organism is usually active before 9am to 17am, and during nighttime or rainy days, they tend to lurk in the back of the middle and lower leaves of the plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "citrus toxoptera citricidus 176", + "fact_text": "Is the body color of the insect in the picture black brown Answer: No", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4404", + "fact_text": "What color are the disease spots appearing on crop leaves -> The disease spots on the leaves may initially be light yellow spots or short stripes, but as the disease progresses, these spots will gradually expand and the color will change from yellow to brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5774", + "fact_text": "On which plants are these insects usually found -> This type of insect is generally found on various medicinal plants, including mandalas, gourds, goji berries, citrus fruits, and eggplants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "wheat stem rust 77", + "fact_text": "What is the pathogen of Wheat stem rust -> Wheat variant of Puccinia graminearum", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image3571", + "fact_text": "In which areas are such moldy layers usually prone to occur -> This type of mold layer mainly appears in areas with severely affected lesions. These structures are more pronounced under humid conditions, especially on the leaves and pedicels of plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2764", + "fact_text": "What other prevention and control measures can help improve the color of eggplants -> The use of thin films with high UV transmittance is very effective. In addition, it is also important to regularly replace the film and maintain its cleanliness, which can significantly improve the lighting effect.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "vitis polyphagotars onemus latus 55", + "fact_text": "How many pairs of feet are there in the creature in the picture Answer: Four pairs.", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5332", + "fact_text": "When is the season when the organisms in the image appear the most -> This type of pest occurs during large-scale cultivation in spring and autumn, especially during the periods of April to June and August to October, resulting in two peaks of pest occurrence in spring and autumn. In summer, due to high temperature and drying, as well as a significant reduction in cultivation area, the occurrence of pests will present a low tide.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5290", + "fact_text": "How to prevent and control this pest -> The methods of prevention and control include: hanging lamps to lure and kill adult insects; At the larval stage, 200 times of Bt emulsion containing 12 billion spores or 200 times of HD-l insecticidal powder containing 4000 units were spray; Placing red eyed bee bags during the peak spawning period also has a good preventive effect. If necessary, you can spray 2.5% trichlorfon powder, 1.5-2.5kg per 667m, or spray 90% crystal trichlorfon 1000 times solution or 50% Aikashi emulsion 1000 times solution before the age of 3. In addition, smoke agents made from 90% dichlorfon emulsion and other substances can also be used in hemp fields to fumigate and kill pests.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5173", + "fact_text": "Do the ball flowers in the image have any special symptoms -> Yes, the top of the petals of the ball flower initially shows signs of yellowing, and then the color gradually expands downwards to gray, and eventually the entire ball flower turns light brown to brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4534", + "fact_text": "What is causing this pathogen -> This disease is caused by ErysiphepisiDC, also known as Pea Powdery mildew, and Trichochladia baumleri (Magn.) Neger, also known as Baller's bundle silk shell. Both of these pathogens belong to the phylum Ascomycota fungi.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5417", + "fact_text": "What are the specific damages they cause to crops -> When this pest invades crops, it will cause the young heart leaves to become slender, wrinkled and unable to open, presenting a \"rabbit ear like\" appearance. If severely affected, crops may experience growth arrest, resulting in overall stunting and yellowing. In addition, damaged flowers can also cause difficulties in flowering and fertilization, and in severe cases, can even lead to flower infertility or failure to bear fruit.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4801", + "fact_text": "What color is the insect larvae in the picture -> The larvae are usually milky white with a reddish brown dorsal line and a wide reddish brown band on the forehead.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image6", + "fact_text": "How does this pest harm fruit trees and what are the symptoms -> This pest is characterized by aphids and adult aphids clustering on tender shoots, the back of tender leaves, and the surface of young fruits, piercing and sucking sap. The affected leaves show chlorotic spots, which then curl or shrink towards the back.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5761", + "fact_text": "How to control or prevent the invasion of this adult insect -> According to the suggestions in the data, methods to control this infringement include strict quarantine measures, controlling the source of pests, and possible biological control methods. For example, introducing natural enemies such as Diglyphusisaea, Pediobiusmitsukurii, etc. to naturally control the number of pests.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "wheat phloeothrips 285", + "fact_text": "What color is the insect in the picture Answer: Black brown", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2147", + "fact_text": "How to take measures to reduce the impact of this disease -> Low temperature protection measures can be taken in advance. When the disease is mild, strengthening water and fertilizer management can also enhance plant growth and compensate for losses caused by cold damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5046", + "fact_text": "Is there any abnormal behavior in the petiole -> In the image, it can be seen that the petiole changes from top to bottom to black brown, and some sides even have longitudinal cracks or indentations, which causes the petiole to twist and the leaves to invert and droop.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "mango flat beak 51", + "fact_text": "What is the color of the legs and claws of insects in this image Answer: Yellow white", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3088", + "fact_text": "What methods can prevent this kind of burn -> To prevent such burns, more precise fertilization methods should be adopted, such as applying fertilizers in holes or ditches and burying them in the soil. After fertilization, water should be poured in time to avoid direct contact with the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4405", + "fact_text": "Is there any way to prevent this disease -> There are three main steps to prevent and control this disease: first, select varieties with strong disease resistance for planting; The second is to reasonably control the sowing time. Winter wheat should not be sown too early, while spring wheat should be planted with varieties with moderate or longer growth periods, and formula fertilization techniques should be used; The third is to treat the seeds before sowing, such as soaking them in 45 ℃ water for 3 hours, or soaking them in 1% quicklime water at 30 ℃ for 24 hours, and then mixing them with 0.25% seed weight 40% seed mixing powder.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2098", + "fact_text": "What measures can be taken to prevent the occurrence of this disease -> Effective preventive measures include implementing rotation for more than two years to avoid damaging the roots during planting, loosening soil, or weeding; Timely drainage after rain; Once a diseased plant is found, it should be immediately excavated and disinfected with lime; Reduce or suspend watering during the onset of illness.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2344", + "fact_text": "What is the water situation in the picture, and is there any accumulated water -> The soil in the picture appears moist, and there may be a problem of waterlogging in the field.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4919", + "fact_text": "So are there targeted preventive measures and methods -> To prevent and control this disease, some preventive and control measures can be taken. For example, farmers can pay more attention to soil fertilization, apply nitrogen containing fertilizers moderately, and more phosphorus and potassium fertilizers, which can help prevent cotton from growing too quickly and enhance plant disease resistance. In addition, keep the countryside clean, reduce the source of bacteria, and promptly remove diseased bolls if found. Reasonable planting density and timely drainage can help reduce the breeding of pathogens. The prevention and control of butt pests and the use of pesticides are also commonly used methods for disease prevention.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4556", + "fact_text": "How should we prevent this disease -> There are several effective prevention methods: first, establish disease-free fields and collect seeds from disease-free plants; Then, appropriate disinfection treatment should be carried out on the seeds; In addition, avoid planting in low wetlands and use high beds or ridges for cultivation. Pay attention to ventilation and light transmission, and drain water in a timely manner after rain; In the early stages of the disease, some pesticides can be used for spraying, such as 72% agricultural streptomycin sulfate 4000 times solution or 30% basic copper sulfate suspension 400-500 times solution, 47% garenon wettable broad beans, peas, mung beans, etc.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2629", + "fact_text": "What are the benefits of early harvesting of root melons -> Early harvesting can avoid excessive nutrient consumption of the root melon, help the upper part of the melon obtain sufficient nutrients, promote balanced growth of the entire plant, and overall yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "wheat septoria 5", + "fact_text": "The wheat in the picture seems abnormal, doesn't it Answer: right", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image74", + "fact_text": "Is there any measure to prevent this situation from happening -> Taking appropriate cultivation measures, such as selecting disease resistant varieties suitable for local cultivation, ensuring no excessive application of nitrogen fertilizer, and maintaining good hygiene conditions in the field, are all effective methods of prevention.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "cowpea brown spot 1", + "fact_text": "What kind of disease has affected the leaves in the picture -> Brown spot disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4739", + "fact_text": "What are the significant features of this pest that I can notice -> Insect infestation can damage the young and tender grains of sorghum, using feces or food residues to block the mouth. In severe cases, this type of pest infestation can even consume the entire sorghum grain.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2690", + "fact_text": "What is the process of yellowing? Which part does it start from -> Yellowing usually starts from the top and there is no obvious boundary between the diseased and healthy areas.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2245", + "fact_text": "The image shows dwarfing of the diseased plant, what is the reason for this -> Dwarfism is a physiological disorder caused by viral infection. The virus affects the normal growth hormone balance of Jingshui vegetables, limiting plant growth and resulting in stunting.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4074", + "fact_text": "At which growth stage will this crack occur -> Usually, this type of cracking is most likely to occur in the stage before fruit ripening.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3922", + "fact_text": "Is there any measure in the image to show that it has been taken to control this situation -> There are no obvious signs of control or preventive measures in the image, and the disease seems to be still progressing.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4360", + "fact_text": "Is there an effective prevention and control method -> You can choose disease-free seeds and remove diseased residues, implementing rotation for more than 2 years. In autumn, cultivate deeply without stubble and eliminate self growing wheat seedlings. In terms of pesticide control, seeds can be treated with special pesticides, and pesticide spraying can be carried out during the wheat heading period.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5372", + "fact_text": "Does this pest pose a threat to other plants as well -> This pest can erode over 120 species of plants in 45 families, including cabbage, cabbage, radish, spinach, melons, legumes, green peppers, tomatoes, eggplants, and other crops, thus posing a threat to other plants as well.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1535", + "fact_text": "What measures can be taken to improve the disease resistance of plants -> By applying sufficient organic fertilizer and appropriate chemical fertilizers, the disease resistance of plants can be improved. Meanwhile, ensuring good moisture management and appropriate ventilation are also crucial.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5390", + "fact_text": "The crops in the image appear somewhat abnormal. Can you explain what the situation is -> The surface of the crop leaves in the image has many white spots, which are mostly caused by the ingestion of pests on the back of the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image4791", + "fact_text": "Does this pest and disease have a significant impact on the overall crop -> Yes, this type of pest and disease can have a significant impact on crops. Especially for peas, it has a significant impact on their fullness, seed quality, and yield, as well as the normal growth of vegetables.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tea brown blight 13", + "fact_text": "What kind of disease is the leaf in the picture suffering from -> Tea brown light", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image234", + "fact_text": "Can you see this spread in the image -> It can be observed that the color of the leaves gradually changes from the bottom, and a process of displaying similar symptoms one by one upwards.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4725", + "fact_text": "Under what conditions do these types of pests typically operate and lay eggs -> This type of pest prefers warm and humid environments, and the suitable temperature for adult oviposition is above 23 ℃. When the temperature drops below 20 ℃, they often reduce their egg laying. In addition, the development of larvae is also highly dependent on temperature and humidity, with 25-28 ℃ and a relative humidity of 75-90% being the most suitable.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1701", + "fact_text": "What are the special manifestations of this disease in high humidity and high temperature environments -> Under high humidity and high temperature conditions, the lesions are prone to perforation, especially the gray brown or black brown lesions on the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5283", + "fact_text": "How does this pest affect crops -> The larvae of pests feed on leaves to form gaps or holes, and in severe cases, only the leaf veins remain. The invasion of this pest can cause slow or stagnant growth of the affected plants, resulting in short stature, thin hemp bark, and low fiber quality.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image17", + "fact_text": "Is there any way to prevent this disease -> The methods to prevent this disease include selecting resistant varieties, removing infected perennial roots, and selecting disease - free and stem borer free seedlings; Acidic soil can be treated with a small amount of lime to adjust its pH value and reduce the occurrence of diseases; Winter and spring should choose \" cold tail and warm head \" weather for planting, and germination should be carried out during planting to promote early growth and reduce the occurrence of the disease.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "beet spot flies 282", + "fact_text": "The insects in the picture have some slender hairs on their bodies, right Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5440", + "fact_text": "Can you provide a specific description of the pest characteristics in the image -> In the image, some larvae can be seen on the mulberry leaves. These larvae have a darker body color, ranging from yellow green to dark green, and may be severely infected.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5407", + "fact_text": "What is its impact on crops -> This type of insect can cause soybean seeds to shrink and tender shoots to wither, affecting crop yield and quality.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2974", + "fact_text": "What effect does humidity have on the changes on these leaves -> In environments with high humidity, a small amount of white mold layer will appear in the affected area, which helps to further spread the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4593", + "fact_text": "What nutrient deficiency is causing this yellowing between leaf veins -> The yellowing between leaf veins is usually related to sulfur deficiency. Long term or continuous use of sulfur free fertilizers can lead to this symptom.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4506", + "fact_text": "What is the cause of this disease -> The pathogen of this disease is Xanthomonas campestrispv.holcicola, which is a short rod-shaped bacterium. The size of the bacterial body is 1.05-2.4 Γ— 0.49-0.9 (um). They are single, twin, or in short chains, and are surrounded by a layer of capsule. This type of bacteria does not have spores and has unipolar flagella. It is a Gram negative, aerobic microorganism. The most suitable environment for its growth has an average temperature of 28-30 ℃.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3135", + "fact_text": "Has the color of the center of these spots changed -> Yes, as the mesophyll cell tissue necroses, the color of the center of the spot changes from dark to light, usually appearing grayish brown to yellowish brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2954", + "fact_text": "What is the soil moisture in the image -> From the image, it can be observed that some parts of the soil appear relatively dry, while others are relatively moist. This uneven humidity may be a factor contributing to the problem.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5042", + "fact_text": "How to prevent and control this disease -> The methods for preventing and controlling this disease include: (1) selecting disease resistant varieties, and varieties with disease resistance and toxicity are more advantageous in production. (2) Use disease-free seeds and perform seed treatment, such as mixing seeds with 0.3% 50% Fumeishuang or 40% Dafudan. (3) Timely autumn plowing should be carried out on the harvested soybean fields to accelerate the decay of diseased residues and reduce the source of pathogens. (4) Spray the pesticide once at the beginning of flowering, bud stage, pod setting stage, and tender pod stage. The specific pesticide and concentration can be selected according to the actual situation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato mosaic virus 1461", + "fact_text": "What is the mode of transmission of Tomato Mosaic virus disease Answer: Juice", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image867", + "fact_text": "How to effectively prevent this problem with zucchini -> Properly increasing the night temperature in the cultivation area to reduce condensation, prevent excessive watering, and use appropriate pesticides for prevention and treatment.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2824", + "fact_text": "What would be the difference in leaf performance if the conditions were dry -> Under drought conditions, potassium deficient tomato leaves will appear dark green and relatively stiff, reducing the plant's drought tolerance. At the same time, there may be accompanying phenomena of falling flowers and fruits.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4310", + "fact_text": "How can we prevent the occurrence of this lodging phenomenon -> To prevent rice lodging, the following measures can be taken: 1) selecting lodging resistant varieties that are suitable for the local area; 2) Apply appropriate formula fertilizer to prevent biased or excessive application of nitrogen fertilizer, and spray specific liquid fertilizers if necessary; 3) Reasonably adjust the planting density; 4) For rice with lodging tendency, chemical spraying should be carried out at the beginning of the jointing stage to increase toughness.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3936", + "fact_text": "What is the overall form presented -> The overall shape presents a branching structure similar to coral, which is very unique.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image16", + "fact_text": "What kind of organism is causing this disease -> Sugarcane pineapple disease is caused by a fungus called Ceratocystisparadoxa, whose asexual form is called Thielaviopsisparadoxa. This fungus can remain dormant in soil for more than 4 years in the form of thick walled spores, resisting adverse environmental conditions.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1112", + "fact_text": "Is there any abnormal phenomenon on the fruit of eggplant -> The abnormal phenomena on the fruit include a watery appearance at the beginning, gradually browning and rotting in the later stage, and the boundary between the diseased and healthy parts is very clear. In environments with high humidity, gray mold like growth may also be observed.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image3415", + "fact_text": "What does this color change indicate -> This indicates that the leaves may be losing their normal function, such as photosynthesis, due to damage to the root system affecting nutrient and water absorption.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image5072", + "fact_text": "Is there any special pattern or color on the surface of the plants in this image -> The plants in the image display symptoms of rapeseed black rot disease. We can see yellow V-shaped spots on the leaves, veins turning black brown, and petioles turning dark green. When the humidity is high, there may be yellow bacterial pus overflowing, and the disease spot further expands, causing the leaves to dry up. The main axis may also have dark green water soaked spots, while the siliques may turn brown or black brown with some depression.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4712", + "fact_text": "What type of plants do these pests mainly prefer -> The pests in the image prefer plants such as corn, sorghum, millet, cotton, hemp, beans, sweet potatoes, sugar beets, tomatoes, chili peppers, and wheat.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4730", + "fact_text": "Does this image depict the damage caused by pests to crops -> Yes, the image shows that crops have been severely damaged by a pest.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image976", + "fact_text": "What is the reason for this phenomenon -> This is caused by a type of fungus, which belongs to the subphylum Pseudomonas.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4144", + "fact_text": "How to prevent this situation from happening in tomato cultivation -> To prevent this situation, it is recommended to use sulfur-containing fertilizers, such as ammonium sulfate or potassium sulfate, especially in protected cultivation where attention should be paid to the selection of fertilizers.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image811", + "fact_text": "Is there any way to prevent or control this situation -> Some cultivation measures can be taken, such as planting heat-resistant and weather resistant leek varieties. In addition, once the disease occurs, timely use of recommended pesticides for spraying, such as basic copper sulfate suspension, according to the recommended dosage and frequency, can help control the condition.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1941", + "fact_text": "How does this disease spread through soil -> Pathogens mainly survive in soil in the form of fungal nuclei for many years, with strong environmental adaptability and survival ability.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2000", + "fact_text": "What is the health status of the leaves of pea seedlings -> The impact on the leaves of pea seedlings is not clearly shown in the image, and the main symptoms are concentrated in the roots and seeds.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5473", + "fact_text": "What color are the insects in the image -> Insect wings are gray white and densely covered with small gray black dots.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5295", + "fact_text": "What are the methods for preventing and controlling this pest -> Some effective prevention and control methods include strict quarantine to prevent the spread of pests, specialized investigation and census of crops, and avoiding the introduction of vegetables and flowers affected by pests from epidemic areas as much as possible. In terms of agricultural prevention and control, it includes reasonable crop layout, crop rotation, appropriate thinning, and timely cleaning of the fields. In addition, using fly trapping paper to lure and kill adults, scientific medication, and using biological control methods to release parasitic wasps with high parasitism rates against the leaf miner are also effective control methods.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4293", + "fact_text": "How to prevent and control this disease -> The prevention and control of this disease mainly includes strengthening quarantine to prevent the long-distance transmission of pathogens, using resistant and tolerant hybrid rice, avoiding biased or delayed application of nitrogen fertilizer, cooperating with phosphorus and potassium fertilizers, and avoiding excessive watering. If necessary, it is also possible to refer to the chemical control methods for rice leaf blight for chemical control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5365", + "fact_text": "What type of crops are displayed in the image -> The crop in the image is an oilseed crop, which is a crop called rapeseed.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4334", + "fact_text": "So how to prevent and control the occurrence of this disease -> The main methods for preventing and controlling this disease include crop rotation, especially with crops such as corn, sesame, and melons, or planting winter wheat as spring wheat, which can avoid diseases caused by winter snow. In addition, increasing the application of organic fertilizer, phosphorus, and potassium fertilizers can enhance the plant's disease resistance. The timing of sowing and irrigation is also crucial, not too early or too late, and timely drainage should be carried out after the snow melts. Finally, seeds can be mixed with pesticides, such as using 40% carbendazim ultra fine wettable powder at a seed weight of 0.3%, which can achieve a control effect of over 90%.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image555", + "fact_text": "Are there any protective measures for these damaged fruits in the image -> According to recommendations, timely harvesting of slightly reddish near ground fruits and maintaining good drainage can help alleviate the condition.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5122", + "fact_text": "How does this disease usually spread -> This disease is mainly transmitted through diseased tissues and mycelium or spores in paddy soil, and can also be spread through air, water, or agricultural tools.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image156", + "fact_text": "Is there any problem with the crops in the image -> The leaves in the image have an unusual white powdery cover.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image890", + "fact_text": "How does this situation usually spread -> Mainly transmitted through aphids, it is also possible to spread through seed and manual contact.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image3128", + "fact_text": "Is there any specific morphology of the pathogen displayed in the image -> The image may have captured some characteristics of pathogens, such as white hyphae and pink mold like substances.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image751", + "fact_text": "What is the overall appearance of the plants in the image -> The overall growth of the plant appears to be poor, with withered and yellow leaves and damaged roots. The overall growth status is weak, showing obvious pathological characteristics.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image364", + "fact_text": "What preventive measures do we need to take when observing these situations -> Preventive measures include providing sufficient light and suitable temperature, ensuring a balance of water and nutrient supply, and avoiding flower and fruit shedding caused by environmental pressure.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2961", + "fact_text": "Has the garlic in the image been properly irrigated -> It is important to avoid excessively humid soil conditions for the prevention and control of this disease. Excessive irrigation increases the risk of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5767", + "fact_text": "What kind of damage do these insects usually cause to plants -> The insect larvae in the picture can feed on leaves, causing gaps or holes, and in severe cases, only the petiole remains, which can affect the flowering and fruiting of plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1403", + "fact_text": "Is there any indication of prevention and control measures in the image -> The image does not directly display obvious prevention and control measures, and it is necessary to carefully observe leaf symptoms and adopt correct prevention and control strategies in combination with structured knowledge.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "citrus toxoptera aurantii 193", + "fact_text": "What insects are densely packed on the plants in the picture -> Toxoptera aurantii", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5353", + "fact_text": "How to prevent and deal with this pest -> An effective method is to apply fully decomposed organic fertilizer to reduce adult egg laying. Timely prevention and control during the peak period of adult egg laying and maggot hatching. Medications can also be used to treat seeds or soil. In addition, poisonous grains can also be prepared for pest control during the planting process.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "apple Brown spot 24", + "fact_text": "What is the cause of the phenomenon in the picture -> Apple brown spot", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5398", + "fact_text": "How can we prevent and treat this pest -> The methods for preventing and controlling this pest can be found in the prevention and control methods of the striped bee edge bug. The specific prevention and control measures may vary depending on local conditions and pest control. It is best to consult local agricultural experts or pest control departments.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image174", + "fact_text": "So what methods can be used to prevent this situation -> Preventive methods include using specific chemical agents to treat seeds, strengthening seedbed management to avoid high temperature and humidity environments, and using appropriate pesticides for spraying during the seedling stage to enhance the plant's disease resistance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "rice leaf smut 23", + "fact_text": "What kind of disease is the leaf in the picture suffering from -> Rice leaf smut disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4651", + "fact_text": "What are the impacts of this pest on crops -> The pests in the image have a significant impact on crops. Their adults and nymphs both prick and suck on the sap of crops such as rice. This not only causes direct damage to crops, but may also lead to secondary infections of crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2768", + "fact_text": "How does the stripe appear on the stem -> In the upper and middle parts of the stem, initially appearing as dark green sunken short stripes, later turning into dark sunken oil soaked necrotic spots, these spots gradually spread and expand.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5263", + "fact_text": "In which parts do these insects usually move -> This type of insect likes to move around the nectar, especially feeding on tender leaves, stems, petioles, veins, and buds.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image473", + "fact_text": "Can you see the situation at the base of the plant -> At the base of the plant in the image, it is possible to see tissue collapse caused by bacterial invasion, resulting in stem collapse.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4700", + "fact_text": "What is the main damage caused by this pest to crops -> Destructive larvae can burrow into the stem, and in severe cases, the entire stem may be eaten empty. Mature larvae will burrow into the root and stem, biting off the stem or leaving only a small amount of epidermal connection, making the affected wheat prone to collapse.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image248", + "fact_text": "Is there anything special about the color change of these spots -> Yes, the lesion gradually changes from white to yellow brown and eventually turns black brown.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5239", + "fact_text": "Is there any characteristic that can distinguish the cotton damage caused by this pest -> There are some features that can help us identify the damage of pests to cotton. If boreholes are found on cotton and there are feces or accumulated insect feces around the holes, it may be the effect of this pest. For young buds and large bolls, pests can leave about 4mm large holes, causing cotton to produce insect infested flowers, also known as \"twisted flowers\". Generally, they are not eaten up, but large bolls are prone to decay or the fibers and cotton seeds inside the boll room solidify into black cakes or stiff bolls, with light yellow paste like or sawdust like moist feces inside and outside the holes.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "rice hispa 79", + "fact_text": "Does the back of the insect in the picture have a metallic luster Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5705", + "fact_text": "How are these spots distributed on the leaves -> These spots mainly appear at the leaf tips or edges, gradually expanding and affecting larger areas of the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4352", + "fact_text": "So what symptoms will these crops exhibit -> In the image, the spike of the crop seems to be the most affected part. You can see that some tassels are pulled out earlier than healthy ones and wrapped in a layer of gray film. Over time, this thin film ruptured and released black powder. When the black powder is blown away, the tassel is exposed. This disease can even cause the entire spike to be destroyed.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4084", + "fact_text": "Is there a recommended prevention and control measure for this situation -> Yes, the occurrence of fruit cracking can be reduced by improving water management and nutrient supply, especially calcium and boron supplementation, as well as timely harvesting.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4844", + "fact_text": "What terrain does this animal usually inhabit -> This animal generally inhabits sandy or semi sandy slopes, plains, and alpine meadows. They are typical grassland animals and usually operate in these areas.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5253", + "fact_text": "How can we prevent this insect from damaging crops -> Preventive measures can be implemented to address the damage caused by this insect, such as using crop cotton rotation to disrupt its food chain. If necessary, 90% crystal trichlorfon 900-1000 fold solution can also be sprayed to achieve good control effect.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1278", + "fact_text": "If the disease develops into the later stage, what changes will occur -> In the later stage of the disease, the original white mold spots will turn gray due to the aging of the hyphae, and the affected leaves will gradually turn yellow and wither.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1681", + "fact_text": "Why do leaves produce white powdery substances -> The infected leaf epidermis partially cracked and rolled back, resulting in the scattering of white powdery substances.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1230", + "fact_text": "Is the color change of the leaves significant -> Yes, the color change of the leaves is very obvious, showing an uneven distribution, and the color is much lighter compared to healthy leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1979", + "fact_text": "What is the impact of high humidity environment on this disease -> A high humidity environment can promote the occurrence and spread of this disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image1490", + "fact_text": "Do these amaranth leaves look healthy -> Not completely healthy, there are some damages on the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image4302", + "fact_text": "How should we prevent this situation -> Prevention methods include selecting disease resistant varieties, controlling the number of weeds, and strengthening management to improve disease resistance. Chemical drugs can also be used for prevention and control, such as using thiazide wettable powder, rapid flea net emulsion, or rapid herbicide wettable powder for spraying to prevent the reproduction of leafhoppers.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image3586", + "fact_text": "Do you have any prevention and control suggestions for this situation -> It is recommended to spray pesticides for prevention and control in the early stages of the disease, such as using Diclofenac emulsion or Segao water dispersible granules, while paying attention to increasing the application of organic fertilizer and phosphorus and potassium fertilizers to improve the overall disease resistance of the plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image4851", + "fact_text": "What are the characteristics of the leaves of weeds in the image -> The weed leaves in the image are narrow and linear, about 3 millimeters wide, and the base of the leaf may contain larger membranous leaf sheaths, making it difficult to distinguish from the leaves of major crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4088", + "fact_text": "So, can yellowed leaves return to green -> Leaves that have already yellowed will not return to their original green state, but controlling environmental factors can prevent new leaves from experiencing the same problem.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image903", + "fact_text": "What impact will this situation have on the entire plant -> When this situation is severe, a large number of spots fuse and cause the leaves to wither, yellow, and dry. The affected leaves cannot effectively carry out photosynthesis, which may affect the health and yield of the entire plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4933", + "fact_text": "Does the seed of the crop appear healthy in the image -> The seeds of the crops in the image are not very healthy. There is a disease called angular spot disease, which causes the seeds to have small dark green spots in the shape of primary oil soaked seeds, which then expand into nearly circular or irregular shapes where multiple lesions merge into an irregular shape, ranging from brown to reddish brown. The diseased area is sunken, the young bell falls off, and the ventricles of the mature bell part decay.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4397", + "fact_text": "So, how did this situation arise -> Usually, the formation of this situation is a gradual accumulation process. During the process of sowing, collecting, and threshing, due to improper operation or poor management, other varieties of wheat may be introduced, resulting in mechanical mixing. Meanwhile, in the natural environment, due to wind and insect transmission, different varieties of wheat may undergo natural hybridization, producing offspring with degraded traits.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "rice hispa 79", + "fact_text": "Is the insect in the picture covered with thorns on its back Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2676", + "fact_text": "So how to manage nutrition reasonably to prevent this situation -> Avoiding biased application of nitrogen fertilizer and maintaining nutrient balance is crucial, and timely use of plant protection products can help plants grow healthily and enhance their resistance.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2452", + "fact_text": "Under what cultivation conditions are celery more susceptible to disease -> In the case of protected cultivation or high fertilizer concentration, such as excessive application of nitrogen and potassium fertilizers, or high soil salt concentration, this problem can occur.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5479", + "fact_text": "Is there any special condition on the surface of the crop leaves in the image -> In the image, there are several defects on the surface of the leaves, as if they were eaten by something.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4707", + "fact_text": "Can you see their shape features on the image -> Yes, based on structured knowledge, we can see the morphological features of this insect in the image. Their body length is 10-13 millimeters, with wings spread 30-36 millimeters. Their chest, abdomen, and front wings are light yellow with distinct kidney shaped stripes.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1028", + "fact_text": "Do the plants in the picture show signs of water stress -> The leaves in the image appear reddish brown when dry, which may be a sign of water stress caused by diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4702", + "fact_text": "When does this pest mainly occur -> This type of pest grows once a year in the northern spring wheat area, overwintering with eggs. It begins to hatch and damage wheat seedlings in early and mid May of the following year. The wheat enters its peak damage period from tillering to jointing. And adults appear in the first and middle of July, and enter the peak of moth emergence in the first and middle of August.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato yellow leaf curl virus 23", + "fact_text": "Will tomato yellow leaf curl virus disease cause uneven surface coloring of fruits Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5680", + "fact_text": "What impact does the storm have on this situation -> After a storm, the condition usually intensifies because pathogens can spread and infect through wind and rain, especially during hot and rainy seasons.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1876", + "fact_text": "What are the treatment methods included -> The treatment method includes using specific fungicides for spraying, such as a 300 fold solution of 14% copper oxychloride solution or a 500 fold solution of 60% aluminum succinate wettable powder. Early treatment is particularly crucial. Seed treatment and appropriate cultivation measures are also recommended to prevent disease development.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image2329", + "fact_text": "Is there any other type of covering on the surface of the affected shepherd's purse -> Yes, the affected area will be covered with gray moldy material in humid environments.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5046", + "fact_text": "Is there an effective method to prevent this crop disease -> Some effective prevention and control methods include selecting disease resistant varieties, planting them in close proximity, and implementing rotation for more than three years. Timely removal of diseased plant residues in the field after autumn harvest can reduce the likelihood of disease in the coming year. When necessary, specific medical protectants can also be sprayed to prevent and control diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4828", + "fact_text": "What specific impacts do these damages have on crops -> This type of damage can hinder the absorption of water and nutrients by plants, leading to slow growth and, in severe cases, even overall plant death, which can have a significant negative impact on crop production and harvest.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4576", + "fact_text": "So, how do we prevent and control this disease -> Firstly, strict quarantine can be carried out, and epidemic areas and protected areas must be designated to strictly prohibit the transportation of potatoes from epidemic areas. The soil and plants growing on the diseased fields are also strictly prohibited from being transported outside. Secondly, selecting disease resistant varieties and switching to non Solanaceae crops are both effective practices. It is also possible to strengthen cultivation management, such as frequent tillage, application of clean manure, increased application of phosphorus and potassium fertilizers, and timely centralized burning of diseased plants. If necessary, soil disinfection can be carried out. Finally, in the early stages, prevention and control can be achieved by using specific proportions of chemicals.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "potato early blight 2", + "fact_text": "What disease is causing the abnormal phenomenon in the picture -> Potato early brightness", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5430", + "fact_text": "What are the significant morphological features of this pest that can be identified -> This type of insect pest has a body length of 12mm, a wingspan of 22-25mm, yellow to orange yellow, and many black spots on the surface of the body and wings resembling leopard prints. Oval shaped, 0.6mm long and 0.4mm wide, with a color that initially turns milky white to orange yellow and reddish brown. The larva has a body length of 22mm and a variety of colors, including light brown, light gray, light gray blue, and dark red. The belly is mostly light green.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1313", + "fact_text": "What causes the symptoms on the cucumber leaves in the picture -> The symptoms on the cucumber leaves in the picture may be caused by various environmental factors, such as excessive manganese, low temperature, and improper fertilization.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "citrus phyllocnistis citrella stainton 1", + "fact_text": "What insect is causing the abnormal phenomenon in the picture -> Citrus leafminer", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4490", + "fact_text": "What causes this symptom -> These symptoms are caused by a fungus called Alternaria alternata, commonly known as Alternaria alternata.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image673", + "fact_text": "Has other parts of the plant been affected -> Mainly the leaves are affected, and in severe cases, the leaves may wither and fall off, which may lead to the death of the entire plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image261", + "fact_text": "How does this disease usually spread -> This disease mainly invades through wounds and may also be transmitted through rainwater and irrigation water, especially in adverse weather conditions such as continuous cloudy and rainy weather.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5389", + "fact_text": "What organisms are involved in the formation of these damages -> These damages are mainly caused by some larvae, who tend to curl the leaves and feed inside, causing damage to the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2089", + "fact_text": "Does high humidity have a significant impact on this situation -> High humidity can indeed exacerbate the development of diseases, especially in environments with high soil and air humidity.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image262", + "fact_text": "Will this disease disappear after the fruit ripens -> This type of disease is persistent and usually persists until the fruit ripens.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image449", + "fact_text": "Are there any effective preventive measures that can be taken -> Effective preventive measures include using compost to reduce fertilizer use, timely replacement of nutrient solution in soilless cultivation, and implementing multi year rotation in soil cultivation to avoid continuous cropping.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image943", + "fact_text": "How is the development of the fruit -> The fruit is very rare and small, and some even fail to develop and form normally.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4801", + "fact_text": "What is the size of the adult worm -> The body length of adults is approximately 4 to 5 millimeters and the width is approximately 2.6 to 2.8 millimeters.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5424", + "fact_text": "What are the morphological characteristics of this organism -> The pests that cause damage to this crop typically have a body length between 14-18mm and a wingspan of 30-38mm, typically appearing grayish brown. The wings of this insect have unique markings such as brown circular stripes and kidney shaped stripes, as well as black dots. However, their body colors may vary slightly, including light green, light red to reddish brown, and even black purple.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image484", + "fact_text": "How are the spots on the tomato leaves in this picture formed -> These spots initially appear as dark brown spots immersed in water, usually developing into elliptical or irregular shapes, gradually expanding.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5505", + "fact_text": "What impact will this situation have on plant growth -> Affected plants may experience abnormal growth of new shoots due to insect infestation, and in severe cases, may cause fruit drop, which can have a negative impact on the overall health and yield of the plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4759", + "fact_text": "Is there any method to prevent and control this pest -> There are several prevention and control methods that can be adopted: 1) In summer, lighting can be used to lure and kill the second generation adults to reduce the occurrence of the third generation. 2) When adults and nymphs are concentrated on grasses such as foxtail millet, insecticides such as dichlorvos powder or 1605 powder can be sprayed in a timely manner. 3) If necessary, you can also spray pesticides such as Baode emulsion or Da Gongchen.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5078", + "fact_text": "Are the shapes and structures of these plants normal -> No, the plants in the image have been affected by nutrient deficiency disease on their structure. The plant grows thin and weak, with a short and slender main stem and a loose plant shape. In addition, the number of pods is small and the final flowering period is advanced, indicating that the overall physiological function of the plant has been seriously affected.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image1007", + "fact_text": "What may be the reasons for fruit deformation and shrinkage -> It may be due to poor nutrient absorption in plants caused by diseases, especially under the influence of cotton rot disease, which hinders the transmission of water and nutrients, resulting in poor natural fruit development.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image3061", + "fact_text": "What preventive measures are mentioned in the image in maintaining crop health -> Prevention and control measures include timely sowing, rotation with non cruciferous vegetables, application of sufficient organic and phosphorus potassium fertilizers, moderate watering and post rain drainage, timely removal of diseased leaves and field residues, and deep soil plowing.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "citrus phyllocoptes oleiverus ashmead 147", + "fact_text": "Is the body color of the insect in the picture yellow Answer: No", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5357", + "fact_text": "What prevention and control methods can be used to deal with this pest -> There are several methods to prevent and control this pest. The methods of agricultural prevention and control include removing residual plants and fallen leaves from vegetable fields, uprooting weeds, and breaking down their wintering grounds and food bases; Deeply plowing and sun drying the soil before sowing is not conducive to its living environment and can eliminate some pupae. The prevention and control methods of pesticides include 90% crystal trichlorfon 1000 times solution, 50% phoxim emulsion 1000 times solution, 21% killing (synergistic cyanide Β· horse emulsion) 4000 times solution, and large-scale spraying, which can prevent and control adult insects. The first two pesticides can also be used for root irrigation to control larvae. Other prevention and control methods can be found in the prevention and control measures for the yellow curly striped flea beetle.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4421", + "fact_text": "What causes this disease -> This disease is caused by a virus called Barley Yellow Dwarf Virus, with virus particles in an equiaxed regular 20hedron. When observing ultra-thin sections of leaf phloem tissue, virus particles with a diameter of 24nm can be observed under electron microscopy.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image569", + "fact_text": "The tomato plants in the image look very withered, what's going on -> The lethargy of tomatoes in the image may be caused by the spread of disease spots from leaves to the main stem.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4333", + "fact_text": "What is the nature of plant diseases -> This is a crop disease that mainly affects the leaves and stems of wheat.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4831", + "fact_text": "How does this insect reproduce -> After mating in spring, females usually lay eggs at a depth of 1 to 4 centimeters in the soil surface, and the larvae begin to harm seeds or seedlings after hatching.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2560", + "fact_text": "Will this disease cause the entire plant to wilt or even collapse -> Yes, in severe cases, the entire plant in the image may wilt or collapse, and the pathological condition is very obvious.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image5377", + "fact_text": "Which part of plants are mainly affected by insects -> This type of insect mainly feeds on the leaves and buds of cotton, and in severe cases, it will eat up the leaves, damage the buds and buds, and cause them to rot or fall off.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1619", + "fact_text": "What is the possible cause of this kind of spot occurrence -> This is caused by a fungal disease, related to high humidity conditions and frequent rainfall.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5364", + "fact_text": "Is there any abnormality on the surface of the plants in this image -> Yes, the image shows that there are holes and notches on the leaves of the plant, which are caused by the invasion of a leaf wasp larva.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4822", + "fact_text": "When is the main period of activity for these insects -> These insects usually start their activity from March to April when the temperature rises. Spring is the beginning period of their activity, and they continue to harm through autumn until they enter a dormant state in winter.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4676", + "fact_text": "How does this pest affect my crops -> This type of pest mainly harms crops by piercing and sucking the sap from their leaves. At the beginning, yellow spots will appear on the leaves, followed by the leaf tips turning red, and then irregular reddish brown spots or red veins and edges will appear on the leaves. Finally, the entire leaf will wither. If the crop is damaged before booting, it is usually not easy to tassel; If it is damaged after booting, it will lead to short and small panicles with more grains.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5763", + "fact_text": "What are the effects of this pest on plants -> The insect infestation in the image can cause larvae to feed on plant leaves and bite off tender shoots, seriously affecting plant growth and development.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image1935", + "fact_text": "What season does this situation usually occur in -> This type of disease is usually more likely to occur in high temperature environments after being damp and rainy.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5293", + "fact_text": "So what is the lifecycle of this pest -> This pest only produces one generation a year in Ningxia. Their larvae overwinter on the hemp stems and roots, and sometimes mix with the larvae of the longhorn beetle to cause harm. In the spring of the second year, they will transform into pupae and then emerge as adults around June. Adults love to move on plants in the umbrella family such as fennel and carrots.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2016", + "fact_text": "How to prevent corn from lodging again -> To prevent further lodging, it is advisable to soil in a timely manner after stabilization, and control the density and fertilization amount of plants appropriately, especially nitrogen fertilizer. The use of specific growth regulators may also help enhance the plant's ability to resist lodging.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "citrus parlatoria zizyphus lucus 2", + "fact_text": "What is the mode of transmission of the insects in the picture Answer: Wind", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5532", + "fact_text": "What is the possible cause of these deformed roots -> This type of abnormal lump in the root is usually caused by a type of slender parasitic organism that invades the plant roots and stimulates root cells to produce this lump.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4447", + "fact_text": "What are the specific causes of root tumors and ruptures -> This is caused by one or several nematodes. There may be multiple types of nematodes that cause different symptoms, such as root tumors and ruptures.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5651", + "fact_text": "How does this situation usually spread -> This situation is mainly transmitted through insects such as the yellow striped flea beetle and the cucumber 11 star leaf beetle.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5277", + "fact_text": "What is the main damage caused by this pest in the image -> The main damage caused by pests is that they affect the normal growth of crops, as they mainly move and reproduce in the stem positions of plants, thereby damaging the crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3719", + "fact_text": "Is there a recommended chemical agent for preventing and treating this disease -> Some can be treated with recommended medications such as 5% Tian'an water solution, 30% Beisheng emulsifiable oil, and 50% Diclofenac wettable powder, with a focus on spraying on the leaf sheath to control disease development.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4050", + "fact_text": "How did this situation arise -> This belongs to physiological diseases, mainly due to the fact that during the differentiation and development of tomato flower buds, if there is too much nitrogen fertilizer in the nutrient soil for seedling cultivation, the content of available nutrients in the soil will be too high, which will affect the normal development of flower organs and lead to the production of this abnormal fruit.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image1825", + "fact_text": "How to prevent this situation from happening -> Preventive measures include crop rotation with non leguminous crops, timely removal of disease residues and rational fertilization, especially potassium fertilizer, as well as attention to drainage to reduce field humidity. If necessary, appropriate pesticides can be used for spraying.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image12", + "fact_text": "Has this insect have any impact on crops in the image -> Yes, the insects in the image have a significant impact on the crops. They feed on leaves, fruits, and tender stems, forming many irregularly shape brown spots on the leaves. Excessive damage can cause the leaves to wither.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2669", + "fact_text": "What are the climate conditions displayed in the image -> The specific climate conditions cannot be seen from the image, but generally in high temperature and high humidity environments, especially in cloudy and rainy weather, such symptoms will worsen.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image806", + "fact_text": "Has the lesion in the image developed to the tip of the leaf -> Yes, there is a type of lesion that starts from the leaf tip and appears as a watery stain before turning light green with brown wheel markings.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image833", + "fact_text": "How do pests on plants affect pumpkins -> Insect pests, such as aphids and leaf beetles, can exacerbate the spread of viruses and plant diseases by biting and feeding on pumpkin juice.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image2193", + "fact_text": "If such a situation occurs, what preventive measures are usually taken -> To prevent high-temperature damage, timely ventilation to reduce leaf surface temperature is a very effective measure. In addition, partial shading can also be used, such as using insect nets to reduce solar radiation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4530", + "fact_text": "How does this disease spread -> This disease pathogen mainly overwinters in seeds or disease residues through hyphae, or on crops through conidia, and then spreads through wind and rain. In addition, premature sowing, excessive nitrogen fertilizer, and planting in damp areas can all exacerbate the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4689", + "fact_text": "What type of crop is in the image -> The crop in the image is wheat, specifically barley.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2225", + "fact_text": "How to prevent or alleviate the occurrence of this symptom -> Efforts should be made to avoid intercropping with other crops with high calcium uptake, such as cabbage, soybeans, and tomatoes. Adequate watering should also be carried out in the morning and evening to keep the soil moderately moist. Increase the application of organic fertilizer, balance the use of nitrogen, phosphorus, and potassium fertilizers, and apply fertilizer in a reasonable and phased manner. In addition, regular foliar spraying of trace element fertilizers such as calcium and manganese can also help with prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5334", + "fact_text": "What are the main forms of crop damage caused by this pest -> The larvae of this pest feed on leaves. They nibble on the leaf flesh, sometimes leaving leaves with holes or notches, and in severe cases, only the veins remain. In addition, the insect excrement emitted by the larvae pollutes the leaf surface, reducing the commercial value of vegetables.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tea red leaf spot 501", + "fact_text": "What is the dissemination method of Tea red leaf spot -> Spread of wind and rain", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5233", + "fact_text": "Is there any abnormal behavior of the crop leaves in the image -> The leaves in the image show notches and holes, which may be caused by the larvae of a certain pest feeding on the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5377", + "fact_text": "Where do the pests in the image live -> This type of pest is distributed throughout the country. In North China, there are 4-5 generations per year, 5-6 generations in the Yangtze River Basin, and 6-9 generations in Fujian. They can reproduce year-round in Guangdong, Guangxi, Fujian, and Taiwan.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1139", + "fact_text": "What changes will these lesions exhibit under specific climatic conditions -> Under high temperature and rainy conditions, these lesions will quickly spread and grow dense white fluff at the affected area.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5326", + "fact_text": "Is there a specific time or season when crops are affected by pests -> Yes, this type of pest is most severe in winter in Taiwan from December to March.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4744", + "fact_text": "Can other special biological features be observed in the image -> It can be seen that some small insect bodies are concentrated in certain parts of the crop, which may be the main cause of the above problems.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3248", + "fact_text": "Is it possible for the neighboring fields to also be affected by this -> It is possible that this disease usually originates from nearby fields of poisonous lettuce or other crops, and is transmitted through aphids.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3423", + "fact_text": "What are the abnormal symptoms of the leaves in this picture -> Oil stained reddish brown dots initially appear on the leaves, gradually developing into nearly circular to irregularly shaped reddish brown necrotic spots.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2639", + "fact_text": "Why is nitrogen missing in soil -> The nitrogen deficiency in soil may be due to strong sandy soil, nitrate loss caused by excessive watering or rain, microbial denitrification, and insufficient or uneven nitrogen fertilizer application.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1", + "fact_text": "How does this disease harm crops -> The pathogen of this disease overwinters with the disease residue or in soil through hyphae, sclerotia, and conidia. When the conditions are suitable, conidia are produced and spread to the blueberry inflorescence through air flow. Under the condition of external exudates ( such as nectar ) as nutrients, conidia are easy to germinate. Through the susceptible parts of blueberries such as withered flowers, withered stigma, damaged leaves, and wounds, initial infection is achieved. After infection occurs, a large number of conidia can be produced for secondary and multiple infections.", + "source": "Agri-LLaVA-Chatbot-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image2244", + "fact_text": "What causes this symptom -> This symptom is caused by several viruses, mainly including turnip mosaic virus, cucumber mosaic virus, and tobacco mosaic virus.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4674", + "fact_text": "What are the morphological features of the species in the image -> The insects in the image have significant morphological features. Among them, adult males can grow up to 15-33mm in length, while females range from 19-40mm in color, appearing yellow green, brown green, and green. The leading edge of the forewings is green, with the remainder being light brown. Insects have a broad, oval shaped head, with the head extending forward, compound eyes oval shaped, and filamentous antennae. Their wings extend beyond the end of their hind legs. The tail of male insects is nearly conical, while the lower back corner of the back plate of the 2nd to 3rd segments of the abdomen of female insects is prickly. Among these insects, nymphs are 5-6 years old, with a few being 7 years old. The wing buds of 4-year-old insects are triangular in shape, and the last wing bud extends beyond the third segment of the abdomen.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2571", + "fact_text": "How is the condition of the fruit -> There are also small water soaked spots on the fruit, which then expand and become irregular in shape. In severe cases, a large amount of dirty white bacterial pus may overflow on the surface of the fruit, and water stained decay may occur inside.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5279", + "fact_text": "May I ask what are the activity habits of this pest -> This type of pest can reproduce twice a year in Shawan, Xinjiang, and coexist with the hemp stem borer. The pupation begins in mid May of the following year, with mid June being the peak period for overwintering adult emergence, mid to late June being the peak period for eggs, early July being the peak period for larvae, and mid to late July being the peak period for pupae. The peak period of the first generation adult emergence is in early August. In early October, the larvae mature and overwinter.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image813", + "fact_text": "What is the condition of the petiole and stem -> This situation can also occur on the petioles and stems, displaying similar white powdery features.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3830", + "fact_text": "Have you seen any solid objects near the roots -> Yes, some mouse fecal shaped fungal nuclei can be seen near the roots, which are derived from the initial white flocculent hyphae.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image3432", + "fact_text": "How much area will these small black dots cover -> These black dots usually appear concentrated on the infected concave lesions, and depending on the degree of infection, they can locally cover or form a more scattered dot like pattern.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4019", + "fact_text": "Is there any special change in the leaf veins in the image -> The color of the leaf veins in the image has changed to purple, which is significantly different from the normal green leaf veins.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image4625", + "fact_text": "What is the manifestation shape of this pest -> In the image, the pest is reflected in a spindle shape, and its size is 20-30mm long, which is a very distinctive observation structure.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2592", + "fact_text": "How to deal with the unfolding of this situation -> Immediate measures should be taken, such as adjusting the concentration and dosage of medication, implementing irrigation mitigation measures if necessary, and monitoring the environmental temperature of the seedbed to ensure appropriate soil temperature.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4556", + "fact_text": "What is the route of transmission for this disease -> This disease is mainly caused by the overwintering of pathogenic bacteria within the bean seeds and becomes the initial source of infection in the following year. In addition, factors such as excessive plant growth, untimely drainage after rain, excessive fertilization, and encountering low temperature obstacles in production, especially sudden onset of disease after frost damage, can all lead to the rapid expansion of diseases. It is more susceptible to disease during off-season cultivation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4306", + "fact_text": "Does the crop in the image appear to have been attacked -> Yes, in the image, you can see that the growth of crops has been affected. The phenomenon of withered seedlings, withered sheaths, and ear problems may all be caused by this pest in the image.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "species identification", + "entity": "image4885", + "fact_text": "What is the approximate height of the plant -> According to the image, the height of this weed is approximately between 20 and 90 centimeters.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2867", + "fact_text": "What effective preventive measures are there for this physiological disease -> Ensuring suitable temperature and lighting conditions is the key to prevention. Proper management of nitrogen fertilizer and water supply during seedling cultivation, as well as ensuring sufficient calcium nutrition for seedlings, can effectively reduce the occurrence of this phenomenon. At the same time, avoid low temperatures in the environment, especially at night.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image2749", + "fact_text": "How to effectively prevent this situation from developing to a more serious stage -> If diseased plants are found, they should be promptly uprooted, buried deeply, or burned to prevent the disease from spreading to other healthy plants.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image2748", + "fact_text": "Are there any other special signs on these leaves -> Yes, signs of withering can be observed on the leaves, ultimately leading to the shedding of the entire plant.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2458", + "fact_text": "How to effectively prevent or reduce the occurrence of this disease -> Seed treatment, appropriate cultivation measures, and timely spraying are all effective preventive measures. For example, seeds can be soaked in potassium dihydrogen phosphate solution and treated with metalaxyl seed dressing, appropriate cultivation and water management measures can be taken, and diseased leaves can be promptly removed or sprayed with appropriate pesticides.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "wheat powdery mildew 3", + "fact_text": "When the relative humidity exceeds what level, it can lead to the spread of this disease Answer: 70%", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4098", + "fact_text": "Have these symptoms of leaves and roots affected the overall growth of tomatoes -> Yes, due to damage to the roots, the absorption function is weakened, which in turn affects the nutrient supply of the aboveground parts, leading to slow growth. In severe cases, plants may wilt and die.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image1115", + "fact_text": "Is there any abnormality in the leaves of the plant -> The leaves are relatively weak and have a lighter color, indicating a nutritional imbalance caused by excessive nitrogen fertilizer and water.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image3609", + "fact_text": "What is the overall condition of the basil plants in the image -> The overall appearance of the basil plant in the image is wilted and powerless, with some leaves already beginning to wither.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5398", + "fact_text": "How big are the creatures in the image and what do they look like -> The organism in the image is a pest, with its adult body measuring 15-17mm in length and 3.6-4.5mm in width. It is narrow and yellow brown to black brown, covered with white fine hairs. Its head forms a triangle in front of the compound eyes, and the back shrinks as thin as the neck. Its antennae are longer in the first segment than in the second segment, with slightly enlarged ends in the first, second, and third segments. The base half is pale in color, while the base of the fourth segment is pale at a distance of 1/4. The front chest back plate and chest side plate have many irregular black particles. The front lobe of the front chest back plate tilts forward, with a collar at the front edge and two bends at the back edge. The side corners are prickly. Small shield triangle. The anterior wing membrane is light brown in color, slightly longer than the end of the abdomen. The lateral border of the abdomen is slightly exposed, alternating yellow and black.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4447", + "fact_text": "I have observed abnormalities in the crop roots in this picture. Can you tell me what's going on -> The crop roots in the image have been attacked by a disease, which inhibits root development, reduces quantity, and may lead to tumors and root rot.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4816", + "fact_text": "Is there an effective prevention method for this pest -> The prevention and control methods include implementing rice cotton rotation and removing weeds inside and outside the field before sowing. Pesticides can also be used for seed mixing or spraying during the emergence period. In addition, baiting is also an effective method of prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image1014", + "fact_text": "How does this surface whitening and hardening occur -> This is caused by direct sunlight, which strongly radiates and causes burns to epidermal cells.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5433", + "fact_text": "What are the characteristics of the larvae that can be observed in the picture -> The larvae have a long body length and a gradual change in surface color from light green to brown. Their color is similar to that of tree bark, providing a good camouflage. In addition, the body of the larva is slightly cylindrical, with black dots scattered throughout its body.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5250", + "fact_text": "What are the specific characteristics of this pest -> In the image, the pest body is 13-18mm long, slender and emerald green. Small head, light yellow white, with a brown patch above the monocular area. The front chest shield and hip plate are similar to the body color or light yellow; Chests and feet are light yellow or light yellow brown. Its adult body length is 6-8mm, wing span is 15-20mm, and it is yellow brown. The tentacles are filamentous, and the lower lip must be clearly extended forward. The front wings are slightly rectangular, with a dark brown base, middle band, and end stripes.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4824", + "fact_text": "What damage did the pests in the image cause to crops -> In the image, insect infestation mainly affects the stem base of wheat, leading to green withering of the heart leaves and later yellow withering and death. This may cause a shortage of seedlings and ridges in the field, or lead to seed damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5780", + "fact_text": "Are there any measures in nature that can help control the number of these larvae -> In nature, specific natural enemies such as the narrow faced wasp can help control the number of this larva, especially in the second generation of pest infestation, where the number of natural enemies is relatively high, and sometimes even artificial chemicals can be used for control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4815", + "fact_text": "How to prevent the damage of this pest to cotton -> The methods to prevent this pest include implementing rice cotton rotation, removing weeds from the field before sowing, and using pesticides to mix seeds. If the number of newly damaged cotton seedlings reaches a certain proportion, it is necessary to spray pesticides in a timely manner. Poisonous bait can also be used to lure and kill larvae to reduce insect damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image4500", + "fact_text": "How does this disease spread -> The specific infection pathway is not yet fully understood. Infection usually occurs before the stigma and anthers of the flower are exposed outside the protective glumes, and 2-3 days after the glumes are opened, a gray white winter spore pile can be seen. Diseases are mainly transmitted through winter spores, which can germinate without dormancy after browning. The germination temperature range of winter spores is 10-35 ℃, and relative humidity below 90% is not conducive to their germination.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image665", + "fact_text": "How does the mung bean in the picture enhance the plant's own resistance -> Suggest improving the cultivation environment, such as appropriately reducing plant density to enhance ventilation, reducing excessive nitrogen fertilizer application, and paying attention to field hygiene to remove disease residues.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5239", + "fact_text": "How can cotton be prevented from being harmed by this pest -> There are multiple methods to prevent cotton from being harmed by this pest. The most effective methods are agricultural and biological control. Agricultural prevention and control includes adhering to correct harvesting and planting rules, such as timely transportation of wheat outside the field after harvest. For cotton and corn in mixed planting areas, it is necessary to pay attention to the appropriate area ratio and avoid cross planting as much as possible. Biological control includes releasing parasitic wasps such as red eyed bees during the peak spawning period of corn borers, and spraying Beauveria bassiana or B, t emulsion during the larval stage. Chemical control can also consider spraying specific chemicals after specific start-up conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1810", + "fact_text": "Under what climatic conditions will this situation become more severe -> The conditions of heavy rain, high humidity, and low temperature will make this situation more severe. The plants in the picture are more prone to disease when the temperature is between 11-24 ℃ and the relative humidity is between 72% and 85%.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1803", + "fact_text": "What are the characteristics of these lesions -> The center of the lesion is slightly sunken in a thin papery shape, with slightly raised edges, and the diameter is usually between 1 and 3 millimeters.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5505", + "fact_text": "Are there any visible small insects or insect marks on the leaves -> Yes, in the image, you can see some dark brown or dark brown small insects gathering on the back of the leaves and tender stems.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3777", + "fact_text": "Under what conditions does this situation usually worsen -> The incidence rate is usually high in rainy seasons, especially in the case of poor management of the protected areas. In addition, the initial infection caused by watering or water spraying through pipes, as well as humid climate conditions, can also exacerbate the development of this disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5398", + "fact_text": "Is there anything unusual about the crops in the image -> The crops in the image have been affected by this pest. Adults and nymphs provide nutrients by sucking juice through thorns. When leguminous vegetables begin to bear fruit, they often cluster and cause damage, leading to the withering of buds and flowers, and the formation of fruiting pods or shrunken grains; In severe cases, the entire plant withers and there is no harvest.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5411", + "fact_text": "What are the obvious effects of insects on plants -> The gnawing of this insect can cause leaves to have notches and holes, thereby affecting the photosynthetic capacity of plants and ultimately affecting their overall health and growth.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4950", + "fact_text": "So, under what circumstances is this disease more likely to occur -> Generally speaking, this disease is more likely to occur in hot and humid weather, especially in low-lying areas. In addition, excessive application of nitrogen fertilizer or in long-term continuous cropping fields can also worsen the condition.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4981", + "fact_text": "What are the abnormal manifestations of plant fruit parts -> The fruit stalks and pods in the picture are infected, appearing black brown and rotten. The fruit stalks are prone to breakage, leading to fruit drop.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4741", + "fact_text": "What kind of damage can pests cause -> Insect damage is mainly caused by larvae feeding on leaves, which can consume an entire area of plants. They will also collectively migrate to another place to continue causing harm. In fact, this pest has caused two large-scale outbreaks in some areas of North China, Northwest China, and Northeast China in the past.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "citrus parlatoria zizyphus lucus 68", + "fact_text": "There is an insect distributed on the surface of this fruit, right Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5367", + "fact_text": "What type of crop does this pest usually prefer -> This type of pest mainly parasitizes on cruciferous vegetables, including rapeseed, cabbage, purple cabbage, broccoli, cauliflower, mustard, cauliflower, cabbage, and radish.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1749", + "fact_text": "Does the environment around the plants in the image contribute to the occurrence of this situation -> Yes, high humidity and suitable temperature conditions may promote the occurrence and development of this situation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4918", + "fact_text": "What is the pathogen that causes this symptom -> The pathogen is a fungus, a subphylum of fungi called Diplodiagossypina Cooke, also known as cotton colored two celled. Its conidia are black and lurk beneath the epidermis. Its conidia are oval shaped, colorless, but will turn black brown upon maturity.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "soybean mosaic disease 4", + "fact_text": "Can the symptoms of leaves be used to determine what diseases they are suffering from -> Soybean mosaic disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5327", + "fact_text": "How do the peas in the image look -> The peas in the image may have been eroded by the tobacco aphid, and there may be signs of its feeding, such as damage to buds, flowers, fruits, tender stems, leaves, and buds. Especially fruit decay caused by decay is the main reason for reduced yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "mango sternochetus frigidus 59", + "fact_text": "What is the reason for the abnormal phenomenon in the picture -> Sternochetus frigidus", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4937", + "fact_text": "So how to prevent and control this disease -> Firstly, in response to the frequent occurrence of this disease in the field, it is necessary to strengthen cotton field management, such as repairing drainage and irrigation systems, and promoting the normal development of root systems by maintaining appropriate water content in the soil. At the same time, increasing the application of organic fertilizers, promoting the use of compost made by fermenting bacteria or planting green manure, adopting formula fertilization techniques, especially in the later stage, attention should be paid to increasing the application of phosphorus and potassium fertilizers. When symptoms of yellow leaf stem blight appear, you can spray 2% urea solution or Huimanfeng active liquid fertilizer, with a dosage of 400 milliliters per 667 square meters, mixed with 400-500 times water, and spray 2-3 times continuously.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image4301", + "fact_text": "How is this disease transmitted -> The main mode of transmission of this virus is through an insect called the brown planthopper. Lice carry viruses and can transmit them to healthy rice crops. It is worth noting that the virus cycle in lice is 10 days, and they can carry and transmit the virus for life, but cannot transmit the virus to the next generation.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1655", + "fact_text": "What abnormality appears on the lettuce leaves in the image -> The lettuce leaves in the image are covered with a layer of gray mold, resembling water stains and rotting.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4701", + "fact_text": "How should we prevent and control this pest -> Adults can be lured and killed, for example, by using their habit of laying eggs on the leaves of cereal crops. They can insert straw or straw stalks into the wheat field, replace them with new ones every 5 days, and burn them all together. Medication can also be used for prevention and control, such as spraying 2.5% dichlorvos powder or 5% chlorpyrifos powder before the third instar of larvae.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4292", + "fact_text": "What are the main transmission routes and suitable conditions for the disease in the image -> The main transmission route of this disease is through the transmission of rice seeds, straw, and self growing rice, becoming the initial source of infection, and there may even be cross infection between wild rice and Li's rice. Bacteria mainly invade from wounds, and bacterial pus can be transmitted through wind, rain, dew, and other means, and then re infect. The suitable disease condition is high temperature and humidity. For example, typhoon and rain may cause wounds, making the disease prone to epidemic. At the same time, biased application of nitrogen fertilizer and excessive watering can also exacerbate the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4529", + "fact_text": "Does this disease have a particularly favorable growth environment -> Yes, the most suitable invasion temperature for this disease is 20 ℃, with a maximum of 30 ℃ and a minimum of 1 ℃. When spores germinate and invade, it only takes 8-12 hours at 20 ℃, but 3-4 days at 5 ℃. In addition, it is necessary to have humidity saturation and a certain degree of moisture on the host surface for spores to sprout and invade. Acidic soil, sticky or poorly drained soil, and potassium deficient continuous cropping fields can promote the occurrence of this disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "vitis parathrene regalis 5", + "fact_text": "Has the plant in the picture been invaded by insects Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image2043", + "fact_text": "Why do the corn leaves in the image have a purple red color change -> In the image, the purple red color of corn leaves is mainly due to the influence of carbon metabolism under specific conditions, which leads to the accumulation of sugar in the leaves and ultimately promotes the formation of anthocyanins.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4707", + "fact_text": "What kind of damage have they caused to crops -> The damage caused by this insect to buckwheat is mainly manifested by the larvae in the early hatching stage nibbling on the flesh of tender leaves, leaving behind a thin leaf epidermis, and the bitten leaves are in a thin film shape. As the larvae grow, they will spin silk and roll leaves, hiding them and gradually feeding through the leaves. When they occur on a large scale, they can lead to a reduction of over 40% in production.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2059", + "fact_text": "Is there any special requirement for fertilization in this situation -> In adverse climate conditions such as high temperature, drought, or continuous rain, it is recommended to use active organic fertilizers and high-efficiency amino acid liquid fertilizers, which can improve crop stress resistance and nutrient absorption efficiency.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image467", + "fact_text": "What are the characteristics of these irregular lesions -> The lesion is V-shaped, with irregular edges and a grayish white appearance when the center develops. In a humid environment, gray mold layers may appear on the surface of these lesions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4796", + "fact_text": "What are the effective prevention methods for dealing with this pest -> There are various methods for preventing and controlling this type of pest, and insect resistant varieties can be selected. Generally, varieties with hairy or limited fruiting habits have insect resistance or resistance. You can use black light to lure and kill adult insects. Specific pesticides can also be sprayed in the early stages, such as 10% imidacloprid wettable powder 1500 times solution or 40% fenvalerate 2000 times solution. Of course, medication should be stopped 7 days before harvesting.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "citrus toxoptera aurantii 18", + "fact_text": "What is the name of the insect in the picture -> Toxoptera aurantii", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5487", + "fact_text": "How to prevent such leaf erosion -> Preventive measures include timely cleaning of fallen leaves and plant debris, reasonable control of plant density to increase ventilation and light transmission, and the use of appropriate biological or chemical insecticides for pest control before pest activity.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image2038", + "fact_text": "The leaves of the plants in the image look very abnormal. What is causing this -> The black mold spots on the leaves of plants in the image are caused by a type of mold, usually related to the activity of insects such as aphids.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "tomato mosaic virus 1476", + "fact_text": "What is the appropriate temperature range for the occurrence of Tomato Mosaic virus disease Answer: 20-25 ℃", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5266", + "fact_text": "Is there an effective prevention and control method -> The prevention and control methods can refer to the treatment methods for green blind bugs. Specific recommendations need to be determined based on the level of pest development and the condition of crops.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image5801", + "fact_text": "In what environment do the adults in the picture usually live -> This type of adult usually lives on certain specific tree species in Guangdong, Guangxi and other regions, and is most common on the branches of plants such as longan and lychee. From June to November, they may be seen in the fields of these places, with July to September being the most abundant period.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5416", + "fact_text": "What are the specific symptoms of pest damage to crops -> According to the knowledge base, this pest can cause the leaves to become slender, wrinkled and unable to open, forming a so-called \"rabbit ear shape\". If invaded by pests, young heart leaves will be damaged, affecting crop growth, flowering, and fertilization. In severe cases, it can cause plant growth to stagnate, appearing short and yellow weak. After the flowers are damaged, it may lead to infertility or lack of fruit.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image5005", + "fact_text": "What are the abnormal symptoms of sesame leaves in the image -> The sesame leaves in the image have initially dark brown, nearly circular to irregularly shaped lesions, ranging in size from 4-12mm, with indistinct wheel spinning. The edges of the leaves are brown and covered with a black mold layer. When the disease is severe, the leaves will wither and fall off.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "weed management", + "knowledge_type": "management instructions", + "entity": "image4922", + "fact_text": "How can we prevent the disease from continuing to spread when crops are infected -> Firstly, we can avoid excessive density, enhance field management, weed control in a timely manner, and drain water in a timely manner after rain to prevent moisture retention in cotton fields. Secondly, fungicides such as 40% sulfur suspension or 50% carbendazim wettable powder can be sprayed in the early stages of the disease, and should be sprayed every 7-10 days. If resistance is found, other fungicides can be used instead. Through these methods, we can effectively prevent further spread of diseases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image5374", + "fact_text": "How many types of insects cause damage in the image -> The image only shows damage caused by one type of insect.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4649", + "fact_text": "What damage does this pest cause to rice -> This type of pest, whether adult or nymph, will feed on the juice of rice, thereby affecting the ripening of seeds.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4829", + "fact_text": "What are the characteristics of the body structure of this insect -> This type of insect has a slender body, with a final larval body length of about 32mm, a flat head, and distinct differences between the thoracic and abdominal segments.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5423", + "fact_text": "What are the specific characteristics of crop pest problems -> Crops with this pest infestation may have their larvae entangle and consume the interior of flowers, leaves, or stems. It is common to find seeds that have been emptied, as well as black fruits and yellowed plants caused by them.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image5441", + "fact_text": "Do the plant branches in the image look healthy -> Not very good, the plant branches in the image appear to have signs of insect damage, and there are chrysanthemum shaped tunnels forming in the branches.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image1369", + "fact_text": "What changes will occur in lesions under different environmental conditions -> In humid environments, the lesions will turn black brown and overflow with an amber gel like substance similar to resin; In a dry environment, the lesions appear reddish brown and show signs of drying shrinkage and longitudinal cracking.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image4708", + "fact_text": "Are there any effective prevention and control methods -> There are some methods that can do their best to prevent the occurrence of this disease and pest. For example, implementing crop rotation between wheat and non gramineous crops. In addition, 3% methyl isocarbophos granules can be used before sowing, with a dosage of 3kg per 667 square meters, and it can be sprinkled in the planting ditch for soil treatment. After rain or irrigation, 2.5% methyl isocarbophos or other organic phosphorus pesticide powders can be sprayed at noon, which can also be considered an effective control method.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image1645", + "fact_text": "Does the picture show the overall growth of the plants -> From the image, it can be seen that the overall plant growth is not vigorous, showing signs of slow growth and malnutrition.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image801", + "fact_text": "Is there any special change in the disease spots on the leaves in a humid environment -> Yes, when the humidity is high, the diseased areas on the leaves will produce black moldy substances.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image2868", + "fact_text": "What should be noted when preventing this situation -> To reduce the incidence, low temperatures and excessive use of nitrogen fertilizer should be avoided. Meanwhile, maintaining a suitable supply of water and calcium is also crucial.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4865", + "fact_text": "What is the shape of a plant's inflorescence -> The shape of the inflorescence is a narrow cylindrical shape, presenting a grayish green color. The spikelets are densely arranged on the inflorescence.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "insect/pest identification", + "entity": "image4424", + "fact_text": "What microbial factors are causing this problem -> The pathogen that causes this disease is a fungus called Bipolaris carbonum Wilson, also known as Charcoal long worm fungus. This fungus has dark brown conidia and light colored tips. Its conidia are elliptical in shape, with a wide center and gradually narrowing at both ends. The conidia have 4-10 septa, usually 5-7.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1547", + "fact_text": "What effective preventive measures can be taken -> Prevention can be achieved by timely ventilation and dehumidification, reducing leaf condensation time, and spraying designated pesticides to control the development of this disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4688", + "fact_text": "What are the main damage characteristics caused by pests -> Pests mainly prick and suck sap on the ears, causing slow growth of damaged wheat, reduced tillering, and a decrease in thousand grain weight. This is a serious crop pest that may affect wheat yield.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "tomato leaf miner 17", + "fact_text": "What serious consequences will the abnormal phenomenon in the picture bring Answer: Leaves wither", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4121", + "fact_text": "What is the thickness of these leaves -> Leaves caused by nitrogen deficiency are thinner than normal leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image5549", + "fact_text": "What is the mode of transmission for this situation -> This disease is transmitted through the transportation of infected ginger seeds or through irrigation water, surface water, underground pests, and rainwater splashing in the field, and is highly dependent on a humid environment.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "symptom/visual description", + "entity": "image4158", + "fact_text": "How can we effectively improve the health status of these plants -> Organic fertilizers should be increased to enhance the effectiveness of boron in the soil and advance the application of boron containing fertilizers. If symptoms of boron deficiency have appeared, timely foliar spraying of boron containing solution should be carried out to help the plant recover its health.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "mango dasineura sp 5", + "fact_text": "Does Dasineura sp cause leaf detachment Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image3233", + "fact_text": "Do you see any methods for treating this disease in the picture -> Although the treatment method is not directly shown in the figure, the general recommended practices include timely removal of the diseased plant, improvement of drainage, and appropriate use of antifungal agents.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "mango sternochetus frigidus 437", + "fact_text": "Why does the blade in the picture exhibit this abnormal phenomenon -> Sternochetus frigidus", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "mango sternochetus frigidus 1", + "fact_text": "Does the abnormal phenomenon in the picture occur on the surface or inside of the fruit Answer: Internally", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5240", + "fact_text": "What is the activity habit of this pest -> It is a multi generational seasonal pest. It can reproduce once a year in Northeast China and twice in North China. Insects will overwinter as second instar larvae, forming thin cocoons in the bark crevices. When the leaf spreading period of poplar and willow begins in mid April of the following year, they begin to move. At night, they climb trees and cause damage, while during the day they hide in tree holes or other dark crevices.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2291", + "fact_text": "What impact does this infection have on seedlings -> In the seedling stage, the impact of infection is relatively severe. White frost like mold spots can be seen on the stems and leaves, causing the seedlings to gradually wither and die.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4764", + "fact_text": "When is this pest most active -> This type of pest is most active in the morning and evening, and they usually search for suitable places to lay eggs during these two time periods.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image4507", + "fact_text": "How does this disease affect the leaves of crops -> This disease mainly damages the leaves of crops. When there are many lesions, it can cause partial or complete withering of the leaves.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4814", + "fact_text": "How many generations does this insect reproduce in a year -> This type of pest usually reproduces 3 to 4 generations per year. Among them, the damage to cotton seedlings by the first generation larvae is the most severe.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "image4697", + "fact_text": "How does this pest survive and reproduce on plants -> This type of pest can produce 2-3 generations within a year. Breeding for one generation in spring, followed by 1-2 generations in autumn. They can overwinter as adults, eggs, or nymphs. Overwintering mites hatch and cause damage in spring. And they mainly occur in dryland wheat fields, with pseudolethality, laying their eggs on hard soil blocks or small stones and wheat stubble or soil blocks in the wheat fields.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image4937", + "fact_text": "Are there any specific factors that contribute to the occurrence of this condition -> Yes, there are some specific factors that can affect the occurrence of this condition. Firstly, soil, nutrition, climate, and cultivation conditions are all related to the occurrence of diseases, among which the supply of potassium fertilizer is crucial. Secondly, if cotton fields are continuously cultivated for a long time, the fertility is not high, and the supply of fertilizer and water is insufficient, it is very easy to cause this disease. In addition, excessive rainfall in the early stage leads to rapid growth of cotton aboveground parts, but shallow root systems weaken the ability to absorb nutrients, resulting in more severe disease. If rainstorm suddenly clears during the drought period from July to August, the transpiration force will increase sharply, which will lead to physiological disorder and more serious disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5373", + "fact_text": "Can plants recover from the pest infestation in the image after being controlled -> Structured data does not provide specific recovery information. But usually, timely and effective prevention and control can avoid further losses, and the degree of recovery may depend on the severity of the pest and the timeliness of treatment.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "pepper virus disease 29", + "fact_text": "What kind of disease does the chili pepper in the picture suffer from -> Chili pepper virus disease", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "wheat cerodonta denticornis 24", + "fact_text": "Does the shape of the larvae in the picture resemble maggot like Answer: Yes", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4784", + "fact_text": "Is there any way to prevent and treat this pest -> Firstly, you can medicate the seed potatoes. For seed potatoes with pests, fumigate them with bromomethane or carbon disulfide, or spray them with 90% crystal trichlorfon or 25% quinophos emulsion at a rate of 1000 times. Let them dry before storage. Secondly, timely soil cultivation should be carried out to prevent the potato chunks from exposing to the surface and avoid being laid eggs by adults. Finally, pesticides can be used for prevention and control. During the peak period of adult infestation, 10% Saibokai emulsion at a rate of 2000 times or 0.12% Tianli E wettable powder at a rate of 1000-1500 times can be sprayed.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "wheat spindle streak mosaic disease 1", + "fact_text": "What is the pathogen of the toxic disease of Wheat Spindle Stream Mosaic Disease -> Wheat Spindle Stream Mosaic Disease Poison", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image5329", + "fact_text": "Do the plants in the picture have potential control methods -> There are several prevention and control methods, including mechanical hunting and egg removal when the number of insects increases, as well as the use of biological control methods, such as using natural enemy insects. In addition, enhancing the management of plants themselves can also help reduce damage.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image2942", + "fact_text": "What is the reaction of crops in high humidity environments in the image -> In environments with higher humidity, crops are more affected because the pathogen is more likely to develop and spread under humid conditions.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image5523", + "fact_text": "Does this insect activity have any impact on plants -> The feeding activity of this insect will gradually weaken the overall health of the plant, leading to plant weakness and, in severe cases, may cause the branches to wither.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image4065", + "fact_text": "What are the different forms of fruit changes in this type of fruit -> From mild to severe, the first is the shape of an open pomegranate, called a pomegranate fruit; When more severe, it forms irregular fruits, also known as cat face fruits; At its most severe stage, it will split into petals, resembling a lotus flower, with multiple small heads protruding from the top, also known as lotus fruit or multi headed fruit.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "symptom/visual description", + "entity": "image5294", + "fact_text": "What kind of damage do they cause to crops -> They will cause direct damage to crops. Adults will bite the leaves, forming notches or holes, and in severe cases, leave only the base of the leaf veins. Larvae can damage the cortex of ramie fiber roots, underground stems, and nutrient roots, or gradually penetrate into the pulp, forming irregular wounds. Some may even bite off or empty the underground stems or root bases.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image4709", + "fact_text": "Does the wheat in the image appear to have suffered any damage -> Yes, the wheat in the image was indeed pecked by birds from the stage of filling to maturity, showing symptoms of damaged grains and ears. In severe cases, this situation can have varying degrees of impact on the harvest.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image2641", + "fact_text": "What methods can prevent plants from experiencing this situation -> By adjusting the nutrient balance in the soil, such as reducing excessive application of boron, phosphorus, calcium, and nitrogen, and supplementing potassium in potassium deficient soil, iron absorption can be promoted, thereby preventing yellowing of leaves and fruits.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image1983", + "fact_text": "What should be noted to prevent this situation -> We should do a good job in water and fertilizer management, especially by applying more organic fertilizers to cultivate healthy seedlings. At the same time, it is also necessary to control aphids to cut off the transmission path of viruses. In the early stages of the disease, it is necessary to promptly remove diseased plants in the field to control the spread of the disease.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "nutrient deficiency", + "knowledge_type": "management instructions", + "entity": "image3328", + "fact_text": "Are there any recommended practices to prevent further spread of the disease -> Appropriate agricultural measures should be taken, such as clearing ditches and draining water, increasing the application of organic and phosphorus potassium fertilizers, and avoiding excessive use of nitrogen fertilizers. In addition, during the initial stage of the disease, use recommended pesticides for spraying and control every 7 to 10 days, with continuous control for 2 to 3 times.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "generic identification", + "knowledge_type": "species identification", + "entity": "wheat scab 3", + "fact_text": "What bacteria are causing Wheat Scab Answer: Fusarium", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image5240", + "fact_text": "Are there any effective prevention and control methods -> For this type of pest, it can be combined with the prevention and control of other pests. If the situation is serious, spraying 5% glyphosate emulsion or 20% pyrethroid emulsion 3000 times can also be used for prevention and control.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "insect/pest identification", + "entity": "mango flat beak 15", + "fact_text": "Please name the organisms on the leaves in this picture. -> Mango flat beam", + "source": "Agri-LLaVA-VQA-Bench" + }, + { + "subdomain": "pests control", + "knowledge_type": "disease identification", + "entity": "image4815", + "fact_text": "How many generations can this pest reproduce in a year -> This pest can produce 3 to 4 generations per year, mainly the generation of larvae that cause damage to cotton seedlings.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "pests control", + "knowledge_type": "management instructions", + "entity": "image4651", + "fact_text": "So how to prevent and control this pest -> I cannot provide clear information on the prevention and control methods, as the provided knowledge base only provides a simple prompt \"see rice thorn edge melting\", without a detailed prevention and control strategy.", + "source": "Agri-LLaVA-instruction-tuning" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000002.JPG", + "fact_text": "Provide the most precise disease identification you can. -> This plant appears to be healthy and free of disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000003.jpg", + "fact_text": "Which disease or problem specifically affects this specimen? -> This is a healthy plant leaf.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000005.JPG", + "fact_text": "What specific disease symptoms are present on this tomato leaf specimen? -> This is a viral infection: TYLCV.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000009.JPG", + "fact_text": "What disease, if any, is visible on this Soybean leaf? -> This plant appears to be healthy and free of disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000010.JPG", + "fact_text": "What specific disease symptoms are present on this tomato leaf specimen? -> This is Late Blight, caused by the oomycete Phytophthora infestans.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000011.JPG", + "fact_text": "What disease determination can be made from this visual data? -> The diagnosis is Tomato Yellow Leaf Curl Virus (TYLCV).", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000012.JPG", + "fact_text": "What specific disease symptoms are present on this tomato leaf specimen? -> This tomato leaf shows classic signs of TYLCV, like yellowing and curling.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000015.JPG", + "fact_text": "Can you determine what disease is impacting this tomato leaf sample? -> The large, dark, water-soaked lesions are a key sign of Late Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000022.JPG", + "fact_text": "What symptoms might appear if this Tomato were infected with Bacterial spot? -> The key visual difference would be the absence of circular spots with target-like patterns.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000026.JPG", + "fact_text": "State the specific disease with complete accuracy. -> No signs of disease are visible; the plant is in good health.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000028.JPG", + "fact_text": "Please give the official disease classification for this foliage. -> The cause is the bacterium Candidatus Liberibacter asiaticus, leading to Huanglongbing.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000029.JPG", + "fact_text": "Can you establish the exact disease affecting this specimen? -> The pest responsible is the Two-spotted spider mite.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000032.JPG", + "fact_text": "What is the specific disease designation for this case? -> This is Late Blight, caused by the oomycete Phytophthora infestans.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000034.JPG", + "fact_text": "Can you make a definitive disease determination from this image? -> This is Early Blight, identifiable by the 'target-like' concentric rings in the spots.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000059.JPG", + "fact_text": "What disease indicators would be missing in a healthy version of this plant? -> The key visual difference would be the absence of evidence of orange or brown pustular structures.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000065.JPG", + "fact_text": "Is there a specific disease that can be identified on this tomato leaf? -> The plant is suffering from a Late Blight infection.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000068.JPG", + "fact_text": "What disease, if any, is visible on this Peach leaf? -> The plant is affected by Bacterial Spot disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000074.JPG", + "fact_text": "Please give the official disease classification for this foliage. -> The diagnosis is Target Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_000076.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> This tomato leaf shows classic signs of TYLCV, like yellowing and curling.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000077.JPG", + "fact_text": "What symptoms might appear if this Apple were infected with Cedar apple rust? -> A healthy version of this plant would not exhibit the evidence of orange or brown pustular structures.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000080.JPG", + "fact_text": "What disease manifestation can be observed on this tomato foliage? -> The causal agent is the Tomato Yellow Leaf Curl Virus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000082.JPG", + "fact_text": "What disease, if any, is visible on this Cherry leaf? -> No signs of disease are visible; the plant is in good health.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000086.JPG", + "fact_text": "What infectious agent, if any, is causing symptoms on this tomato leaf? -> The diagnosis is Bacterial Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000087.JPG", + "fact_text": "What disease symptoms would not exist in a healthy version of this plant? -> A healthy leaf would be uniformly green and free of the symptoms of disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000087.JPG", + "fact_text": "What specific disease symptoms are present on this tomato leaf specimen? -> The numerous small, angular spots are characteristic of Bacterial Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000088.JPG", + "fact_text": "Which disease symptoms would be absent following successful treatment? -> The key visual difference would be the absence of evidence of orange or brown pustular structures.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000089.JPG", + "fact_text": "What disease, if any, is visible on this Corn leaf? -> Cercospora leaf spot Gray leaf spot", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000090.JPG", + "fact_text": "Is there a specific disease that can be identified on this orange leaf? -> This is citrus greening disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000092.JPG", + "fact_text": "Given the observable symptoms, what disease is present? -> This is citrus greening disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000095.JPG", + "fact_text": "What infectious agent, if any, is causing symptoms on this tomato leaf? -> This is damage from Spider Mites.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_000096.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The symptoms, especially the olive-green mold on the leaf underside, indicate Leaf Mold.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000096.JPG", + "fact_text": "Which pathogenic infection, if present, is manifesting on this tomato leaf? -> Diagnosis: Leaf Mold.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000101.JPG", + "fact_text": "What disease determination can be made from this visual data? -> This is Bacterial Spot. Note the small, dark, water-soaked lesions.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000103.JPG", + "fact_text": "What disease manifestation can be observed on this tomato foliage? -> The diagnosis is Bacterial Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000104.JPG", + "fact_text": "What specific disease symptoms are present on this tomato leaf specimen? -> The plant is affected by Bacterial Spot disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_000114.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this orange leaf's health? -> The cause is the bacterium Candidatus Liberibacter asiaticus, leading to Huanglongbing.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_000116.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> This is Late Blight, caused by the oomycete Phytophthora infestans.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000116.JPG", + "fact_text": "What disease, if any, is visible on this Potato leaf? -> The condition is identified as Late Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000117.JPG", + "fact_text": "What symptoms might appear if this Pepper bell were infected with Bacterial spot? -> A healthy leaf would be uniformly green and free of the circular spots with target-like patterns.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000118.JPG", + "fact_text": "What core factor underlies these disease manifestations? -> The causal agent is the Tomato Yellow Leaf Curl Virus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000118.JPG", + "fact_text": "Which disease symptoms would be absent following successful treatment? -> If the plant were healthy, the evidence of orange or brown pustular structures would be absent.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000124.JPG", + "fact_text": "What disease manifestation can be observed on this tomato foliage? -> The plant shows no symptoms of pathology.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000128.JPG", + "fact_text": "Which pathogenic infection, if present, is manifesting on this tomato leaf? -> The plant shows no symptoms of pathology.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000129.JPG", + "fact_text": "Is there a specific disease that can be identified on this tomato leaf? -> This is a viral infection: TYLCV.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000134.JPG", + "fact_text": "What infectious agent, if any, is causing symptoms on this tomato leaf? -> The plant is suffering from a fungal infection: Septoria Leaf Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000136.JPG", + "fact_text": "What disease state does this plant exhibit? -> The plant is suffering from a fungal infection: Septoria Leaf Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image_000137.JPG", + "fact_text": "Please identify the exact disease name affecting this plant. -> This is a viral infection: TYLCV.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000139.JPG", + "fact_text": "What symptoms might appear if this Tomato were infected with Early blight? -> A healthy leaf would be uniformly green and free of the round lesions with bull's-eye appearances.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000139.JPG", + "fact_text": "Can you determine what disease is impacting this tomato leaf sample? -> The specimen is healthy.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000141.JPG", + "fact_text": "Can you make a definitive disease determination from this image? -> The condition is identified as Late Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000143.JPG", + "fact_text": "Which disease or problem specifically affects this specimen? -> The cause is the bacterium Candidatus Liberibacter asiaticus, leading to Huanglongbing.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000145.JPG", + "fact_text": "What accounts for these disease indicators? -> This is Bacterial Spot. Note the small, dark, water-soaked lesions.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000147.JPG", + "fact_text": "What symptoms might appear if this Tomato were infected with Leaf Mold? -> The key visual difference would be the absence of yellow surface spots and velvety green undersurface.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000147.JPG", + "fact_text": "What infectious agent, if any, is causing symptoms on this tomato leaf? -> The plant shows no symptoms of pathology.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image_000148.JPG", + "fact_text": "What symptoms might appear if this Tomato were infected with Spider mites Two-spotted spider mite? -> A healthy leaf would be uniformly green and free of the evidence of orange or brown pustular structures.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000148.JPG", + "fact_text": "Is precise disease identification possible from these visual symptoms? -> The plant shows no symptoms of pathology.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000158.JPG", + "fact_text": "Can you diagnose any disease affecting this tomato plant tissue? -> The diagnosis is Target Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000159.JPG", + "fact_text": "What disease symptoms would not exist in a healthy version of this plant? -> A healthy leaf would be uniformly green and free of the evidence of orange or brown pustular structures.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000162.JPG", + "fact_text": "What disease or disorder is this plant experiencing? -> This is a viral infection: TYLCV.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000165.JPG", + "fact_text": "What disease, if any, is visible on this Potato leaf? -> These 'bullseye' lesions are a tell-tale sign of Early Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000166.JPG", + "fact_text": "Which disease affects this specimen? -> The causal agent is the Tomato Yellow Leaf Curl Virus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000168.JPG", + "fact_text": "Which visual abnormalities would disappear after disease elimination? -> A healthy version of this plant would not exhibit the yellow spots paired with olive-green undersurface fungus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000168.JPG", + "fact_text": "What is the specific disease designation for this case? -> The diagnosis is Tomato Yellow Leaf Curl Virus (TYLCV).", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000177.JPG", + "fact_text": "Identify the pathogen or disorder with full precision. -> This is damage from Spider Mites.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000179.JPG", + "fact_text": "What exact disease or disorder is manifesting in this plant? -> The symptoms, especially the olive-green mold on the leaf underside, indicate Leaf Mold.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000184.JPG", + "fact_text": "Which causative agent is responsible for these disease signs? -> This is Late Blight, caused by the oomycete Phytophthora infestans.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000187.JPG", + "fact_text": "What specific disease symptoms are present on this orange tree leaf? -> This is citrus greening disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000189.JPG", + "fact_text": "What disease, if any, is visible on this Blueberry leaf? -> The plant shows no symptoms of pathology.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000191.JPG", + "fact_text": "What disease manifestation can be observed on this tomato foliage? -> The plant is infected with Target Spot fungus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000193.JPG", + "fact_text": "What disease manifestation can be observed on this tomato foliage? -> This tomato leaf shows classic signs of TYLCV, like yellowing and curling.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000195.JPG", + "fact_text": "Please give the official disease classification for this foliage. -> This is citrus greening disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000205.JPG", + "fact_text": "Which pathogenic infection, if present, is manifesting on this tomato leaf? -> The diagnosis is Bacterial Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000206.JPG", + "fact_text": "What symptoms might appear if this Strawberry were infected with Leaf scorch? -> A healthy leaf would be uniformly green and free of the evidence of orange or brown pustular structures.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000210.JPG", + "fact_text": "What disease manifestation can be observed on this tomato foliage? -> Diagnosis: Leaf Mold.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_000214.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this orange leaf's health? -> This is citrus greening disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000215.JPG", + "fact_text": "What disease manifestation can be observed on this tomato foliage? -> The diagnosis is Tomato Yellow Leaf Curl Virus (TYLCV).", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000217.JPG", + "fact_text": "Which causative agent is responsible for these disease signs? -> This tomato leaf shows classic signs of TYLCV, like yellowing and curling.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image_000218.JPG", + "fact_text": "Please identify the exact disease name affecting this plant. -> Diagnosis: Huanglongbing (HLB), or citrus greening.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_000222.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The symptoms, especially the olive-green mold on the leaf underside, indicate Leaf Mold.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000222.JPG", + "fact_text": "Can you provide a precise disease identification based on visual evidence? -> Diagnosis: Leaf Mold.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000223.JPG", + "fact_text": "What disease, if any, is visible on this Cherry leaf? -> This is a healthy plant leaf.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000226.JPG", + "fact_text": "What symptoms might appear if this Tomato were infected with Tomato Yellow Leaf Curl Virus? -> A healthy version of this plant would not exhibit the yellow spots paired with olive-green undersurface fungus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000228.JPG", + "fact_text": "Is there a specific disease that can be identified on this orange leaf? -> Diagnosis: Huanglongbing (HLB), or citrus greening.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000229.JPG", + "fact_text": "Identify the agent responsible for these disease signs. -> The diagnosis is Septoria Leaf Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000231.JPG", + "fact_text": "What disease, if any, is visible on this Potato leaf? -> The plant is suffering from a Late Blight infection.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000234.JPG", + "fact_text": "Which factor or pathogen creates these disease indicators? -> The symptoms are characteristic of Leaf scorch.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000235.JPG", + "fact_text": "What disease, if any, is visible on this Soybean leaf? -> No signs of disease are visible; the plant is in good health.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000236.JPG", + "fact_text": "Can you determine what disease is impacting this tomato leaf sample? -> The diagnosis is Tomato Yellow Leaf Curl Virus (TYLCV).", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_000246.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The disease is Target Spot, marked by dark, concentric 'bullseye' lesions.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image_000250.JPG", + "fact_text": "Please identify the exact disease name affecting this plant. -> The cause is the bacterium Candidatus Liberibacter asiaticus, leading to Huanglongbing.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000251.JPG", + "fact_text": "What disease indicators would not appear in a healthy plant specimen? -> A healthy leaf would be uniformly green and free of the evidence of orange or brown pustular structures.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000255.JPG", + "fact_text": "What symptoms might appear if this Tomato were infected with Early blight? -> A healthy version of this plant would not exhibit the round lesions with bull's-eye appearances.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000255.JPG", + "fact_text": "Which pathogenic infection, if present, is manifesting on this tomato leaf? -> This plant appears to be healthy and free of disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000256.JPG", + "fact_text": "Which disease affects this specimen? -> This is Late Blight, caused by the oomycete Phytophthora infestans.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000260.JPG", + "fact_text": "What symptoms might appear if this Strawberry were infected with Leaf scorch? -> The key visual difference would be the absence of evidence of orange or brown pustular structures.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000263.JPG", + "fact_text": "What disease, if any, is visible on this Soybean leaf? -> This is a healthy plant leaf.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000267.JPG", + "fact_text": "What disease determination can be made from this visual data? -> This is a viral infection: TYLCV.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000270.JPG", + "fact_text": "What specific disease symptoms are present on this tomato leaf specimen? -> The diagnosis is Bacterial Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000275.JPG", + "fact_text": "What infectious agent, if any, is causing symptoms on this tomato leaf? -> The diagnosis is Target Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000284.JPG", + "fact_text": "Name the pathogen or factor causing these manifestations. -> This tomato leaf shows classic signs of TYLCV, like yellowing and curling.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_000286.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The condition is identified as Late Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000286.JPG", + "fact_text": "What infectious agent, if any, is causing symptoms on this tomato leaf? -> This is Late Blight, caused by the oomycete Phytophthora infestans.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000290.JPG", + "fact_text": "What infectious agent, if any, is causing symptoms on this tomato leaf? -> The leaf shows symptoms of Early Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000292.JPG", + "fact_text": "What specific disease symptoms are present on this tomato leaf specimen? -> The diagnosis is Tomato Yellow Leaf Curl Virus (TYLCV).", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000298.JPG", + "fact_text": "What specific disease symptoms are present on this orange tree leaf? -> The leaf shows blotchy, asymmetrical yellowing, a classic symptom of HLB.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_000300.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> This is Bacterial Spot. Note the small, dark, water-soaked lesions.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000300.JPG", + "fact_text": "Is there a specific disease that can be identified on this tomato leaf? -> The plant is affected by Bacterial Spot disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000306.JPG", + "fact_text": "Can you determine what disease is impacting this tomato leaf sample? -> No signs of disease are visible; the plant is in good health.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image_000308.JPG", + "fact_text": "What symptoms might appear if this Tomato were infected with Spider mites Two-spotted spider mite? -> The key visual difference would be the absence of evidence of orange or brown pustular structures.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000313.JPG", + "fact_text": "Please provide the exact disease nomenclature for these symptoms. -> Diagnosis: Huanglongbing (HLB), or citrus greening.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000320.JPG", + "fact_text": "What disease manifestation can be observed on this tomato foliage? -> No signs of disease are visible; the plant is in good health.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000323.JPG", + "fact_text": "Can you diagnose any disease affecting this tomato plant tissue? -> The numerous small, angular spots are characteristic of Bacterial Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000328.JPG", + "fact_text": "What produces the disease manifestations in this image? -> The symptoms, especially the olive-green mold on the leaf underside, indicate Leaf Mold.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_000331.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> This is Early Blight, identifiable by the 'target-like' concentric rings in the spots.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000332.JPG", + "fact_text": "Given the observable symptoms, what disease is present? -> This tomato leaf shows classic signs of TYLCV, like yellowing and curling.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000335.JPG", + "fact_text": "What disease manifestation can be observed on this tomato foliage? -> This is a viral infection: TYLCV.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000338.JPG", + "fact_text": "What infectious agent, if any, is causing symptoms on this tomato leaf? -> The large, dark, water-soaked lesions are a key sign of Late Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000340.JPG", + "fact_text": "Give the most detailed disease diagnosis possible. -> The plant is suffering from a fungal infection: Septoria Leaf Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000343.JPG", + "fact_text": "What disease, if any, is visible on this Cherry leaf? -> Powdery mildew", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_000344.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The leaf shows symptoms of Early Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000344.JPG", + "fact_text": "What disease, if any, is visible on this Potato leaf? -> The leaf shows symptoms of Early Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000353.JPG", + "fact_text": "Can you diagnose any disease affecting this tomato plant tissue? -> The symptoms, especially the olive-green mold on the leaf underside, indicate Leaf Mold.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000360.JPG", + "fact_text": "Name the pathogen or factor causing these manifestations. -> The causal agent is the Tomato Yellow Leaf Curl Virus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000361.JPG", + "fact_text": "Name the pathogen or factor causing these manifestations. -> The pest responsible is the Two-spotted spider mite.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000361.JPG", + "fact_text": "Can you diagnose any disease affecting this tomato plant tissue? -> The stippling and fine webbing are clear signs of a Spider Mite infestation.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000369.JPG", + "fact_text": "Given the observable symptoms, what disease is present? -> The specimen is healthy.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000373.JPG", + "fact_text": "What symptoms might appear if this Tomato were infected with Late blight? -> A healthy version of this plant would not exhibit the leaf edge browning and necrosis.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_000375.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The mosaic pattern of light and dark green areas is a classic symptom of ToMV.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_000377.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> Diagnosis: Leaf Mold.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000385.jpg", + "fact_text": "What specific disease symptoms are present on this tomato leaf specimen? -> The condition is identified as Late Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000389.JPG", + "fact_text": "What produces the disease manifestations in this image? -> The symptoms are characteristic of Cercospora leaf spot Gray leaf spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000392.JPG", + "fact_text": "Can you determine what disease is impacting this tomato leaf sample? -> The causal agent is the Tomato Yellow Leaf Curl Virus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000401.JPG", + "fact_text": "What symptoms might appear if this Cherry were infected with Powdery mildew? -> A healthy version of this plant would not exhibit the evidence of orange or brown pustular structures.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000414.JPG", + "fact_text": "Which disease or problem specifically affects this specimen? -> The mosaic pattern of light and dark green areas is a classic symptom of ToMV.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000421.JPG", + "fact_text": "What specific disease symptoms are present on this tomato leaf specimen? -> No signs of disease are visible; the plant is in good health.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000423.JPG", + "fact_text": "What symptoms might appear if this Pepper bell were infected with Bacterial spot? -> A healthy version of this plant would not exhibit the circular spots with target-like patterns.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000424.JPG", + "fact_text": "What specific disease symptoms are present on this tomato leaf specimen? -> The causal agent is the Tomato Yellow Leaf Curl Virus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000427.JPG", + "fact_text": "What disease, if any, is visible on this Pepper bell leaf? -> No signs of disease are visible; the plant is in good health.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000430.JPG", + "fact_text": "What disease, if any, is visible on this Potato leaf? -> This is Early Blight, identifiable by the 'target-like' concentric rings in the spots.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000431.JPG", + "fact_text": "What disease, if any, is visible on this Grape leaf? -> Leaf blight Isariopsis Leaf Spot", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000434.JPG", + "fact_text": "Please provide the exact disease nomenclature for these symptoms. -> The diagnosis is Septoria Leaf Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000436.JPG", + "fact_text": "Please provide the exact disease nomenclature for these symptoms. -> This tomato leaf shows classic signs of TYLCV, like yellowing and curling.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000441.JPG", + "fact_text": "What symptoms might appear if this Tomato were infected with Early blight? -> The key visual difference would be the absence of round lesions with bull's-eye appearances.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000441.JPG", + "fact_text": "What specific disease symptoms are present on this tomato leaf specimen? -> This plant appears to be healthy and free of disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000443.JPG", + "fact_text": "Can you diagnose any disease affecting this orange plant tissue? -> The leaf shows blotchy, asymmetrical yellowing, a classic symptom of HLB.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000447.JPG", + "fact_text": "Please state the formal disease designation for this leaf. -> This is a healthy plant leaf.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000448.JPG", + "fact_text": "What disease, if any, is visible on this Cherry leaf? -> The specimen is healthy.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000448.JPG", + "fact_text": "What symptoms might appear if this Cherry were infected with Powdery mildew? -> The key visual difference would be the absence of evidence of orange or brown pustular structures.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000450.JPG", + "fact_text": "What disease, if any, is visible on this Potato leaf? -> This is Late Blight, caused by the oomycete Phytophthora infestans.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000454.JPG", + "fact_text": "Which factor is the source of these disease manifestations? -> The diagnosis is Tomato Yellow Leaf Curl Virus (TYLCV).", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000458.JPG", + "fact_text": "What infectious agent, if any, is causing symptoms on this tomato leaf? -> The disease is Target Spot, marked by dark, concentric 'bullseye' lesions.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000459.JPG", + "fact_text": "What is the specific disease designation for this case? -> This plant appears to be healthy and free of disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000463.JPG", + "fact_text": "What disease manifestation can be observed on this tomato foliage? -> The condition is identified as Late Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000468.JPG", + "fact_text": "What produces the disease manifestations in this image? -> The numerous small, angular spots are characteristic of Bacterial Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000473.JPG", + "fact_text": "Which pathogenic infection, if present, is manifesting on this tomato leaf? -> The mosaic pattern of light and dark green areas is a classic symptom of ToMV.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000476.JPG", + "fact_text": "What disease manifestation can be observed on this tomato foliage? -> The plant is suffering from a Late Blight infection.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000478.JPG", + "fact_text": "Is precise disease identification possible from these visual symptoms? -> The causal agent is the Tomato Yellow Leaf Curl Virus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000483.JPG", + "fact_text": "What disease, if any, is visible on this Strawberry leaf? -> This is a healthy plant leaf.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "species identification", + "entity": "image_000487.JPG", + "fact_text": "Please identify the exact disease name affecting this plant. -> These 'bullseye' lesions are a tell-tale sign of Early Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "disease identification", + "entity": "image_000496.JPG", + "fact_text": "What disease determination can be made from this visual data? -> The pest responsible is the Two-spotted spider mite.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "symptom/visual description", + "entity": "image_000497.JPG", + "fact_text": "What infectious agent, if any, is causing symptoms on this tomato leaf? -> This is a viral infection: TYLCV.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000499.JPG", + "fact_text": "What is the specific disease designation for this case? -> The stippling and fine webbing are clear signs of a Spider Mite infestation.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000506.JPG", + "fact_text": "Provide the most precise disease identification you can. -> The cause is the bacterium Candidatus Liberibacter asiaticus, leading to Huanglongbing.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000507.JPG", + "fact_text": "Which causative agent is responsible for these disease signs? -> The cause is the bacterium Candidatus Liberibacter asiaticus, leading to Huanglongbing.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "disease advice", + "knowledge_type": "management instructions", + "entity": "image_000514.JPG", + "fact_text": "Is there a specific disease that can be identified on this tomato leaf? -> The plant shows no symptoms of pathology.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_000521.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The causal agent is the Tomato Yellow Leaf Curl Virus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_000590.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The diagnosis is Bacterial Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_000597.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The leaf shows symptoms of Early Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_000617.jpg", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> The plant is suffering from a Late Blight infection.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_000732.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The diagnosis is Target Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_000807.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The stippling and fine webbing are clear signs of a Spider Mite infestation.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_000992.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The diagnosis is Bacterial Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_001167.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The plant is affected by Bacterial Spot disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_001189.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The diagnosis is Target Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_001271.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The causal agent is the Tomato Yellow Leaf Curl Virus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_001320.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> This is a viral infection: TYLCV.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_001399.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this orange leaf's health? -> The leaf shows blotchy, asymmetrical yellowing, a classic symptom of HLB.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_001440.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The numerous small, angular spots are characteristic of Bacterial Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_001443.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The pest responsible is the Two-spotted spider mite.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_001603.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this orange leaf's health? -> Diagnosis: Huanglongbing (HLB), or citrus greening.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_001682.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> This is Septoria Leaf Spot, characterized by small, circular spots with dark borders.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_001760.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The large, dark, water-soaked lesions are a key sign of Late Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_001796.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The plant is suffering from a Late Blight infection.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_001812.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> The leaf shows blotchy, asymmetrical yellowing, a classic symptom of HLB.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_001854.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> Diagnosis: Huanglongbing (HLB), or citrus greening.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_001954.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The stippling and fine webbing are clear signs of a Spider Mite infestation.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_002152.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The diagnosis is Tomato Yellow Leaf Curl Virus (TYLCV).", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_002203.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> This is damage from Spider Mites.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_002223.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> The disease is Target Spot, marked by dark, concentric 'bullseye' lesions.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_002524.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> This is citrus greening disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_002576.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> This is a fungal disease known as Leaf Mold.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_002614.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> This is Tomato Mosaic Virus (ToMV).", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_002670.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The diagnosis is Septoria Leaf Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_002675.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> This is citrus greening disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_002761.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> This is Bacterial Spot. Note the small, dark, water-soaked lesions.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_002833.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> The cause is the bacterium Candidatus Liberibacter asiaticus, leading to Huanglongbing.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_002940.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> This is Late Blight, caused by the oomycete Phytophthora infestans.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_002980.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The large, dark, water-soaked lesions are a key sign of Late Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_003050.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> This is Late Blight, caused by the oomycete Phytophthora infestans.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_003092.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> This is citrus greening disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_003125.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> The diagnosis is Target Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_003316.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> This is a viral infection: TYLCV.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_003338.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> Diagnosis: Huanglongbing (HLB), or citrus greening.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_003492.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The fungus Alternaria solani, which causes Early Blight, is responsible.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_003525.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The pest responsible is the Two-spotted spider mite.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_003676.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The disease is Target Spot, marked by dark, concentric 'bullseye' lesions.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_003731.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> These 'bullseye' lesions are a tell-tale sign of Early Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_004011.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> This is Bacterial Spot. Note the small, dark, water-soaked lesions.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_004091.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> This is damage from Spider Mites.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_004151.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The plant is infected with Target Spot fungus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_004163.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The causal agent is the Tomato Yellow Leaf Curl Virus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_004170.jpg", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The condition is identified as Late Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_004213.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> This is Late Blight, caused by the oomycete Phytophthora infestans.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_004214.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> This is damage from Spider Mites.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_004283.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The diagnosis is Septoria Leaf Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_004429.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> Diagnosis: Leaf Mold.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_004469.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The plant is suffering from a fungal infection: Septoria Leaf Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_004536.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> This is Early Blight, identifiable by the 'target-like' concentric rings in the spots.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_004665.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> This tomato leaf shows classic signs of TYLCV, like yellowing and curling.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_004780.jpg", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The plant is suffering from a Late Blight infection.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_004786.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The plant is infected with Target Spot fungus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_005043.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The symptoms are characteristic of Common rust.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_005402.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The plant is infected with Tomato Mosaic Virus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_005461.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The symptoms are characteristic of Powdery mildew.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_005521.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The symptoms are characteristic of Common rust.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_005555.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> This tomato leaf shows classic signs of TYLCV, like yellowing and curling.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_005616.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> These 'bullseye' lesions are a tell-tale sign of Early Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_005725.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The leaf shows blotchy, asymmetrical yellowing, a classic symptom of HLB.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_005827.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The symptoms are characteristic of Cedar apple rust.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_005991.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> The leaf shows symptoms of Early Blight.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_006151.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> The numerous small, angular spots are characteristic of Bacterial Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image_006158.JPG", + "fact_text": "What symptoms might appear if this Tomato were infected with Spider mites Two-spotted spider mite? -> If the plant were healthy, the evidence of orange or brown pustular structures would be absent.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_006417.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> This is damage from Spider Mites.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_006796.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The disease is Target Spot, marked by dark, concentric 'bullseye' lesions.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "pests control", + "knowledge_type": "symptom/visual description", + "entity": "image_006936.JPG", + "fact_text": "What symptoms might appear if this Tomato were infected with Spider mites Two-spotted spider mite? -> A healthy version of this plant would not exhibit the evidence of orange or brown pustular structures.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_007016.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> The plant is suffering from a fungal infection: Septoria Leaf Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_007043.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The pest responsible is the Two-spotted spider mite.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_007080.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> The stippling and fine webbing are clear signs of a Spider Mite infestation.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_007401.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The diagnosis is Bacterial Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_007517.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The fungus Alternaria solani, which causes Early Blight, is responsible.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_007534.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> The diagnosis is Tomato Yellow Leaf Curl Virus (TYLCV).", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_007573.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> The diagnosis is Septoria Leaf Spot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_007785.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The diagnosis is Tomato Yellow Leaf Curl Virus (TYLCV).", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_007865.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The symptoms are characteristic of Black rot.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "management instructions", + "entity": "image_007931.JPG", + "fact_text": "What pathogenic or environmental factors are affecting this tomato leaf's health? -> The plant is infected with Tomato Mosaic Virus.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_008565.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The symptoms are characteristic of Leaf scorch.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_008667.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> The plant is affected by Bacterial Spot disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_009758.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The plant is affected by Bacterial Spot disease.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_010177.JPG", + "fact_text": "What pathogen or environmental factor produces these symptoms? -> This is Septoria Leaf Spot, characterized by small, circular spots with dark borders.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_010290.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> This tomato leaf shows classic signs of TYLCV, like yellowing and curling.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_010291.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> This is a viral infection: TYLCV.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_010362.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> The cause is the bacterium Candidatus Liberibacter asiaticus, leading to Huanglongbing.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_010751.JPG", + "fact_text": "What pathogenic or environmental agent creates these symptoms? -> This is Septoria Leaf Spot, characterized by small, circular spots with dark borders.", + "source": "PlantVillageVQA" + }, + { + "subdomain": "environmental stress", + "knowledge_type": "symptom/visual description", + "entity": "image_011537.JPG", + "fact_text": "What pathogenic or environmental agent causes these symptoms? -> The mosaic pattern of light and dark green areas is a classic symptom of ToMV.", + "source": "PlantVillageVQA" + } +] \ No newline at end of file diff --git a/backend/eslint.config.js b/backend/eslint.config.js new file mode 100644 index 0000000000000000000000000000000000000000..2e8311f63b1e960c5cc8e39cc6e4348d2e2a934e --- /dev/null +++ b/backend/eslint.config.js @@ -0,0 +1,30 @@ +import js from "@eslint/js"; +import globals from "globals"; + +export default [ + js.configs.recommended, + { + languageOptions: { + ecmaVersion: "latest", + sourceType: "module", + globals: { + ...globals.node, + ...globals.jest, + }, + }, + rules: { + "no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + }, + ], + "no-console": "off", + }, + }, + { + ignores: ["node_modules/**", "coverage/**"], + }, +]; diff --git a/backend/middleware/authMiddleware.js b/backend/middleware/authMiddleware.js new file mode 100644 index 0000000000000000000000000000000000000000..cb71bfd6da139eb279d5872df57062de9755562b --- /dev/null +++ b/backend/middleware/authMiddleware.js @@ -0,0 +1,22 @@ +import { optionalFirebaseAuth, verifyFirebaseToken } from "./firebaseAuth.js"; + +export const verifyToken = verifyFirebaseToken; +export const optionalAuth = optionalFirebaseAuth; + +export const requireRole = (...roles) => (req, res, next) => { + if (!req.user) { + return res.status(401).json({ success: false, message: "Authentication required." }); + } + if (roles.length > 0 && !roles.includes(req.userRole)) { + return res.status(403).json({ + success: false, + message: `Access denied. Required roles: ${roles.join(", ")}`, + }); + } + return next(); +}; + +export const requireExpert = requireRole("expert", "admin"); +export const requireFarmer = requireRole("farmer", "admin"); + +export default { verifyToken, optionalAuth, requireRole, requireExpert, requireFarmer }; diff --git a/backend/middleware/firebaseAuth.js b/backend/middleware/firebaseAuth.js new file mode 100644 index 0000000000000000000000000000000000000000..e8749a92c30c2d44e6b1f137f7c0e3c3d880e9c7 --- /dev/null +++ b/backend/middleware/firebaseAuth.js @@ -0,0 +1,77 @@ +import { lookupFirebaseIdToken, withFirebaseToken } from "../utils/firebaseRest.js"; + +const extractBearerToken = (req) => { + const authHeader = req.headers.authorization; + if (authHeader?.startsWith("Bearer ")) return authHeader.substring(7).trim(); + return req.cookies?.firebaseToken || null; +}; + +const attachFirebaseUser = (req, identity) => { + const uid = identity.uid; + const role = identity.role || "farmer"; + const name = identity.name || identity.email?.split("@")[0] || "User"; + req.firebaseUser = { + uid, + localId: uid, + email: identity.email || null, + name, + displayName: name, + picture: identity.picture || null, + email_verified: Boolean(identity.emailVerified), + emailVerified: Boolean(identity.emailVerified), + lastLoginAt: identity.lastLoginAt || null, + createdAt: identity.createdAt || null, + }; + req.userId = uid; + req.userEmail = identity.email || null; + req.userRole = role; + req.user = { + id: uid, + _id: uid, + uid, + firebaseUid: uid, + email: identity.email || null, + name, + role, + img: identity.picture || null, + }; +}; + +const authenticationError = (error) => { + const message = String(error?.message || ""); + if (/expired|INVALID_ID_TOKEN|TOKEN_EXPIRED/i.test(message)) return "Token expired. Please login again."; + if (/invalid|malformed|missing|no user|401|403/i.test(message)) return "Invalid token."; + return "Authentication failed."; +}; + +export const verifyFirebaseToken = async (req, res, next) => { + const token = extractBearerToken(req); + if (!token) { + return res.status(401).json({ success: false, message: "Access denied. No Firebase token provided." }); + } + + try { + const identity = await lookupFirebaseIdToken(token); + attachFirebaseUser(req, identity); + return withFirebaseToken(token, next); + } catch (error) { + console.error("Firebase Identity Toolkit verification error:", error.message); + return res.status(401).json({ success: false, message: authenticationError(error) }); + } +}; + +export const optionalFirebaseAuth = async (req, res, next) => { + const token = extractBearerToken(req); + if (!token) return next(); + + try { + const identity = await lookupFirebaseIdToken(token); + attachFirebaseUser(req, identity); + return withFirebaseToken(token, next); + } catch { + return next(); + } +}; + +export { extractBearerToken, attachFirebaseUser }; +export default { verifyFirebaseToken, optionalFirebaseAuth }; diff --git a/backend/middleware/jwt.js b/backend/middleware/jwt.js new file mode 100644 index 0000000000000000000000000000000000000000..64be3cd377f63f8ba2a243b74e51a0309ac6494d --- /dev/null +++ b/backend/middleware/jwt.js @@ -0,0 +1,6 @@ +// Compatibility module: all protected routes now verify Firebase ID tokens. +export { + verifyFirebaseToken as verifyToken, + optionalFirebaseAuth as optionalAuth, +} from "./firebaseAuth.js"; +export { requireRole } from "./authMiddleware.js"; diff --git a/backend/middleware/languageMiddleware.js b/backend/middleware/languageMiddleware.js new file mode 100644 index 0000000000000000000000000000000000000000..8a7beee94bfdc3cf5368a1294c12656c0a2f0d76 --- /dev/null +++ b/backend/middleware/languageMiddleware.js @@ -0,0 +1,15 @@ +/** + * Language middleware + * Extracts and attaches language preference to every request. + * Priority: query ?lang= > body.lang/body.language > Accept-Language header > 'en' + */ + +import { extractLanguage, getLanguageName } from '../utils/aiOrchestrator.js'; + +export function languageMiddleware(req, _res, next) { + req.lang = extractLanguage(req); + req.langName = getLanguageName(req.lang); + next(); +} + +export default languageMiddleware; diff --git a/backend/middleware/multerMiddleware.js b/backend/middleware/multerMiddleware.js new file mode 100644 index 0000000000000000000000000000000000000000..f1fb94e65a4519557961945d99d74bfd494a235e --- /dev/null +++ b/backend/middleware/multerMiddleware.js @@ -0,0 +1,49 @@ +import multer from "multer"; +import fs from "fs"; + +// Define the upload directory +const uploadDir = "./public/temp"; + +// Create the directory if it doesn't exist +if (!fs.existsSync(uploadDir)) { + fs.mkdirSync(uploadDir, { recursive: true }); +} + +// Configure multer storage +const storage = multer.diskStorage({ + destination: (req, file, cb) => { + cb(null, uploadDir); // Store uploaded files in "public/temp" + }, + filename: (req, file, cb) => { + cb(null, `${Date.now()}-${file.originalname}`); + }, +}); + +//Configure memory storage +const storageMemory = multer.memoryStorage(); + +// File filter to accept only image files, matching the frontend's accept="image/*" +// inputs. Checks the MIME type reported by the browser (not a magic-byte sniff -- +// good enough to reject obviously wrong uploads without false-rejecting legitimate +// phone-camera formats like webp/heic-converted-jpeg). +const imageFileFilter = (req, file, cb) => { + if (file.mimetype && file.mimetype.startsWith("image/")) { + cb(null, true); + } else { + cb(new Error("Only image files are allowed")); + } +}; + +export const uploadImage = multer({ + storage, + fileFilter: imageFileFilter, + limits: { fileSize: 10 * 1024 * 1024 }, +}); + +export const uploadImageMemory = multer({ + storage: storageMemory, + fileFilter: imageFileFilter, + limits: { fileSize: 10 * 1024 * 1024 }, +}); + +export const upload = multer({ storage, limits: { fileSize: 10 * 1024 * 1024 } }); diff --git a/backend/middleware/rateLimiter.js b/backend/middleware/rateLimiter.js new file mode 100644 index 0000000000000000000000000000000000000000..efebc63bcd9102f2d5578d3a3d039b671c50bfc6 --- /dev/null +++ b/backend/middleware/rateLimiter.js @@ -0,0 +1,106 @@ +/** + * Rate Limiting Middleware + * Provides configurable rate limiting for API routes + */ + +// Simple in-memory rate limiter +// For production, use Redis-based rate limiting +const rateLimitStore = new Map(); + +/** + * Clean expired entries periodically + */ +setInterval(() => { + const now = Date.now(); + for (const [key, data] of rateLimitStore.entries()) { + if (data.resetTime < now) { + rateLimitStore.delete(key); + } + } +}, 60000); // Clean every minute + +/** + * Create a rate limiter middleware + * @param {Object} options Rate limiting options + * @param {number} options.windowMs - Time window in milliseconds + * @param {number} options.max - Maximum requests per window + * @param {string} options.message - Error message when rate limited + * @returns {Function} Express middleware + */ +export const createRateLimiter = (options = {}) => { + const { + windowMs = 60000, // 1 minute + max = 100, // 100 requests per minute + message = 'Too many requests, please try again later.', + keyGenerator = (req) => req.ip || req.connection.remoteAddress || 'unknown', + } = options; + + return (req, res, next) => { + const key = keyGenerator(req); + const now = Date.now(); + + let record = rateLimitStore.get(key); + + if (!record || record.resetTime < now) { + // Reset the window + record = { + count: 1, + resetTime: now + windowMs, + }; + rateLimitStore.set(key, record); + + // Set rate limit headers + res.set('X-RateLimit-Limit', max); + res.set('X-RateLimit-Remaining', max - 1); + res.set('X-RateLimit-Reset', Math.ceil(record.resetTime / 1000)); + + return next(); + } + + record.count++; + rateLimitStore.set(key, record); + + // Set rate limit headers + res.set('X-RateLimit-Limit', max); + res.set('X-RateLimit-Remaining', Math.max(0, max - record.count)); + res.set('X-RateLimit-Reset', Math.ceil(record.resetTime / 1000)); + + if (record.count > max) { + res.set('Retry-After', Math.ceil((record.resetTime - now) / 1000)); + return res.status(429).json({ + success: false, + message, + retryAfter: Math.ceil((record.resetTime - now) / 1000), + }); + } + + next(); + }; +}; + +// Pre-configured rate limiters +export const apiLimiter = createRateLimiter({ + windowMs: 60000, // 1 minute + max: 100, // 100 requests per minute + message: 'Too many API requests, please try again later.', +}); + +export const authLimiter = createRateLimiter({ + windowMs: 900000, // 15 minutes + max: 10, // 10 attempts per 15 minutes + message: 'Too many authentication attempts, please try again later.', +}); + +export const uploadLimiter = createRateLimiter({ + windowMs: 3600000, // 1 hour + max: 50, // 50 uploads per hour + message: 'Upload limit exceeded, please try again later.', +}); + +export const heavyLimiter = createRateLimiter({ + windowMs: 60000, // 1 minute + max: 10, // 10 requests per minute for heavy endpoints + message: 'This endpoint is rate limited, please try again later.', +}); + +export default { createRateLimiter, apiLimiter, authLimiter, uploadLimiter, heavyLimiter }; diff --git a/backend/middleware/securityMiddleware.js b/backend/middleware/securityMiddleware.js new file mode 100644 index 0000000000000000000000000000000000000000..4e57f9c9a488bf84b30f46f5eab2fbab59f5ab5b --- /dev/null +++ b/backend/middleware/securityMiddleware.js @@ -0,0 +1,56 @@ +/** + * Security headers middleware + * Adds security-related HTTP headers to all responses. + */ + +export function securityHeaders(req, res, next) { + // Prevent MIME type sniffing + res.setHeader('X-Content-Type-Options', 'nosniff'); + // Do not set X-Frame-Options to DENY because Hugging Face Spaces + // renders the app inside an iframe. + // XSS protection + res.setHeader('X-XSS-Protection', '1; mode=block'); + // Referrer policy + res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin'); + // Content Security Policy (basic) + res.setHeader( + 'Content-Security-Policy', + "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self' https://huggingface.co https://*.hf.space;" + ); + // Surface request latency via Server-Timing to aid production diagnostics. + // Wrap res.end so the elapsed time is known before headers are flushed. + const startMs = Date.now(); + const originalEnd = res.end.bind(res); + res.end = function (chunk, encoding, callback) { + if (!res.headersSent) { + res.setHeader('Server-Timing', `total;dur=${Date.now() - startMs}`); + } + return originalEnd(chunk, encoding, callback); + }; + // Remove server identification + res.removeHeader('X-Powered-By'); + + next(); +} + +/** + * Global error handler that sanitizes error output in production + */ +export function errorHandler(err, _req, res, _next) { + const statusCode = err.statusCode || err.status || 500; + + // Never expose stack traces in production + const isProduction = process.env.NODE_ENV === 'production'; + + if (statusCode >= 500) { + console.error('Server error:', err.message, isProduction ? '' : err.stack); + } + + res.status(statusCode).json({ + success: false, + message: isProduction ? 'An internal error occurred' : err.message, + ...(isProduction ? {} : { stack: err.stack }), + }); +} + +export default { securityHeaders, errorHandler }; diff --git a/backend/models/appointmentModel.js b/backend/models/appointmentModel.js new file mode 100644 index 0000000000000000000000000000000000000000..9765439a534ad6d227a0960a79eaef0faf306d9a --- /dev/null +++ b/backend/models/appointmentModel.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const Appointment = createFirestoreModel("appointments"); +export default Appointment; diff --git a/backend/models/auth.model.js b/backend/models/auth.model.js new file mode 100644 index 0000000000000000000000000000000000000000..edd55e1e5e4022e225ecaee59a570278234bfbc1 --- /dev/null +++ b/backend/models/auth.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const User = createFirestoreModel("users"); +export default User; diff --git a/backend/models/crop.model.js b/backend/models/crop.model.js new file mode 100644 index 0000000000000000000000000000000000000000..b2573b2921470a52bad578ac35613311bb0a93f1 --- /dev/null +++ b/backend/models/crop.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const Crop = createFirestoreModel("crops"); +export default Crop; diff --git a/backend/models/expertDetail.model.js b/backend/models/expertDetail.model.js new file mode 100644 index 0000000000000000000000000000000000000000..b68672de4a71126f7d664054d9e1c29a485c8a20 --- /dev/null +++ b/backend/models/expertDetail.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const ExpertDetails = createFirestoreModel("expertDetails"); +export default ExpertDetails; diff --git a/backend/models/exportOpportunity.model.js b/backend/models/exportOpportunity.model.js new file mode 100644 index 0000000000000000000000000000000000000000..81de8b9384a231f616cf6472c2809638a982a475 --- /dev/null +++ b/backend/models/exportOpportunity.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const ExportOpportunity = createFirestoreModel("exportOpportunities"); +export default ExportOpportunity; diff --git a/backend/models/farmerDetail.model.js b/backend/models/farmerDetail.model.js new file mode 100644 index 0000000000000000000000000000000000000000..816513b4b32f3ef67c1a6a0b2e97d321d2d35e9c --- /dev/null +++ b/backend/models/farmerDetail.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const FarmerDetails = createFirestoreModel("farmerDetails"); +export default FarmerDetails; diff --git a/backend/models/irrigation.model.js b/backend/models/irrigation.model.js new file mode 100644 index 0000000000000000000000000000000000000000..5b65a78528428b270e042a220d80861673eb36fa --- /dev/null +++ b/backend/models/irrigation.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const Irrigation = createFirestoreModel("irrigation"); +export default Irrigation; diff --git a/backend/models/listing.model.js b/backend/models/listing.model.js new file mode 100644 index 0000000000000000000000000000000000000000..bb3eab932022b539842d0eb748623aaff90398b8 --- /dev/null +++ b/backend/models/listing.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const Listing = createFirestoreModel("listings"); +export default Listing; diff --git a/backend/models/monthlySummary.model.js b/backend/models/monthlySummary.model.js new file mode 100644 index 0000000000000000000000000000000000000000..d3f836423e126e85cc5ff6a718fdde7e37b72e7f --- /dev/null +++ b/backend/models/monthlySummary.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const MonthlySummary = createFirestoreModel("monthlySummaries"); +export default MonthlySummary; diff --git a/backend/models/offer.model.js b/backend/models/offer.model.js new file mode 100644 index 0000000000000000000000000000000000000000..399e7edf4784c04ff52c3e70283e26a0abac9e40 --- /dev/null +++ b/backend/models/offer.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const Offer = createFirestoreModel("offers"); +export default Offer; diff --git a/backend/models/post.model.js b/backend/models/post.model.js new file mode 100644 index 0000000000000000000000000000000000000000..6e8e00dd7405e1e2691e4111f67fbceb90e61562 --- /dev/null +++ b/backend/models/post.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const Post = createFirestoreModel("posts"); +export default Post; diff --git a/backend/models/priceHistory.model.js b/backend/models/priceHistory.model.js new file mode 100644 index 0000000000000000000000000000000000000000..0bb50b6d0b9c2ca12802fd538d829227f8a47854 --- /dev/null +++ b/backend/models/priceHistory.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const PriceHistory = createFirestoreModel("priceHistory"); +export default PriceHistory; diff --git a/backend/models/processor.model.js b/backend/models/processor.model.js new file mode 100644 index 0000000000000000000000000000000000000000..0bd914ee31bd5239a79c5964e7a4d95270d7d5b3 --- /dev/null +++ b/backend/models/processor.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const Processor = createFirestoreModel("processors"); +export default Processor; diff --git a/backend/models/record.model.js b/backend/models/record.model.js new file mode 100644 index 0000000000000000000000000000000000000000..77012067b492150ebfa2f136ae2aac3eab19e465 --- /dev/null +++ b/backend/models/record.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const Record = createFirestoreModel("records"); +export default Record; diff --git a/backend/models/task.model.js b/backend/models/task.model.js new file mode 100644 index 0000000000000000000000000000000000000000..67ee5a27162fce5dfa42d24a24a129a423a5cf11 --- /dev/null +++ b/backend/models/task.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const Task = createFirestoreModel("tasks"); +export default Task; diff --git a/backend/models/transformRequest.model.js b/backend/models/transformRequest.model.js new file mode 100644 index 0000000000000000000000000000000000000000..bd75a427e9b3c5cfb8fcf5e6f40a9963908b7941 --- /dev/null +++ b/backend/models/transformRequest.model.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const TransformRequest = createFirestoreModel("transformRequests"); +export default TransformRequest; diff --git a/backend/models/userModel.js b/backend/models/userModel.js new file mode 100644 index 0000000000000000000000000000000000000000..edd55e1e5e4022e225ecaee59a570278234bfbc1 --- /dev/null +++ b/backend/models/userModel.js @@ -0,0 +1,5 @@ +/** Firestore-backed replacement for the former Mongoose model. */ +import { createFirestoreModel } from "../utils/firestoreModel.js"; + +const User = createFirestoreModel("users"); +export default User; diff --git a/backend/package-lock.json b/backend/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..aa11edef25a0e21269cafbbfe8f2c3d82fe65326 --- /dev/null +++ b/backend/package-lock.json @@ -0,0 +1,6089 @@ +{ + "name": "backend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "backend", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "axios": "^1.19.0", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "express": "^4.22.2", + "form-data": "^4.0.6", + "morgan": "^1.11.0", + "multer": "^1.4.5-lts.1", + "socket": "^0.14.15", + "socket.io": "^4.8.1", + "ws": "^8.21.3" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "eslint": "^10.0.1", + "globals": "^17.9.0", + "jest": "^29.7.0", + "nodemon": "^3.1.11", + "supertest": "^6.3.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", + "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", + "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.12", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.12.tgz", + "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz", + "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz", + "integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.6", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.13", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.13.tgz", + "integrity": "sha512-k9HNuUVMlqVjQ9UHzfPjIqiDbWw7WqT1AoT7GL8VwvF3r0ZfArtgiSPAlmupyNquNgOJHTuH4CKYf8ttMTWBTQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz", + "integrity": "sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.12", + "caniuse-lite": "^1.0.30001809", + "electron-to-chromium": "^1.5.402", + "node-releases": "^2.0.53", + "update-browserslist-db": "^1.3.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001809", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz", + "integrity": "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.403", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.403.tgz", + "integrity": "sha512-MQsYmdaLzvaCX5j+ZZBr5Fm6uCCnPQcRtlvmvRlWqrXy+BH2O4ffXIAScF+JQznQWB9brWp4lSD9Z4yNmaf2BA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.6.9", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.9.tgz", + "integrity": "sha512-clKkw4C7nJ22mGgoVcCg6V/W/TxdNyIOTr89k2ONZu81qqkddPFDF0LXcbAwhzPD8DjkiRCjzuiO6Y+fkpD4vg==", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "@types/ws": "^8.5.12", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.21.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.8.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.8.1.tgz", + "integrity": "sha512-wqA7W2jbsC/BnV9Iv1UZpKVFkO1AdNoSmYW8NWG4HNOBbkAMvIqDZ27pI2f07dqn583NcIC44ckjAcOXDL1QbQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.7.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.2", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.15.1", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formidable": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.5.tgz", + "integrity": "sha512-Oz5Hwvwak/DCaXVVUtPn4oLMLLy1CdclLKO1LFgU7XzDpVMUU5UjlSLpGMocyQNNk8F6IJW9M/YdooSn2MRI+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", + "dezalgo": "^1.0.4", + "once": "^1.4.0", + "qs": "^6.11.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "17.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.9.0.tgz", + "integrity": "sha512-m/MvAW61QVU5VDNF1Vj8axt016h8w7L5TU1e9zlab7XIttAT2YAlCwl75K1fOqvMM9apmD7lbCIRhpfkhmxhCg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz", + "integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/morgan": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.11.0.tgz", + "integrity": "sha512-zSkVu3t18r39pw4ixfBKvfZi3y2UOqr7d4WYwcj3m8nXpEQK4rPO6GLzs/CExoRgmX3y9EjmmcXqv6jq0SK46g==", + "license": "MIT", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.4.1", + "on-headers": "~1.1.0" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/morgan/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/morgan/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multer": { + "version": "1.4.5-lts.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz", + "integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==", + "deprecated": "Multer 1.x is impacted by a number of vulnerabilities, which have been patched in 2.x. You should upgrade to the latest 2.x version.", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.53", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz", + "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/socket": { + "version": "0.14.155", + "resolved": "https://registry.npmjs.org/socket/-/socket-0.14.155.tgz", + "integrity": "sha512-nIXKRMjknrqKbW8DVUeUwJTWbLnK+VwO2XpzmztXntF9BGkvRRs7JOjiZpXMUd5rPg1uHODc9HpkNhrfHGHLuw==", + "license": "MIT", + "bin": { + "socket": "bin/cli.js", + "socket-npm": "bin/npm-cli.js", + "socket-npx": "bin/npx-cli.js" + }, + "engines": { + "node": "18.20.7 || ^20.18.3 || >=22.14.0" + } + }, + "node_modules/socket.io": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz", + "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.4.1", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.8.tgz", + "integrity": "sha512-6Oy52pbg+kvdCVvjcN+FnY7BvxZ7cIHNScbvztT/It5d0vbwoJoVZmF2gjJmnV0/4WlXRfG15zc45ySk9Ah8bw==", + "license": "MIT", + "dependencies": { + "debug": "~4.4.1", + "ws": "~8.21.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.7.tgz", + "integrity": "sha512-IH/iSeO9T6gz1KkFleGDWkG9N3dl4jXVYUtMhIqH10Md0ttMer8nUNWiP1DKuNrybD2xBrixLJdCC9J6ECoYkg==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superagent": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", + "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", + "deprecated": "Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/supertest": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.4.tgz", + "integrity": "sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==", + "deprecated": "Please upgrade to supertest v7.1.3+, see release notes at https://github.com/forwardemail/supertest/releases/tag/v7.1.3 - maintenance is supported by Forward Email @ https://forwardemail.net", + "dev": true, + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^8.1.2" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.0.tgz", + "integrity": "sha512-x/M6q3w4Ybp91CNaS4S69UnliqR3BzRpOT6LWbksjth0S/+jhfaPJsWjt/TewpT8j9eLIojUf5jr29WextHroA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/backend/package.json b/backend/package.json new file mode 100644 index 0000000000000000000000000000000000000000..6a41e8344f454a195cfbe0e8c78dce31115886c4 --- /dev/null +++ b/backend/package.json @@ -0,0 +1,64 @@ +{ + "name": "backend", + "version": "1.0.0", + "main": "server.js", + "scripts": { + "dev": "nodemon server.js", + "start": "node server.js", + "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --passWithNoTests --forceExit --setupFilesAfterEnv=./tests/setup.js", + "test:watch": "npm test -- --watch", + "test:coverage": "npm test -- --coverage", + "lint": "eslint .", + "lint:fix": "eslint . --fix" + }, + "keywords": [], + "type": "module", + "author": "", + "license": "ISC", + "description": "AgroMind Backend API", + "dependencies": { + "axios": "^1.19.0", + "cookie-parser": "^1.4.7", + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "express": "^4.22.2", + "form-data": "^4.0.6", + "morgan": "^1.11.0", + "multer": "^1.4.5-lts.1", + "socket": "^0.14.15", + "socket.io": "^4.8.1", + "ws": "^8.21.3" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "eslint": "^10.0.1", + "globals": "^17.9.0", + "jest": "^29.7.0", + "nodemon": "^3.1.11", + "supertest": "^6.3.4" + }, + "overrides": { + "ws": "^8.21.3", + "form-data": "^4.0.6", + "websocket-driver": "^0.7.5", + "yauzl": "^3.4.0", + "path-to-regexp": "^0.1.13", + "flatted": "^3.4.4", + "engine.io": "^6.6.9", + "socket.io-parser": "^4.2.7", + "tar": "^7.5.22", + "uuid": "^11.1.1", + "gaxios": "^7.3.0", + "retry-request": "^9.0.0", + "teeny-request": "^11.0.0", + "minimatch": "^10.2.6", + "fast-xml-parser": "^5.10.1" + }, + "jest": { + "testEnvironment": "node", + "testMatch": [ + "**/tests/**/*.test.js" + ], + "transform": {} + } +} diff --git a/backend/routes/aiModelRoutes.js b/backend/routes/aiModelRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..6e639d3b203c42ddca522cbd5072071684dc0dc1 --- /dev/null +++ b/backend/routes/aiModelRoutes.js @@ -0,0 +1,269 @@ +import express from "express"; +import multer from "multer"; +import { generateAIContent } from "../utils/aiHelper.js"; +import { LANGUAGE_MAP } from "../utils/aiOrchestrator.js"; +import mlRoutes from "./mlRoutes.js"; + +const router = express.Router(); +const upload = multer({ storage: multer.memoryStorage() }); + +const normalizeUrl = (value) => value?.trim().replace(/\/$/, ""); + +// Timeout for ML model requests β€” models may need to download from HF Hub on first call +const ML_MODEL_TIMEOUT_MS = 120_000; + +const buildFallbackAiBackendUrl = () => { + const spaceHost = process.env.SPACE_HOST; + + if (!spaceHost?.trim()) { + return null; + } + + const inferredHost = spaceHost + .trim() + .replace(/-backend(\.hf\.space)$/i, "-ai-backend$1"); + + if (inferredHost === spaceHost.trim()) { + return null; + } + + return `https://${inferredHost}`; +}; + +const getAiBackendCandidates = () => { + const configured = normalizeUrl(process.env.AI_BACKEND_URL); + const fallback = normalizeUrl(buildFallbackAiBackendUrl()); + const local = "http://localhost:5000"; + + return [...new Set([configured, fallback, local].filter(Boolean))]; +}; + +const fetchWithTimeout = async (url, options = {}) => { + if (typeof AbortController === "undefined") { + return Promise.race([ + fetch(url, options), + new Promise((_, reject) => + setTimeout(() => reject(new Error(`Request timeout after ${ML_MODEL_TIMEOUT_MS}ms`)), ML_MODEL_TIMEOUT_MS) + ), + ]); + } + + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), ML_MODEL_TIMEOUT_MS); + + try { + return await fetch(url, { ...options, signal: controller.signal }); + } finally { + clearTimeout(timer); + } +}; + +const parseUpstreamResponse = async (response) => { + const rawResponse = await response.text(); + if (!rawResponse) return {}; + + try { + return JSON.parse(rawResponse); + } catch (_error) { + const preview = rawResponse.slice(0, 160).replace(/\s+/g, " ").trim(); + const message = `Upstream did not return JSON (status ${response.status}). Body starts with: ${preview}`; + throw new Error(message, { cause: _error }); + } +}; + +const forwardJsonRequest = async (req, res, upstreamPath) => { + const candidates = getAiBackendCandidates(); + const failures = []; + + for (const candidateUrl of candidates) { + try { + const response = await fetchWithTimeout(`${candidateUrl}${upstreamPath}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(req.body), + }); + + const data = await parseUpstreamResponse(response); + + return res.status(response.status).json(data); + } catch (error) { + failures.push({ url: candidateUrl, message: error.message }); + } + } + + return res.status(502).json({ + error: "AI model service unavailable", + details: failures, + hint: "Set AI_BACKEND_URL to a reachable AI service URL (for HF, usually https://-agromind-ai-backend.hf.space).", + }); +}; + +router.post("/crop-recommendation", async (req, res) => { + await forwardJsonRequest(req, res, "/crop_recommendation"); +}); + +router.post("/fertilizer-prediction", async (req, res) => { + await forwardJsonRequest(req, res, "/fertilizer_prediction"); +}); + +router.post("/predict-disease", upload.single("file"), async (req, res) => { + const candidates = getAiBackendCandidates(); + const failures = []; + + try { + if (!req.file) { + return res.status(400).json({ error: "No image file uploaded" }); + } + + for (const candidateUrl of candidates) { + try { + const formData = new FormData(); + formData.append( + "file", + new Blob([req.file.buffer]), + req.file.originalname || "image.jpg" + ); + + const response = await fetchWithTimeout(`${candidateUrl}/predict_disease`, { + method: "POST", + body: formData, + }); + + const data = await parseUpstreamResponse(response); + + return res.status(response.status).json(data); + } catch (error) { + failures.push({ url: candidateUrl, message: error.message }); + } + } + + return res.status(502).json({ + error: "AI model service unavailable", + details: failures, + hint: "Set AI_BACKEND_URL to a reachable AI service URL (for HF, usually https://-agromind-ai-backend.hf.space).", + }); + } catch (error) { + return res.status(500).json({ + error: "Unexpected error while processing disease prediction request", + details: error.message, + }); + } +}); + +/** + * POST /api/ml/remedy + * Generate AI-powered remedy and prevention advice for a detected plant disease. + * Optionally translate the response into any Indian language. + * maxTokens is set to 1024 to accommodate Indic scripts which consume more tokens + * per character than English (BPE tokenizers encode Unicode Indic glyphs at 2-4x cost). + */ +router.post("/remedy", async (req, res) => { + const { disease, lang = "en" } = req.body; + if (!disease) { + return res.status(400).json({ error: "disease name is required" }); + } + + const langName = LANGUAGE_MAP[lang] || "English"; + const langInstruction = + lang !== "en" + ? `Respond entirely in ${langName}. Use simple, farmer-friendly language.` + : "Use simple, farmer-friendly English."; + + const prompt = `You are an expert agricultural scientist. A farmer's plant has been detected with: "${disease}". + +${langInstruction} + +Provide a concise and practical response in exactly this format: +🌿 Organic Remedy: [2-3 organic/traditional remedies, max 30 words each] +πŸ’Š Chemical Treatment: [1-2 specific pesticide/fungicide names with dosage, max 20 words each] +πŸ›‘οΈ Prevention: [2-3 preventive measures for next season, max 25 words each] + +Be specific, actionable, and keep each section brief.`; + + try { + // 1024 tokens instead of 512 β€” Indic languages need ~2-4x more tokens per character + const text = await generateAIContent(prompt, { model: 'openai/gpt-oss-120b', temperature: 0.4, maxTokens: 1024 }); + return res.json({ success: true, remedy: text.trim(), disease, lang }); + } catch (err) { + return res.status(500).json({ + success: false, + error: "Failed to generate remedy", + details: err.message, + }); + } +}); + +/** + * POST /api/ml/analyze-prediction + * Generate an AI-powered summary and analysis of an ML model prediction. + * Used by frontend prediction components to show a helpful explanation. + * maxTokens is set to 1024 to accommodate Indic scripts which consume more tokens + * per character than English. + */ +router.post("/analyze-prediction", async (req, res) => { + const { model_type, prediction, input_data, lang = "en" } = req.body; + if (!model_type || !prediction) { + return res.status(400).json({ error: "model_type and prediction are required" }); + } + + const langName = LANGUAGE_MAP[lang] || "English"; + const langInstruction = + lang !== "en" + ? `Respond entirely in ${langName}. Use simple, farmer-friendly language.` + : "Use simple, farmer-friendly English."; + + let contextDescription; + if (model_type === "crop_recommendation") { + const d = input_data || {}; + contextDescription = `The AI crop recommendation model analyzed the farmer's soil and weather conditions: +- Nitrogen: ${d.nitrogen ?? "N/A"}, Phosphorus: ${d.phosphorus ?? "N/A"}, Potassium: ${d.potassium ?? "N/A"} +- Temperature: ${d.temperature ?? "N/A"}Β°C, Humidity: ${d.humidity ?? "N/A"}%, Rainfall: ${d.rainfall ?? "N/A"} mm, pH: ${d.ph ?? "N/A"} +The model recommends growing: "${prediction}".`; + } else if (model_type === "fertilizer_prediction") { + const d = input_data || {}; + contextDescription = `The AI fertilizer prediction model analyzed: +- Soil Type: ${d.soil_type ?? "N/A"}, Crop Type: ${d.crop_type ?? "N/A"} +- Temperature: ${d.temperature ?? "N/A"}, Humidity: ${d.humidity ?? "N/A"}, Moisture: ${d.moisture ?? "N/A"} +- Nitrogen: ${d.nitrogen ?? "N/A"}, Phosphorus: ${d.phosphorus ?? "N/A"}, Potassium: ${d.potassium ?? "N/A"} +The model recommends using: "${prediction}" fertilizer.`; + } else if (model_type === "loan_prediction") { + contextDescription = `The AI loan eligibility model analyzed the farmer's data and predicted: "${prediction}".`; + } else if (model_type === "disease_detection") { + contextDescription = `The AI plant disease detection model identified: "${prediction}" from the uploaded plant image.`; + } else { + contextDescription = `The AI model (${model_type}) predicted: "${prediction}".`; + } + + const prompt = `You are a helpful agricultural AI assistant. ${contextDescription} + +${langInstruction} + +Provide a brief, farmer-friendly summary in 3-4 sentences explaining: +1. What this prediction means for the farmer +2. Why this might be recommended given the conditions +3. One practical next step the farmer should take + +Keep it concise and actionable.`; + + try { + // 1024 tokens instead of 512 β€” Indic languages need ~2-4x more tokens per character + const text = await generateAIContent(prompt, { model: 'openai/gpt-oss-120b', temperature: 0.5, maxTokens: 1024 }); + return res.json({ success: true, analysis: text.trim(), model_type, prediction }); + } catch (err) { + return res.status(500).json({ + success: false, + error: "Failed to generate analysis", + details: err.message, + }); + } +}); + +// ── HF-backed ML routes (saffron, walnut-defect, walnut-rancidity, apple-price) ── +// These are handled entirely by mlRoutes.js which uses its own multer instance +// that accepts both "image" and "file" field names. Do NOT add duplicate handlers +// for these paths above this line β€” they would shadow mlRoutes and break field parsing. +router.use(mlRoutes); + +export default router; diff --git a/backend/routes/appointmentRoutes.js b/backend/routes/appointmentRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..98ec389d6701d6bf72c717dfddd1bc37611c350e --- /dev/null +++ b/backend/routes/appointmentRoutes.js @@ -0,0 +1,20 @@ +// appointmentRoutes.js + +import express from 'express'; +import { bookAppointment, acceptAppointment, declineAppointment, getAppointmentsForExpert, getAppointmentsForFarmer } from '../controllers/appointmentController.js'; +import { verifyToken } from '../middleware/jwt.js'; + +const router = express.Router(); + +// Apply the verifyToken middleware to the book route +router.post('/book', verifyToken, (req, res) => bookAppointment(req, res, req.app.get('socketio'))); +router.post('/:appointmentId/accept', verifyToken, (req, res) => acceptAppointment(req, res, req.app.get('socketio'))); +router.post('/:appointmentId/decline', verifyToken, (req, res) => declineAppointment(req, res, req.app.get('socketio'))); + +// Route to get all appointments for expert +router.get('/expert', verifyToken, getAppointmentsForExpert); + +// Route to get all appointments for farmer +router.get('/farmer', verifyToken, getAppointmentsForFarmer); + +export default router; diff --git a/backend/routes/assistantRoute.js b/backend/routes/assistantRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..df101f783e430b7fdd19906a131b1a73de99a7c1 --- /dev/null +++ b/backend/routes/assistantRoute.js @@ -0,0 +1,115 @@ +/** + * POST /api/assistant/chat + * AgroMind AI Assistant β€” powered by Groq LLaMA. + * Supports all Indian languages. Responds in the language the user writes in. + */ +import express from "express"; +import { generateAIContent } from "../utils/aiHelper.js"; +import { LANGUAGE_MAP } from "../utils/aiOrchestrator.js"; + +const router = express.Router(); + +export const ASSISTANT_MAX_TOKENS = 4096; + +export const resolveAssistantLanguage = ({ lang = "en", selected_language: selectedLanguage } = {}) => { + if (selectedLanguage && LANGUAGE_MAP[selectedLanguage]) return selectedLanguage; + if (lang && LANGUAGE_MAP[lang]) return lang; + return "en"; +}; + +export const buildSystemPrompt = (languageCode = "en") => { + const languageName = LANGUAGE_MAP[languageCode] || "English"; + return `You are AgroMind AI, a friendly, secure, and highly knowledgeable agricultural AI assistant for Indian farmers. + +All communications and data entered here are completely private, confidential, and protected. We value your privacy and never sell or share your farming data with external third parties. + +Your task is to help farmers with farming decisions and navigate the AgroMind application. + +APPLICATION NAVIGATION & HELP GUIDE (RAG Database): +AgroMind has many specialized sections/features. When a user asks about a feature, how to navigate to a tool, where to perform an action, or requests help, you MUST guide them and provide a direct hyperlink using markdown: [Feature Name](/route_path) + +Available features, tools, and their exact routes: +- Crop Prediction / Recommendation: Suggests the best crops to grow based on soil N, P, K, pH, temp, humidity, and rainfall. Link: [Crop Prediction](/crop_prediction) +- Plant Disease Detection: Upload a crop leaf image to detect diseases and get treatment. Link: [Disease Detection](/crop_disease_detection) +- Fertilizer Recommendation: Recommends fertilizer type and ratio based on soil values and crop type. Link: [Fertilizer Prediction](/fertilizer_prediction) +- Farm Loan Eligibility: Predicts eligibility for agricultural loans (KCC) based on farmer profile. Link: [Loan Prediction](/loan_prediction) +- Harvest Readiness: Predicts the optimal harvesting time based on weather, crop type, and visual indicators. Link: [Harvest Readiness](/harvest_readiness) +- Water Optimization: Smart irrigation planner based on moisture levels. Link: [Water Optimization](/water_optimization) +- Soil Health Monitoring: Tracks soil nutrients and composition over time. Link: [Soil Health](/soil_health) +- Crop Rotation Planner: Recommends crop rotation schedules to maintain soil fertility. Link: [Crop Rotation](/crop_rotation) +- Saffron Purity Analyzer: Detects adulteration in saffron using vision analysis. Link: [Saffron Analyzer](/saffron_analyzer) +- Walnut Defect Detection: Detects defects, shells, or damage in walnuts. Link: [Walnut Defect](/walnut_defect) +- Walnut Shelf-Life Predictor: Estimates shelf life of walnuts based on temperature and storage. Link: [Walnut Shelf Life](/walnut_shelf_life) +- Pest Outbreak Warning System: Predicts regional pest outbreaks using weather data. Link: [Pest Outbreak Warning](/pest_outbreak_warning) +- Market Price Prediction: Predicts future market prices of agricultural commodities. Link: [Market Price Prediction](/market_prediction) +- Apple Price Predictor: Recommends prices for apples based on grade and quality. Link: [Apple Price Predictor](/apple_price_predictor) +- Mandi Prices: Shows current real-time prices in various local mandis. Link: [Mandi Prices](/mandi_prices) +- Crop Economics Simulator: Calculates costs, profits, and budgets for different crops. Link: [Crop Economics](/crop_economics) +- Value Chain Platform: Connects farmers directly to wholesalers and cold storage. Link: [Value Chain](/value_chain) +- Hedging Platform: Protects crop sales against future price fluctuations. Link: [Hedging Platform](/hedging_platform) +- CPO Tariff Simulator: Models palm oil import tariffs and effects. Link: [Tariff Simulator](/tariff_simulator) +- CROPIC Insurance (PMFBY): Estimates crop insurance premiums and handles claims. Link: [CROPIC Insurance](/cropic_insurance) +- Carbon Credits & MRV: Track carbon sequestration and earn carbon credits. Link: [Carbon Credits & MRV](/mrv_carbon) +- CRM Machine Tracking: Rents and tracks crop residue management machines. Link: [CRM Machine Tracking](/crm_tracking) +- Millets Marketplace: Trade millets directly at competitive prices. Link: [Millets Marketplace](/millets_marketplace) +- Oil Palm Advisory: Tailored crop advisory for oil palm plantation. Link: [Oil Palm Advisory](/oil_palm_advisory) +- Real-Time Weather Alerts: Provides detailed local weather forecasts and alerts. Link: [Weather Alerts](/weather_report) +- NDVI & Rainfall: Satellite vegetation health indices and rainfall tracking. Link: [NDVI & Satellite](/ndvi) +- Geo Pest Heatmap: Geospatial map of pest and disease outbreaks. Link: [Pest Heatmap](/geo_pest_disease_heatmap) +- AI Yield Prediction: Estimates crop yields per hectare. Link: [Yield Prediction](/yield_prediction) +- Community Forum: Discuss with fellow farmers and krishi scientists. Link: [Community Forum](/community) +- Smart Crop Advisory: General personalized crop recommendations. Link: [Crop Advisory](/farming_recommendations) +- Smart Task Scheduling: Interactive scheduler for farm tasks. Link: [Task Scheduling](/task_scheduling) +- AgroMind-VQA (Visual Question Answering): Multimodal system to ask questions by uploading farm photos, sensor readings, and satellite data. Link: [AgroMind-VQA](/agromind_vqa) +- User Profile: View and update farmer details and land size. Link: [Profile](/profile) +- Application Settings: Change language, theme, and authentication settings. Link: [Settings](/settings) +- Home Dashboard: Overview of active farm stats. Link: [Home](/farmer_home) + +NAVIGATION LINK INSTRUCTION: +Whenever a user asks how to find a page, how to use a feature, where to do an action, or says they are lost, ALWAYS provide the exact markdown link above so they can navigate directly (e.g. "You can use our [Disease Detection](/crop_disease_detection) tool to detect this leaf disease."). + +PRIVACY COMMITMENT: +State clearly that all farmer data (images, sensor readings, chat logs) is fully secure, private, and conforms to strict privacy policies. + +IMPORTANT RULES: +1. Always respond in the user's selected language: ${languageName}. If the user writes in another language, still reply in ${languageName} unless they explicitly ask for translation. +2. Use simple, practical language that farmers can understand. +3. Be concise β€” keep answers to 3-5 sentences unless more detail is needed. +4. Be encouraging and respectful. Address the farmer as a knowledgeable person. +5. If you don't know something, say so honestly and suggest consulting a local agricultural officer (Krishi Vigyan Kendra). +6. Always prioritize sustainable and cost-effective solutions.`; +}; + +router.post("/chat", async (req, res) => { + const { message, history = [] } = req.body; + const languageCode = resolveAssistantLanguage(req.body); + + if (!message || !message.trim()) { + return res.status(400).json({ error: "message is required" }); + } + + // Build messages array (keep last 10 turns for context) + const recentHistory = history.slice(-10); + const messages = [ + { role: "system", content: buildSystemPrompt(languageCode) }, + ...recentHistory.map((h) => ({ role: h.role, content: h.content })), + { role: "user", content: message.trim() }, + ]; + + try { + const reply = await generateAIContent(null, { + temperature: 0.6, + maxTokens: ASSISTANT_MAX_TOKENS, + _messages: messages, // pass raw messages array + }); + return res.json({ success: true, reply: reply.trim(), lang: languageCode, selected_language: languageCode }); + } catch (err) { + return res.status(500).json({ + success: false, + error: "Assistant unavailable", + details: err.message, + }); + } +}); + +export default router; diff --git a/backend/routes/authRoute.js b/backend/routes/authRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..f5a4d9dc30efb1aff40c27840525c71754269606 --- /dev/null +++ b/backend/routes/authRoute.js @@ -0,0 +1,16 @@ +import express from 'express' +import { signin, signout, signup, syncGoogleUser } from '../controllers/authController.js'; +import { verifyToken } from '../middleware/authMiddleware.js'; + +const router = express.Router(); + +router.post('/signup', signup); +router.post('/register', signup); +router.post('/signin', signin); +router.post('/login', signin); +router.post('/signout', signout); +router.post('/logout', signout); +// Sync Firebase-authenticated user into Firestore (call after Firebase sign-in) +router.post('/sync-user', verifyToken, syncGoogleUser); + +export default router; diff --git a/backend/routes/blogRecommendationsRoute.js b/backend/routes/blogRecommendationsRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..238ef103a7a30c7530bff40fae0a6066837eaa68 --- /dev/null +++ b/backend/routes/blogRecommendationsRoute.js @@ -0,0 +1,9 @@ +import express from 'express'; +import { getBlogRecommendations } from '../controllers/blogRecommendationsController.js'; + +const router = express.Router(); + +// Define the route for expert recommendations +router.get('/blog-recommendations', getBlogRecommendations); + +export default router; diff --git a/backend/routes/communityRoutes.js b/backend/routes/communityRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..6fc77975d8026271d4dd620847fdd5487440c8a3 --- /dev/null +++ b/backend/routes/communityRoutes.js @@ -0,0 +1,209 @@ +import express from "express"; + +const router = express.Router(); + +// Temporary in-memory store for Q&A; migrate this collection to Firestore when persistence is enabled. +const questions = []; +const answers = []; +let questionIdCounter = 1; +let answerIdCounter = 1; + +/** + * POST /community/questions + * Post a new question + */ +router.post("/questions", (req, res) => { + const { title, body, crop, tags, authorId, authorName, imageUrl } = req.body; + + if (!title || !body) { + return res.status(400).json({ success: false, message: "title and body are required" }); + } + + const question = { + id: questionIdCounter++, + title, + body, + crop: crop || "general", + tags: tags || [], + authorId: authorId || "anonymous", + authorName: authorName || "Farmer", + imageUrl: imageUrl || null, + votes: 0, + answerCount: 0, + flagged: false, + moderationStatus: "approved", + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }; + + // AI safety check: flag potentially unsafe advice in the question + const unsafeKeywords = ["pesticide mix", "illegal", "banned chemical", "poison"]; + const hasUnsafe = unsafeKeywords.some((kw) => body.toLowerCase().includes(kw)); + if (hasUnsafe) { + question.moderationStatus = "flagged"; + question.flagged = true; + } + + questions.push(question); + + res.status(201).json({ success: true, question }); +}); + +/** + * GET /community/questions + * List questions with filters + */ +router.get("/questions", (req, res) => { + const { crop, sort, page, limit } = req.query; + let filtered = [...questions]; + + if (crop && crop !== "all") { + filtered = filtered.filter((q) => q.crop.toLowerCase() === crop.toLowerCase()); + } + + // Sort + if (sort === "votes") { + filtered.sort((a, b) => b.votes - a.votes); + } else if (sort === "answers") { + filtered.sort((a, b) => b.answerCount - a.answerCount); + } else { + filtered.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); + } + + const pageNum = parseInt(page) || 1; + const pageSize = Math.min(parseInt(limit) || 20, 50); + const start = (pageNum - 1) * pageSize; + const paged = filtered.slice(start, start + pageSize); + + res.json({ + success: true, + questions: paged, + total: filtered.length, + page: pageNum, + totalPages: Math.ceil(filtered.length / pageSize), + }); +}); + +/** + * POST /community/questions/:id/answers + * Post an answer/remedy to a question + */ +router.post("/questions/:id/answers", (req, res) => { + const questionId = parseInt(req.params.id); + const { body, authorId, authorName, imageUrl } = req.body; + + if (!body) { + return res.status(400).json({ success: false, message: "body is required" }); + } + + const question = questions.find((q) => q.id === questionId); + if (!question) { + return res.status(404).json({ success: false, message: "Question not found" }); + } + + const answer = { + id: answerIdCounter++, + questionId, + body, + authorId: authorId || "anonymous", + authorName: authorName || "Farmer", + imageUrl: imageUrl || null, + votes: 0, + isBestRemedy: false, + flagged: false, + createdAt: new Date().toISOString(), + }; + + // AI safety flagging + const unsafeKeywords = ["mix pesticides", "banned", "toxic", "illegal spray"]; + const hasUnsafe = unsafeKeywords.some((kw) => body.toLowerCase().includes(kw)); + if (hasUnsafe) { + answer.flagged = true; + } + + answers.push(answer); + question.answerCount++; + + res.status(201).json({ success: true, answer }); +}); + +/** + * GET /community/questions/:id/answers + * Get answers for a question + */ +router.get("/questions/:id/answers", (req, res) => { + const questionId = parseInt(req.params.id); + const questionAnswers = answers + .filter((a) => a.questionId === questionId) + .sort((a, b) => b.votes - a.votes); + + // Mark top-voted non-flagged answer as best remedy + const bestRemedy = questionAnswers.find((a) => !a.flagged && a.votes > 0); + if (bestRemedy) bestRemedy.isBestRemedy = true; + + res.json({ + success: true, + answers: questionAnswers, + total: questionAnswers.length, + aiSummary: questionAnswers.length > 0 + ? `Based on ${questionAnswers.length} community responses, the most recommended approach involves: ${questionAnswers[0]?.body?.substring(0, 100)}...` + : null, + }); +}); + +/** + * POST /community/questions/:id/vote + * Vote on a question + */ +router.post("/questions/:id/vote", (req, res) => { + const questionId = parseInt(req.params.id); + const { direction } = req.body; // "up" or "down" + + const question = questions.find((q) => q.id === questionId); + if (!question) { + return res.status(404).json({ success: false, message: "Question not found" }); + } + + question.votes += direction === "up" ? 1 : -1; + + res.json({ success: true, votes: question.votes }); +}); + +/** + * POST /community/answers/:id/vote + * Vote on an answer + */ +router.post("/answers/:id/vote", (req, res) => { + const answerId = parseInt(req.params.id); + const { direction } = req.body; + + const answer = answers.find((a) => a.id === answerId); + if (!answer) { + return res.status(404).json({ success: false, message: "Answer not found" }); + } + + answer.votes += direction === "up" ? 1 : -1; + + res.json({ success: true, votes: answer.votes }); +}); + +/** + * POST /community/answers/:id/flag + * Flag an answer for moderation + */ +router.post("/answers/:id/flag", (req, res) => { + const answerId = parseInt(req.params.id); + const { reason } = req.body; + + const answer = answers.find((a) => a.id === answerId); + if (!answer) { + return res.status(404).json({ success: false, message: "Answer not found" }); + } + + answer.flagged = true; + answer.flagReason = reason || "Reported by user"; + + res.json({ success: true, message: "Answer flagged for review" }); +}); + +export default router; diff --git a/backend/routes/crmTrackingRoutes.js b/backend/routes/crmTrackingRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..36539d35c6c190681f6f3b544efa1bee66a6adf5 --- /dev/null +++ b/backend/routes/crmTrackingRoutes.js @@ -0,0 +1,423 @@ +/** + * CRM Machine Tracking Routes + * Full privacy: all user-owned data scoped to userId. + * Shared fleet (machines) visible to all for booking, but write-ops are owner-only. + * Bookings, Maintenance, Analytics β†’ strictly user-scoped. + */ +import express from "express"; +import { verifyToken } from "../middleware/authMiddleware.js"; + +const router = express.Router(); + +import { CRMMachine, CRMBooking, CRMMaintenance, Telemetry } from "../utils/firestoreCollections.js"; + +// ── Helpers ─────────────────────────────────────────────────────────────────── + +/** Resolve user identifier from req β€” returns string or null */ +const resolveUserId = (req) => + req.userId || + (req.user?._id ? req.user._id.toString() : null) || + null; + +// ── BOOKINGS ────────────────────────────────────────────────────────────────── + +/** + * GET /crm/bookings + * Returns ONLY the authenticated user's bookings. + * Falls back to phone-matched offline bookings (from localStorage sync) if offline. + */ +router.get("/bookings", verifyToken, async (req, res) => { + try { + const uid = resolveUserId(req); + const bookings = await CRMBooking.find({ userId: uid }).sort("-createdAt").limit(200); + res.json({ + success: true, + bookings: bookings.map(b => ({ + id: b.bookingRef || b._id.toString().slice(-6).toUpperCase(), + machine: b.asset_type, + date: b.date, + hours: b.hours, + cost: b.estimated_cost, + status: b.status, + farmer: b.farmer_name, + village: b.village, + phone: b.phone, + })), + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * POST /crm/bookings + * Creates a booking scoped to the authenticated user. + */ +router.post("/bookings", verifyToken, async (req, res) => { + try { + const uid = resolveUserId(req); + const { asset_type, date, hours, farmer_name, village, phone, estimated_cost } = req.body; + if (!asset_type || !date || !hours || !farmer_name || !phone) { + return res.status(400).json({ success: false, error: "asset_type, date, hours, farmer_name, and phone are required" }); + } + const bookingRef = `BK${Date.now().toString(36).toUpperCase()}`; + const booking = await CRMBooking.create({ + bookingRef, userId: uid, asset_type, date, + hours: Number(hours), farmer_name, + village: village || "", phone, + estimated_cost: estimated_cost || 0, + status: "confirmed", + }); + res.status(201).json({ + success: true, + message: "Booking confirmed!", + booking: { + id: bookingRef, machine: asset_type, date, + hours: booking.hours, cost: booking.estimated_cost, + status: booking.status, farmer: farmer_name, village, phone, + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * DELETE /crm/bookings/:id + * Cancel a booking (owner only). + */ +router.delete("/bookings/:id", verifyToken, async (req, res) => { + try { + const uid = resolveUserId(req); + const booking = await CRMBooking.findOneAndUpdate( + { $or: [{ bookingRef: req.params.id }, { _id: req.params.id }], userId: uid }, + { status: "cancelled" }, + { new: true } + ); + if (!booking) return res.status(404).json({ success: false, error: "Booking not found or not yours" }); + res.json({ success: true, message: "Booking cancelled" }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +// ── MAINTENANCE ─────────────────────────────────────────────────────────────── + +/** + * GET /crm/maintenance + * User's own maintenance schedules. + */ +router.get("/maintenance", verifyToken, async (req, res) => { + try { + const uid = resolveUserId(req); + const records = await CRMMaintenance.find({ userId: uid }).sort("-createdAt"); + res.json({ success: true, maintenance: records }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * POST /crm/maintenance + * Schedule a new maintenance task. + */ +router.post("/maintenance", verifyToken, async (req, res) => { + try { + const uid = resolveUserId(req); + const { machineId, machineType, maintenanceType, scheduledDate, hoursAtService, priority, notes } = req.body; + if (!machineId || !maintenanceType || !scheduledDate) { + return res.status(400).json({ success: false, error: "machineId, maintenanceType and scheduledDate are required" }); + } + const record = await CRMMaintenance.create({ + userId: uid, machineId, machineType: machineType || "", + maintenanceType, scheduledDate, hoursAtService: hoursAtService || 0, + priority: priority || "medium", notes: notes || "", status: "scheduled", + }); + res.status(201).json({ success: true, message: "Maintenance scheduled!", maintenance: record }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * PUT /crm/maintenance/:id + * Update a maintenance record (mark complete, change priority, etc.) + */ +router.put("/maintenance/:id", verifyToken, async (req, res) => { + try { + const uid = resolveUserId(req); + const updates = req.body; + delete updates.userId; + const record = await CRMMaintenance.findOneAndUpdate( + { _id: req.params.id, userId: uid }, updates, { new: true } + ); + if (!record) return res.status(404).json({ success: false, error: "Record not found or not yours" }); + + // If marking complete, update machine's lastMaintenanceDate + if (updates.status === "completed") { + await CRMMachine.findOneAndUpdate( + { machineId: record.machineId }, + { "stats.lastMaintenanceDate": new Date() } + ); + } + res.json({ success: true, maintenance: record }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * DELETE /crm/maintenance/:id + */ +router.delete("/maintenance/:id", verifyToken, async (req, res) => { + try { + const uid = resolveUserId(req); + const record = await CRMMaintenance.findOneAndDelete({ _id: req.params.id, userId: uid }); + if (!record) return res.status(404).json({ success: false, error: "Record not found or not yours" }); + res.json({ success: true, message: "Maintenance record deleted" }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +// ── FLEET (machines) ────────────────────────────────────────────────────────── + +/** + * GET /crm/machines β€” public fleet overview (readable by anyone for booking purposes) + */ +router.get("/machines", async (req, res) => { + try { + const { lat, lng, radius = 50, status, machineType, available } = req.query; + const query = {}; + if (status) query.currentStatus = status; + if (machineType) query.machineType = machineType; + if (available === "true") query["availability.isAvailable"] = true; + if (lat && lng) { + query.location = { $near: { $geometry: { type: "Point", coordinates: [parseFloat(lng), parseFloat(lat)] }, $maxDistance: parseFloat(radius) * 1000 } }; + } + const machines = await CRMMachine.find(query).populate("ownerId", "name phone").sort("-updatedAt"); + res.json({ success: true, data: machines, total: machines.length }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /crm/my-machines β€” only the logged-in user's machines + */ +router.get("/my-machines", verifyToken, async (req, res) => { + try { + const machines = await CRMMachine.find({ ownerId: req.user._id }); + res.json({ success: true, data: machines }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /crm/machines/:id + */ +router.get("/machines/:id", async (req, res) => { + try { + const machine = await CRMMachine.findOne({ $or: [{ _id: req.params.id }, { machineId: req.params.id }] }).populate("ownerId", "name phone email"); + if (!machine) return res.status(404).json({ success: false, error: "Machine not found" }); + const recentTelemetry = await Telemetry.find({ machineId: machine.machineId }).sort("-timestamp").limit(100); + res.json({ success: true, data: { machine, telemetryHistory: recentTelemetry } }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * POST /crm/register-machine + */ +router.post("/register-machine", verifyToken, async (req, res) => { + try { + const { machineId, gpsDeviceId, machineType, manufacturer, model, yearOfPurchase, registrationNumber, location, availability, region } = req.body; + if (!machineId || !gpsDeviceId || !machineType) { + return res.status(400).json({ success: false, error: "machineId, gpsDeviceId, and machineType are required" }); + } + if (await CRMMachine.findOne({ machineId })) { + return res.status(400).json({ success: false, error: "Machine with this ID already registered" }); + } + const machine = await CRMMachine.create({ + machineId, gpsDeviceId, ownerId: req.user._id, machineType, + manufacturer, model, yearOfPurchase, registrationNumber, + location: location ? { type: "Point", coordinates: [location.lng, location.lat] } : undefined, + availability, region, + }); + res.status(201).json({ success: true, data: machine, message: "Machine registered successfully" }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * PUT /crm/machines/:id β€” owner only + */ +router.put("/machines/:id", verifyToken, async (req, res) => { + try { + const updates = req.body; + delete updates.machineId; delete updates.ownerId; delete updates.gpsDeviceId; + const machine = await CRMMachine.findOne({ $or: [{ _id: req.params.id }, { machineId: req.params.id }], ownerId: req.user._id }); + if (!machine) return res.status(404).json({ success: false, error: "Machine not found or not authorized" }); + Object.assign(machine, updates); + await machine.save(); + res.json({ success: true, data: machine, message: "Machine updated successfully" }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * DELETE /crm/machines/:id β€” owner only + */ +router.delete("/machines/:id", verifyToken, async (req, res) => { + try { + const machine = await CRMMachine.findOne({ $or: [{ _id: req.params.id }, { machineId: req.params.id }], ownerId: req.user._id }); + if (!machine) return res.status(404).json({ success: false, error: "Machine not found or not authorized" }); + await CRMMachine.deleteOne({ _id: machine._id }); + res.json({ success: true, message: "Machine deleted successfully" }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +// ── TELEMETRY ───────────────────────────────────────────────────────────────── + +router.post("/telemetry", async (req, res) => { + try { + const { machineId, lat, lng, timestamp, status, hoursActive, speed, fuelLevel, areaCovered } = req.body; + if (!machineId) return res.status(400).json({ success: false, error: "machineId is required" }); + const telemetry = await Telemetry.create({ + machineId, timestamp: timestamp ? new Date(timestamp) : new Date(), + location: { lat, lng }, status, hoursActive, speed, fuelLevel, areaCovered, + }); + const updateData = { + lastTelemetry: { timestamp: telemetry.timestamp, lat, lng, hoursActive, fuelLevel }, + currentStatus: status || "active", + }; + if (lat && lng) updateData.location = { type: "Point", coordinates: [lng, lat] }; + await CRMMachine.findOneAndUpdate( + { machineId }, + { $set: updateData, $inc: { "stats.totalHoursUsed": hoursActive ? 0.25 : 0, "stats.totalAreaCovered": areaCovered || 0 } } + ); + res.json({ success: true, message: "Telemetry received" }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +// ── ANALYTICS ───────────────────────────────────────────────────────────────── + +/** + * GET /crm/analytics + * Returns live analytics derived from the user's own bookings + maintenance records. + * Replaces the dummy utilization-report for the UI. + */ +router.get("/analytics", verifyToken, async (req, res) => { + try { + const uid = resolveUserId(req); + + // Aggregate bookings by machine type + const bookingAgg = await CRMBooking.aggregate([ + { $match: { userId: uid, status: { $ne: "cancelled" } } }, + { $group: { + _id: "$asset_type", + totalBookings: { $sum: 1 }, + totalHours: { $sum: "$hours" }, + totalCost: { $sum: "$estimated_cost" }, + }}, + { $sort: { totalHours: -1 } }, + ]); + + const maintenanceAgg = await CRMMaintenance.aggregate([ + { $match: { userId: uid } }, + { $group: { + _id: "$status", + count: { $sum: 1 }, + }}, + ]); + + const totalBookings = bookingAgg.reduce((s, b) => s + b.totalBookings, 0); + const totalHours = bookingAgg.reduce((s, b) => s + b.totalHours, 0); + const totalSpent = bookingAgg.reduce((s, b) => s + b.totalCost, 0); + const maintByStatus = Object.fromEntries(maintenanceAgg.map(m => [m._id, m.count])); + + res.json({ + success: true, + data: { + summary: { + totalBookings, + totalHours, + totalSpent, + maintenanceScheduled: maintByStatus.scheduled || 0, + maintenanceCompleted: maintByStatus.completed || 0, + maintenanceOverdue: maintByStatus.overdue || 0, + }, + byMachine: bookingAgg.map(b => ({ + machineId: b._id, + totalBookings: b.totalBookings, + totalHours: b.totalHours, + totalCost: b.totalCost, + utilizationPercent: totalHours > 0 ? Math.round((b.totalHours / totalHours) * 100) : 0, + })), + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /crm/utilization-report (legacy, kept for backward compat only) + * Superseded by GET /crm/analytics (see above), which is what the UI actually + * calls. This is fleet-wide (Telemetry has no per-user field β€” machines are a + * shared resource per this file's own model), not per-user data, so it is + * intentionally NOT scoped by uid. + */ +router.get("/utilization-report", verifyToken, async (req, res) => { + try { + const { from, to } = req.query; + const fromDate = from ? new Date(from) : new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); + const toDate = to ? new Date(to) : new Date(); + + const telemetryStats = await Telemetry.aggregate([ + { $match: { timestamp: { $gte: fromDate, $lte: toDate } } }, + { $group: { + _id: "$machineId", + totalRecords: { $sum: 1 }, + activeRecords: { $sum: { $cond: [{ $eq: ["$status", "active"] }, 1, 0] } }, + totalHours: { $sum: { $ifNull: ["$hoursActive", 0] } }, + totalArea: { $sum: { $ifNull: ["$areaCovered", 0] } }, + avgSpeed: { $avg: "$speed" }, + firstRecord: { $min: "$timestamp" }, + lastRecord: { $max: "$timestamp" }, + }}, + { $lookup: { from: "crmmachines", localField: "_id", foreignField: "machineId", as: "machine" } }, + { $unwind: { path: "$machine", preserveNullAndEmptyArrays: true } }, + { $project: { + machineId: "$_id", + machineType: "$machine.machineType", + region: "$machine.region", + totalRecords: 1, activeRecords: 1, + utilizationPercent: { $multiply: [{ $divide: ["$activeRecords", { $max: ["$totalRecords", 1] }] }, 100] }, + totalHours: 1, totalArea: 1, avgSpeed: 1, + }}, + { $sort: { utilizationPercent: -1 } }, + ]); + + const summary = { + totalMachines: telemetryStats.length, + avgUtilization: telemetryStats.length > 0 ? telemetryStats.reduce((s, x) => s + x.utilizationPercent, 0) / telemetryStats.length : 0, + totalHoursOperated: telemetryStats.reduce((s, x) => s + x.totalHours, 0), + totalAreaCovered: telemetryStats.reduce((s, x) => s + x.totalArea, 0), + underutilized: telemetryStats.filter(x => x.utilizationPercent < 30).length, + }; + res.json({ success: true, data: { period: { from: fromDate, to: toDate }, summary, machines: telemetryStats, alerts: [] } }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +export default router; diff --git a/backend/routes/cropEconomicsRoutes.js b/backend/routes/cropEconomicsRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..d49b81091786dce297df81eff64b66438623303d --- /dev/null +++ b/backend/routes/cropEconomicsRoutes.js @@ -0,0 +1,672 @@ +/** + * Crop Economics Routes + * API endpoints for crop comparison, profitability simulation, and scheme lookup + */ +import express from "express"; +import { verifyToken } from "../middleware/authMiddleware.js"; +import axios from "axios"; +import { generateAIContent } from "../utils/aiHelper.js"; + +const router = express.Router(); + +import { GovernmentScheme, UserBadge, PriceAlert, FarmerProfile, Notification } from "../utils/firestoreCollections.js"; + +// Crop Economics Data (could be from DB, using constants for demo) +const CROP_ECONOMICS = { + groundnut: { + name: "Groundnut", + category: "oilseed", + yieldPerHa: 1800, // kg + pricePerKg: 55, + inputCosts: { + seeds: 4500, + fertilizer: 5500, + pesticides: 3000, + irrigation: 4000, + labor: 15000, + machinery: 5000, + other: 2000, + }, + duration: 120, // days + waterRequirement: 500, // mm + riskLevel: "medium", + }, + soybean: { + name: "Soybean", + category: "oilseed", + yieldPerHa: 2000, + pricePerKg: 42, + inputCosts: { + seeds: 3500, + fertilizer: 4500, + pesticides: 2500, + irrigation: 3500, + labor: 12000, + machinery: 4500, + other: 1500, + }, + duration: 100, + waterRequirement: 450, + riskLevel: "low", + }, + mustard: { + name: "Mustard", + category: "oilseed", + yieldPerHa: 1100, + pricePerKg: 50, + inputCosts: { + seeds: 1500, + fertilizer: 4000, + pesticides: 2000, + irrigation: 3000, + labor: 10000, + machinery: 4000, + other: 1500, + }, + duration: 130, + waterRequirement: 350, + riskLevel: "low", + }, + sunflower: { + name: "Sunflower", + category: "oilseed", + yieldPerHa: 1200, + pricePerKg: 48, + inputCosts: { + seeds: 2500, + fertilizer: 4500, + pesticides: 2500, + irrigation: 4000, + labor: 11000, + machinery: 4000, + other: 1500, + }, + duration: 95, + waterRequirement: 400, + riskLevel: "medium", + }, + cotton: { + name: "Cotton", + category: "cash_crop", + yieldPerHa: 1500, + pricePerKg: 60, + inputCosts: { + seeds: 3000, + fertilizer: 6000, + pesticides: 5000, + irrigation: 5500, + labor: 18000, + machinery: 5000, + other: 2500, + }, + duration: 180, + waterRequirement: 700, + riskLevel: "high", + }, + wheat: { + name: "Wheat", + category: "cereal", + yieldPerHa: 3500, + pricePerKg: 22, + inputCosts: { + seeds: 2000, + fertilizer: 5000, + pesticides: 2000, + irrigation: 6000, + labor: 10000, + machinery: 4500, + other: 1500, + }, + duration: 120, + waterRequirement: 450, + riskLevel: "low", + }, + rice: { + name: "Rice", + category: "cereal", + yieldPerHa: 4000, + pricePerKg: 20, + inputCosts: { + seeds: 1500, + fertilizer: 5500, + pesticides: 3000, + irrigation: 8000, + labor: 15000, + machinery: 4000, + other: 2000, + }, + duration: 130, + waterRequirement: 1200, + riskLevel: "medium", + }, +}; + +const CROP_ALIASES = { + paddy: "rice", +}; + +const normalizeCropKey = (crop = "") => { + const key = String(crop).toLowerCase(); + return CROP_ALIASES[key] || key; +}; + +const getRegionWeather = async (region = "Delhi") => { + const apiKey = process.env.OPENWEATHER_API_KEY; + if (!apiKey) return null; + + const weatherResponse = await axios.get("https://api.openweathermap.org/data/2.5/weather", { + params: { + q: region, + appid: apiKey, + units: "metric", + }, + timeout: 10000, + }); + + return { + region: weatherResponse.data.name || region, + description: weatherResponse.data.weather?.[0]?.description || "clear weather", + temperature: weatherResponse.data.main?.temp, + humidity: weatherResponse.data.main?.humidity, + windSpeed: weatherResponse.data.wind?.speed, + }; +}; + +/** + * GET /crop-economics/comparison + * Compare economics of two crops + */ +router.get("/comparison", async (req, res) => { + try { + const { crop1, crop2, region, areaHa = 1 } = req.query; + + if (!crop1 || !crop2) { + return res.status(400).json({ + success: false, + error: "Both crop1 and crop2 are required", + }); + } + + const cropData1 = CROP_ECONOMICS[normalizeCropKey(crop1)]; + const cropData2 = CROP_ECONOMICS[normalizeCropKey(crop2)]; + + if (!cropData1 || !cropData2) { + return res.status(400).json({ + success: false, + error: "Invalid crop type. Available: " + Object.keys(CROP_ECONOMICS).join(", "), + }); + } + + const area = parseFloat(areaHa); + + // Calculate economics for each crop + const calculateEconomics = (crop) => { + const totalInputCost = Object.values(crop.inputCosts).reduce((a, b) => a + b, 0); + const grossRevenue = crop.yieldPerHa * crop.pricePerKg; + const netProfit = grossRevenue - totalInputCost; + const roi = (netProfit / totalInputCost) * 100; + + return { + name: crop.name, + category: crop.category, + perHectare: { + yield: crop.yieldPerHa, + pricePerKg: crop.pricePerKg, + grossRevenue, + inputCosts: crop.inputCosts, + totalInputCost, + netProfit, + roi: Math.round(roi * 100) / 100, + }, + forArea: { + area, + totalYield: crop.yieldPerHa * area, + grossRevenue: grossRevenue * area, + totalInputCost: totalInputCost * area, + netProfit: netProfit * area, + }, + metrics: { + duration: crop.duration, + waterRequirement: crop.waterRequirement, + riskLevel: crop.riskLevel, + profitPerDay: Math.round((netProfit / crop.duration) * 100) / 100, + waterEfficiency: Math.round((crop.yieldPerHa / crop.waterRequirement) * 100) / 100, + }, + }; + }; + + const comparison1 = calculateEconomics(cropData1); + const comparison2 = calculateEconomics(cropData2); + + // Determine recommendation + let recommendation; + const profitDiff = comparison1.perHectare.netProfit - comparison2.perHectare.netProfit; + const roiDiff = comparison1.perHectare.roi - comparison2.perHectare.roi; + + if (profitDiff > 0 && roiDiff > 0) { + recommendation = { + recommendedCrop: normalizeCropKey(crop1), + reason: `${cropData1.name} offers higher profit (β‚Ή${Math.abs(profitDiff).toFixed(0)}/ha more) and better ROI (${Math.abs(roiDiff).toFixed(1)}% higher)`, + confidence: "high", + }; + } else if (profitDiff < 0 && roiDiff < 0) { + recommendation = { + recommendedCrop: normalizeCropKey(crop2), + reason: `${cropData2.name} offers higher profit (β‚Ή${Math.abs(profitDiff).toFixed(0)}/ha more) and better ROI (${Math.abs(roiDiff).toFixed(1)}% higher)`, + confidence: "high", + }; + } else { + const recommended = profitDiff > 0 ? normalizeCropKey(crop1) : normalizeCropKey(crop2); + recommendation = { + recommendedCrop: recommended, + reason: `Mixed results. Consider your priorities: ${crop1} vs ${crop2} trade-off between profit and ROI.`, + confidence: "medium", + }; + } + + res.json({ + success: true, + data: { + crop1: comparison1, + crop2: comparison2, + comparison: { + profitDifference: profitDiff, + roiDifference: roiDiff, + waterDifference: cropData1.waterRequirement - cropData2.waterRequirement, + durationDifference: cropData1.duration - cropData2.duration, + }, + recommendation, + region: region || "All India", + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /crop-economics/schemes + * Get government schemes for a region + */ +router.get("/schemes", async (req, res) => { + try { + const { region, schemeType, crop } = req.query; + + // Try to get from DB first + let schemes = await GovernmentScheme.find({ + active: true, + ...(region && { $or: [{ region }, { region: "All India" }] }), + ...(schemeType && { schemeType }), + ...(crop && { "eligibility.crops": crop }), + }).sort("-createdAt"); + + // If no schemes in DB, return default schemes + if (schemes.length === 0) { + schemes = [ + { + _id: "nmeo_os", + name: "National Mission on Edible Oils - Oil Seeds (NMEO-OS)", + code: "NMEO-OS", + description: "Mission to increase domestic production of edible oils through expansion of oilseed cultivation", + schemeType: "subsidy", + region: region || "All India", + eligibility: { + minLandHa: 0.5, + farmerCategories: ["small", "marginal", "medium"], + crops: ["groundnut", "soybean", "sunflower", "mustard", "sesame"], + }, + benefits: { + maxAmount: 25000, + subsidyPercent: 50, + description: "Up to 50% subsidy on seeds, farm machinery, and irrigation equipment", + }, + documents: ["Aadhaar", "Land Records", "Bank Account"], + active: true, + contactInfo: { + website: "https://nmeo.dac.gov.in", + }, + }, + { + _id: "pmfby", + name: "Pradhan Mantri Fasal Bima Yojana (PMFBY)", + code: "PMFBY", + description: "Crop insurance scheme to provide financial support in case of crop failure", + schemeType: "insurance", + region: region || "All India", + eligibility: { + farmerCategories: ["all"], + crops: Object.keys(CROP_ECONOMICS), + }, + benefits: { + subsidyPercent: 95, + description: "Premium subsidy up to 95% for food crops and oilseeds", + }, + documents: ["Aadhaar", "Land Records", "Sowing Certificate"], + active: true, + contactInfo: { + website: "https://pmfby.gov.in", + }, + }, + { + _id: "kcc", + name: "Kisan Credit Card (KCC)", + code: "KCC", + description: "Credit facility for farmers at subsidized interest rates", + schemeType: "credit", + region: region || "All India", + eligibility: { + farmerCategories: ["all"], + }, + benefits: { + maxAmount: 300000, + description: "Credit limit up to β‚Ή3 lakhs at 4% interest (with timely repayment)", + }, + documents: ["Aadhaar", "Land Records", "Identity Proof"], + active: true, + contactInfo: { + website: "https://pmkisan.gov.in", + }, + }, + ]; + } + + const weather = await getRegionWeather(region || "Delhi").catch(() => null); + let aiNewsTopics = []; + + if (weather) { + const topicPrompt = ` +You are an agri-policy assistant. +Given weather in ${weather.region} (${weather.description}, ${weather.temperature}Β°C, humidity ${weather.humidity}%, wind ${weather.windSpeed} m/s), +identify up to 5 currently relevant farming news topics for farmers. +Focus on weather-driven farm risks, market movement, sowing, irrigation, pest pressure, or crop-protection updates. +Return ONLY valid JSON array of strings. +`; + + try { + const topicRaw = await generateAIContent(topicPrompt.trim()); + aiNewsTopics = JSON.parse(topicRaw); + if (!Array.isArray(aiNewsTopics)) aiNewsTopics = []; + } catch (_e) { + aiNewsTopics = []; + } + } + + res.json({ + success: true, + data: { + schemes, + total: schemes.length, + region: region || "All India", + weather, + farmingNewsTopics: aiNewsTopics.filter((t) => typeof t === "string").slice(0, 5), + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * POST /crop-economics/simulate-profit + * Simulate profitability with custom parameters + */ +router.post("/simulate-profit", async (req, res) => { + try { + const { + crop, + areaHa = 1, + expectedYield, + expectedPrice, + inputCosts, + subsidy = 0, + loanAmount = 0, + loanInterest = 7, + loanTenure = 12, + } = req.body; + + if (!crop) { + return res.status(400).json({ + success: false, + error: "Crop type is required", + }); + } + + const baseData = CROP_ECONOMICS[normalizeCropKey(crop)]; + if (!baseData) { + return res.status(400).json({ + success: false, + error: "Invalid crop type", + }); + } + + const area = parseFloat(areaHa); + const yieldPerHa = expectedYield || baseData.yieldPerHa; + const pricePerKg = expectedPrice || baseData.pricePerKg; + const costs = inputCosts || baseData.inputCosts; + + // Calculate costs + const totalInputCost = Object.values(costs).reduce((a, b) => a + b, 0) * area; + const subsidyAmount = subsidy; + const effectiveCost = totalInputCost - subsidyAmount; + + // Calculate loan EMI if applicable + let loanEmi = 0; + let totalLoanPayment = 0; + if (loanAmount > 0) { + const monthlyRate = loanInterest / 100 / 12; + loanEmi = loanAmount * monthlyRate * Math.pow(1 + monthlyRate, loanTenure) / + (Math.pow(1 + monthlyRate, loanTenure) - 1); + totalLoanPayment = loanEmi * loanTenure; + } + + // Calculate revenue + const totalYield = yieldPerHa * area; + const grossRevenue = totalYield * pricePerKg; + + // Calculate profit + const netProfit = grossRevenue - effectiveCost - totalLoanPayment; + const roi = (netProfit / effectiveCost) * 100; + const breakEvenPrice = effectiveCost / totalYield; + + // Sensitivity analysis + const sensitivity = [-20, -10, 0, 10, 20].map(pct => { + const adjustedPrice = pricePerKg * (1 + pct / 100); + const adjustedRevenue = totalYield * adjustedPrice; + const adjustedProfit = adjustedRevenue - effectiveCost - totalLoanPayment; + return { + priceChange: pct, + price: adjustedPrice, + revenue: adjustedRevenue, + profit: adjustedProfit, + }; + }); + + res.json({ + success: true, + data: { + inputs: { + crop: baseData.name, + area, + yieldPerHa, + pricePerKg, + subsidy: subsidyAmount, + loanAmount, + }, + costs: { + inputCosts: costs, + totalInputCost, + subsidyAmount, + effectiveCost, + loanEmi: Math.round(loanEmi), + totalLoanPayment: Math.round(totalLoanPayment), + }, + revenue: { + totalYield, + grossRevenue, + }, + profitability: { + netProfit: Math.round(netProfit), + roi: Math.round(roi * 100) / 100, + profitPerHa: Math.round(netProfit / area), + breakEvenPrice: Math.round(breakEvenPrice * 100) / 100, + }, + sensitivity, + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /crop-economics/badges + * Get user's earned badges (gamification) + */ +router.get("/badges", verifyToken, async (req, res) => { + try { + const badges = await UserBadge.find({ userId: req.user._id }).sort("-earnedAt"); + + // Available badges + const availableBadges = [ + { type: "oilseed_champion", name: "Oilseed Champion", description: "Grew oilseeds for 3 consecutive seasons" }, + { type: "first_listing", name: "Market Ready", description: "Created first marketplace listing" }, + { type: "hedging_expert", name: "Hedging Expert", description: "Completed all hedging tutorials" }, + { type: "yield_optimizer", name: "Yield Optimizer", description: "Achieved above-average yields" }, + { type: "scheme_savvy", name: "Scheme Savvy", description: "Applied to 3 government schemes" }, + ]; + + const earnedBadgeTypes = badges.map(b => b.badgeType); + const unearned = availableBadges.filter(b => !earnedBadgeTypes.includes(b.type)); + + res.json({ + success: true, + data: { + earned: badges, + available: unearned, + totalPoints: badges.length * 100, + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /crop-economics/leaderboard + * Get regional leaderboard for gamification + */ +router.get("/leaderboard", async (req, res) => { + try { + const { region } = req.query; + + // Aggregate badges by user + const leaderboard = await UserBadge.aggregate([ + { + $group: { + _id: "$userId", + badgeCount: { $sum: 1 }, + points: { $sum: 100 }, + }, + }, + { $sort: { points: -1 } }, + { $limit: 20 }, + { + $lookup: { + from: "users", + localField: "_id", + foreignField: "_id", + as: "user", + }, + }, + { $unwind: { path: "$user", preserveNullAndEmptyArrays: true } }, + { + $project: { + userId: "$_id", + name: "$user.name", + badgeCount: 1, + points: 1, + }, + }, + ]); + + const ranked = await Promise.all(leaderboard.map(async (entry, index) => { + const profile = entry.userId + ? await FarmerProfile.findOne({ userId: entry.userId }).lean() + : null; + return { + rank: index + 1, + userId: entry.userId, + name: entry.name || "Anonymous Farmer", + badgeCount: entry.badgeCount, + points: entry.points, + acreageHa: profile?.acreageHa || 0, + }; + })); + + res.json({ + success: true, + data: { + leaderboard: ranked, + region: region || "All India", + lastUpdated: new Date().toISOString(), + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +router.post("/price-alerts/subscribe", verifyToken, async (req, res) => { + try { + const { commodity, region = "All India", priceAbove, priceBelow } = req.body || {}; + + if (!commodity) { + return res.status(400).json({ success: false, error: "commodity is required" }); + } + + if ((priceAbove == null || Number.isNaN(Number(priceAbove))) && (priceBelow == null || Number.isNaN(Number(priceBelow)))) { + return res.status(400).json({ success: false, error: "Set at least one of priceAbove or priceBelow" }); + } + + const alert = await PriceAlert.findOneAndUpdate( + { + userId: req.user._id, + commodity: commodity.toLowerCase(), + region, + }, + { + $set: { + commodity: commodity.toLowerCase(), + region, + priceAbove: priceAbove == null ? undefined : Number(priceAbove), + priceBelow: priceBelow == null ? undefined : Number(priceBelow), + enabled: true, + }, + }, + { upsert: true, new: true, setDefaultsOnInsert: true } + ); + + await Notification.create({ + userId: req.user._id, + title: "Price alert enabled", + message: `${alert.commodity} alert active for ${alert.region}`, + type: "price_alert", + link: "/crop_economics", + }); + + res.json({ success: true, data: alert }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +router.get("/price-alerts", verifyToken, async (req, res) => { + try { + const alerts = await PriceAlert.find({ userId: req.user._id, enabled: true }).sort("-updatedAt"); + res.json({ success: true, data: alerts }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +export default router; diff --git a/backend/routes/cropRotationRoutes.js b/backend/routes/cropRotationRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..cc420b55f1e57d813e898934693c4e3d12623624 --- /dev/null +++ b/backend/routes/cropRotationRoutes.js @@ -0,0 +1,9 @@ +import express from "express"; +import { cropRotationRecommendations } from "../controllers/cropRotationController.js"; +import { verifyToken } from "../middleware/jwt.js"; + +const router = express.Router(); + +router.post("/crop-rotation", verifyToken, cropRotationRecommendations); + +export default router; \ No newline at end of file diff --git a/backend/routes/cropRoutes.js b/backend/routes/cropRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..f164977d735b9d5b0d4da23c752f7fc8d76962ad --- /dev/null +++ b/backend/routes/cropRoutes.js @@ -0,0 +1,12 @@ +import express from 'express' +import { addCrop, getAllCrops, updateCrop } from '../controllers/cropController.js'; +import { verifyToken } from '../middleware/jwt.js'; + + +const router = express.Router(); + +router.get("/",verifyToken, getAllCrops); +router.post("/add",verifyToken, addCrop); +router.patch("/update/:id",verifyToken, updateCrop); + +export default router; diff --git a/backend/routes/cropicRoutes.js b/backend/routes/cropicRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..18e90ee51f81f2a2f3605a7fe1d2efcce50bc5a3 --- /dev/null +++ b/backend/routes/cropicRoutes.js @@ -0,0 +1,174 @@ +import express from "express"; +const router = express.Router(); + +/* ═══════════════════════════════════════════════════════════ + CROPIC β€” Crop Insurance (PMFBY) Module + Geo-tagged photo capture + AI damage assessment + ═══════════════════════════════════════════════════════════ */ + +import { CropicClaim } from "../utils/firestoreCollections.js"; + +const DAMAGE_TYPES = [ + "flood", "drought", "hailstorm", "pest_attack", "disease", + "frost", "cyclone", "excess_rain", "unseasonal_rain", "fire", +]; +const PMFBY_RATES = { + kharif: { premium_pct: 2.0, sum_insured_inr_ha: 40000 }, + rabi: { premium_pct: 1.5, sum_insured_inr_ha: 35000 }, + zaid: { premium_pct: 5.0, sum_insured_inr_ha: 30000 }, +}; + +/** + * POST /claims + * Create a new CROPIC insurance claim + */ +router.post("/claims", async (req, res) => { + try { + const { farmer_id, crop, season, area_hectares, policy_number, growth_stage } = req.body; + + if (!farmer_id || !crop) { + return res.status(400).json({ error: "farmer_id and crop are required" }); + } + + const claim = new CropicClaim({ + farmer_id, + crop, + season: season || "kharif", + area_hectares: area_hectares || 1, + policy_number, + growth_stage: growth_stage || "vegetative", + photos: [], + claim_status: "draft", + }); + + await claim.save(); + res.status(201).json({ success: true, claim }); + } catch (error) { + res.status(500).json({ error: "Failed to create claim", details: error.message }); + } +}); + +/** + * POST /claims/:id/photos + * Add a geo-tagged photo to an existing claim + */ +router.post("/claims/:id/photos", async (req, res) => { + try { + const { id } = req.params; + const { url, latitude, longitude, stage, image_base64 } = req.body; + + const claim = await CropicClaim.findById(id); + if (!claim) return res.status(404).json({ error: "Claim not found" }); + + // Simulate AI damage assessment + const assessment = simulateDamageAssessment(); + + const photo = { + url: url || `data:image/jpeg;base64,${image_base64?.substring(0, 20)}...`, + latitude: latitude || 0, + longitude: longitude || 0, + timestamp: new Date(), + stage: stage || claim.growth_stage, + damage_assessment: assessment, + }; + + claim.photos.push(photo); + + // Update damage summary if enough photos + if (claim.photos.length >= 3) { + const avgDamage = claim.photos.reduce((sum, p) => sum + (p.damage_assessment?.severity_pct || 0), 0) / claim.photos.length; + const rates = PMFBY_RATES[claim.season] || PMFBY_RATES.kharif; + const sumInsured = rates.sum_insured_inr_ha * claim.area_hectares; + const loss = Math.round(sumInsured * (avgDamage / 100)); + const compensation = Math.round(loss * 0.85); // 85% of loss + + claim.damage_summary = { + overall_damage_pct: Math.round(avgDamage), + estimated_loss_inr: loss, + eligible_compensation_inr: compensation, + primary_cause: assessment.damage_type, + }; + } + + await claim.save(); + res.json({ success: true, photo, claim }); + } catch (error) { + res.status(500).json({ error: "Failed to add photo", details: error.message }); + } +}); + +/** + * POST /claims/:id/submit + * Submit claim for review + */ +router.post("/claims/:id/submit", async (req, res) => { + try { + const claim = await CropicClaim.findById(req.params.id); + if (!claim) return res.status(404).json({ error: "Claim not found" }); + + if (claim.photos.length < 3) { + return res.status(400).json({ error: "Minimum 3 geo-tagged photos required" }); + } + + claim.claim_status = "submitted"; + claim.submitted_at = new Date(); + await claim.save(); + + res.json({ + success: true, + message: "Claim submitted for review", + claim_id: claim._id, + estimated_compensation: claim.damage_summary?.eligible_compensation_inr, + }); + } catch (error) { + res.status(500).json({ error: "Failed to submit claim", details: error.message }); + } +}); + +/** + * GET /claims/:farmer_id + * Get all claims for a farmer + */ +router.get("/claims/:farmer_id", async (req, res) => { + try { + const claims = await CropicClaim.find({ farmer_id: req.params.farmer_id }).sort({ createdAt: -1 }); + res.json({ success: true, claims }); + } catch (error) { + res.status(500).json({ error: "Failed to fetch claims", details: error.message }); + } +}); + +/** + * POST /assess-damage + * AI-based crop damage assessment from image + */ +router.post("/assess-damage", (req, res) => { + const assessment = simulateDamageAssessment(); + res.json({ success: true, assessment }); +}); + +/** + * GET /pmfby-rates + * Get PMFBY premium rates and coverage + */ +router.get("/pmfby-rates", (req, res) => { + res.json({ success: true, rates: PMFBY_RATES, damage_types: DAMAGE_TYPES }); +}); + +function simulateDamageAssessment() { + const damageType = DAMAGE_TYPES[Math.floor(Math.random() * DAMAGE_TYPES.length)]; + const severity = Math.round(Math.random() * 80 + 10); + return { + damage_type: damageType, + severity_pct: severity, + confidence: Math.round((0.7 + Math.random() * 0.25) * 100) / 100, + ai_model_version: "cropic-damage-v1.2", + details: { + affected_area_pct: severity, + growth_impact: severity > 50 ? "severe" : severity > 25 ? "moderate" : "mild", + recovery_possible: severity < 40, + }, + }; +} + +export default router; diff --git a/backend/routes/detectHarvestReadinessRoutes.js b/backend/routes/detectHarvestReadinessRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..908f0bca5ac3508dbdf2416ce783322733d7d1ca --- /dev/null +++ b/backend/routes/detectHarvestReadinessRoutes.js @@ -0,0 +1,9 @@ +import { Router } from "express"; +import { detectHarvestReadiness } from "../controllers/detectHarvestReadinessController.js"; +import { verifyToken } from "../middleware/jwt.js"; +import { uploadImageMemory } from "../middleware/multerMiddleware.js"; + +const router = Router(); + +router.post("/detect-harvest-readiness", verifyToken, uploadImageMemory.single("image"), detectHarvestReadiness); +export default router; \ No newline at end of file diff --git a/backend/routes/expertDetailsRoute.js b/backend/routes/expertDetailsRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..487c6deae3bd632bfb5b37a051df8fd59ceaee40 --- /dev/null +++ b/backend/routes/expertDetailsRoute.js @@ -0,0 +1,21 @@ +import express from 'express'; +import { verifyToken } from '../middleware/jwt.js'; +import {addExpertDetails, getExpertDetails, updateExpertDetails} from '../controllers/expertDetailsController.js' +import { getUserProfile } from '../controllers/authController.js'; + + + +const router = express.Router(); + +//profile route +router.get('/user/profile',verifyToken,getUserProfile) +// Get Expert Details (by userId from URL params) +router.get('/:userId',verifyToken, getExpertDetails); + +// Add Expert Details (automatically sets userId from authenticated user) +router.post('/', verifyToken, addExpertDetails); + +// Update Expert Details (by userId from URL params) +router.put('/:userId', verifyToken, updateExpertDetails); + +export default router; diff --git a/backend/routes/farmerDetailsRoute.js b/backend/routes/farmerDetailsRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..5bb2edadd49005a6fe4517953ce9afcdb067e63a --- /dev/null +++ b/backend/routes/farmerDetailsRoute.js @@ -0,0 +1,116 @@ +import express from 'express'; +import { verifyToken } from '../middleware/jwt.js'; +import { getUserProfile } from '../controllers/authController.js'; +import { addFarmerDetails, getFarmerDetails, updateFarmerDetails } from '../controllers/farmerDetailsController.js'; +import User from '../models/userModel.js'; +import { LANGUAGE_MAP } from '../utils/aiOrchestrator.js'; + +const router = express.Router(); + +// profile route +router.get('/user/profile', verifyToken, getUserProfile); + +/** + * POST /api/farmer-details/user/register-device + * Called by the frontend on every login / session restore. + * Upserts a device fingerprint into the user's Firestore-backed `devices` array. + * + * Body: { deviceId: string, label?: string } + * + * USER LOOKUP STRATEGY: + * - Firebase/Google users β†’ req.firebaseUser is set β†’ query by { firebaseUid: uid } + * - Email/password and Google users β†’ req.userId is the verified Firebase Auth UID. + * + * The old code always called findByIdAndUpdate(req.userId) which throws a + * CastError when req.userId is a Firebase UID (e.g. "RTpBuNkxSzREXZe1jmbQBnA6K6x1") + * because Firebase Auth identifiers are opaque UID strings. + */ +router.post('/user/register-device', verifyToken, async (req, res) => { + try { + const { deviceId, label } = req.body; + + if (!deviceId) { + return res.status(400).json({ error: 'deviceId is required' }); + } + + // Build the correct filter depending on auth method + let filter; + if (req.firebaseUser?.uid) { + // Google / Firebase OAuth path β€” user document is keyed by firebaseUid + filter = { firebaseUid: req.firebaseUser.uid }; + } else if (req.userId && Boolean(req.userId)) { + // Firebase Auth path β€” the user document is keyed by Firebase UID + filter = { _id: req.userId }; + } else { + // Neither path resolved β€” something is wrong with the token + return res.status(401).json({ error: 'Unable to identify user from token' }); + } + + // Pull any existing entry for this deviceId, then push a fresh one. + // This effectively upserts with updated label + lastSeen. + await User.findOneAndUpdate(filter, { $pull: { devices: { deviceId } } }); + await User.findOneAndUpdate(filter, { + $push: { + devices: { + deviceId, + label: label || 'Unknown Device', + lastSeen: new Date(), + }, + }, + }); + + const updated = await User.findOne(filter).select('devices'); + return res.json({ deviceCount: (updated?.devices || []).length }); + } catch (err) { + console.error('[register-device]', err); + return res.status(500).json({ error: 'Internal server error' }); + } +}); + +router.post('/user/preferences/language', verifyToken, async (req, res) => { + try { + const { language } = req.body; + const supportedLanguages = Object.keys(LANGUAGE_MAP); + + if (!supportedLanguages.includes(language)) { + return res.status(400).json({ message: 'Invalid language' }); + } + + let filter; + if (req.firebaseUser?.uid) { + filter = { firebaseUid: req.firebaseUser.uid }; + } else if (req.userId && Boolean(req.userId)) { + filter = { _id: req.userId }; + } else if (req.userEmail) { + filter = { email: req.userEmail }; + } else { + return res.status(401).json({ message: 'Unauthorized' }); + } + + const updatedUser = await User.findOneAndUpdate( + filter, + { language }, + { new: true }, + ); + + if (!updatedUser) { + return res.status(404).json({ message: 'User not found' }); + } + + return res.json({ success: true, language: updatedUser.language }); + } catch (err) { + console.error('[language-preference]', err); + return res.status(500).json({ message: 'Server error' }); + } +}); + +// get farmer details +router.get('/:userId', verifyToken, getFarmerDetails); + +// add farmer details +router.post('/', verifyToken, addFarmerDetails); + +// update farmer details +router.put('/:userId', verifyToken, updateFarmerDetails); + +export default router; diff --git a/backend/routes/farmingNewsRoute.js b/backend/routes/farmingNewsRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..ee142cf8e4b62f00141e34a4487838b1e4ca9a6c --- /dev/null +++ b/backend/routes/farmingNewsRoute.js @@ -0,0 +1,9 @@ +import express from 'express' +import { getFarmingNews } from '../controllers/farmingNewsController.js'; + + +const router = express.Router(); + +router.get('/farming_news', getFarmingNews); + +export default router; \ No newline at end of file diff --git a/backend/routes/firebaseAuthRoutes.js b/backend/routes/firebaseAuthRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..93b998aeefd20db9d6dca7a257d1fc43c4900dad --- /dev/null +++ b/backend/routes/firebaseAuthRoutes.js @@ -0,0 +1,24 @@ +import express from "express"; +import { verifyFirebaseToken } from "../middleware/firebaseAuth.js"; + +const router = express.Router(); + +/** + * POST /auth/verify-token + * Verify a Firebase ID token and return user profile & roles + */ +router.post("/verify-token", verifyFirebaseToken, (req, res) => { + res.status(200).json({ + success: true, + user: { + uid: req.firebaseUser.uid, + email: req.firebaseUser.email || null, + name: req.firebaseUser.name || null, + picture: req.firebaseUser.picture || null, + role: req.userRole, + emailVerified: req.firebaseUser.email_verified || false, + }, + }); +}); + +export default router; diff --git a/backend/routes/geoPestDiseaseHeatmapRoutes.js b/backend/routes/geoPestDiseaseHeatmapRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..e17f32c062743fa0f77b425fc6ec252843aee911 --- /dev/null +++ b/backend/routes/geoPestDiseaseHeatmapRoutes.js @@ -0,0 +1,9 @@ +import express from "express"; +import { geoPestDiseaseHeatmapRecommendations } from "../controllers/geoPestDiseaseHeatmapController.js"; +import { verifyToken } from "../middleware/jwt.js"; + +const router = express.Router(); + +router.post("/geo-pest-disease-heatmap", verifyToken, geoPestDiseaseHeatmapRecommendations); + +export default router; \ No newline at end of file diff --git a/backend/routes/geocodeRoutes.js b/backend/routes/geocodeRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..917c7ece46a1e20e3a9e968d400068f687cd7d10 --- /dev/null +++ b/backend/routes/geocodeRoutes.js @@ -0,0 +1,32 @@ +import express from "express"; +import axios from "axios"; + +const router = express.Router(); + +/** + * GET /api/geocode/reverse?lat=...&lon=... + * Proxy reverse geocoding requests to Nominatim to avoid CORS issues + */ +router.get("/reverse", async (req, res) => { + try { + const { lat, lon } = req.query; + if (!lat || !lon) { + return res.status(400).json({ error: "Missing required query parameters: lat and lon" }); + } + + const response = await axios.get("https://nominatim.openstreetmap.org/reverse", { + params: { format: "json", lat, lon }, + headers: { + "User-Agent": "AgroMind/1.0 (https://agro-mind-roan.vercel.app)", + }, + }); + + res.json(response.data); + } catch (error) { + console.error("Geocode proxy error:", error.message); + const status = error.response?.status || 502; + res.status(status).json({ error: "Failed to fetch geocoding data" }); + } +}); + +export default router; diff --git a/backend/routes/getExpertsRoute.js b/backend/routes/getExpertsRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..a7589fcbd17506628d9626db117435335e93b0fe --- /dev/null +++ b/backend/routes/getExpertsRoute.js @@ -0,0 +1,8 @@ +import express from 'express' +import { getExperts } from '../controllers/getExpertsController.js' + +const router = express.Router(); + +router.get('/experts', getExperts); + +export default router; \ No newline at end of file diff --git a/backend/routes/getLoanEligibilityReportRoutes.js b/backend/routes/getLoanEligibilityReportRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..7e7be26a4dcb28d0b67ec8487b22a3fd018fe0ca --- /dev/null +++ b/backend/routes/getLoanEligibilityReportRoutes.js @@ -0,0 +1,9 @@ +import express from "express"; +import { getLoanEligibilityReport } from "../controllers/getLoanEligibilityReportController.js"; +import { verifyToken } from "../middleware/jwt.js"; + +const router = express.Router(); + +router.post("/loan-eligibility-report", verifyToken, getLoanEligibilityReport); + +export default router; \ No newline at end of file diff --git a/backend/routes/hedgingRoutes.js b/backend/routes/hedgingRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..3d7ce5cb250bf6db33ca0407a0a02f4b575eaf5e --- /dev/null +++ b/backend/routes/hedgingRoutes.js @@ -0,0 +1,367 @@ +/** + * Hedging Platform Routes + * API endpoints for price risk management and virtual hedging + */ +import express from "express"; +import { verifyToken } from "../middleware/authMiddleware.js"; + +const router = express.Router(); + +import { HedgingPosition, MarketData, EducationModule, ForwardContract } from "../utils/firestoreCollections.js"; + +/** + * GET /hedging/market-data + * Get real-time and historical price feeds from MongoDB + */ +router.get("/market-data", async (req, res) => { + try { + const { commodity, period = "1M" } = req.query; + const selectedCommodity = commodity || "groundnut"; + + const periods = { "1W": 7, "1M": 30, "3M": 90, "6M": 180, "1Y": 365 }; + const days = periods[period] || 30; + const fromDate = new Date(Date.now() - days * 24 * 60 * 60 * 1000); + + const priceHistory = await MarketData.find({ + commodity: selectedCommodity, + date: { $gte: fromDate }, + }).sort("date").limit(500).lean(); + + const currentPrice = priceHistory.length > 0 + ? priceHistory[priceHistory.length - 1].close + : 0; + const previousClose = priceHistory.length > 1 + ? priceHistory[priceHistory.length - 2].close + : currentPrice; + const changePercent = previousClose !== 0 + ? ((currentPrice - previousClose) / previousClose) * 100 + : 0; + + const dayHigh = priceHistory.length > 0 + ? priceHistory[priceHistory.length - 1].high || currentPrice + : 0; + const dayLow = priceHistory.length > 0 + ? priceHistory[priceHistory.length - 1].low || currentPrice + : 0; + const volume = priceHistory.length > 0 + ? priceHistory[priceHistory.length - 1].volume || 0 + : 0; + + res.json({ + success: true, + data: { + commodity: selectedCommodity, + currentPrice: Math.round(currentPrice), + previousClose: Math.round(previousClose), + change: Math.round(currentPrice - previousClose), + changePercent: Math.round(changePercent * 100) / 100, + dayHigh: Math.round(dayHigh), + dayLow: Math.round(dayLow), + volume, + priceHistory: priceHistory.map(p => ({ + date: p.date.toISOString().split("T")[0], + open: p.open, + high: p.high, + low: p.low, + close: p.close, + volume: p.volume, + })), + lastUpdated: new Date().toISOString(), + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * POST /hedging/create-forward + * Create a forward sale contract + */ +router.post("/create-forward", verifyToken, async (req, res) => { + try { + const { buyerId, commodity, quantity, price, deliveryDate, terms } = req.body; + + if (!commodity || !quantity || !price || !deliveryDate) { + return res.status(400).json({ + success: false, + error: "Missing required fields: commodity, quantity, price, deliveryDate", + }); + } + + const contract = new ForwardContract({ + sellerId: req.user._id, + buyerId: buyerId || null, + commodity, + quantity, + price, + deliveryDate: new Date(deliveryDate), + terms: terms || {}, + status: buyerId ? "pending" : "draft", + }); + + await contract.save(); + + res.status(201).json({ + success: true, + data: contract, + message: "Forward contract created successfully", + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * POST /hedging/simulate-hedge + * Simulate hedging positions with price scenarios + */ +router.post("/simulate-hedge", verifyToken, async (req, res) => { + try { + const { + commodity, + quantity, + positionType, + entryPrice, + scenarios + } = req.body; + + if (!commodity || !quantity || !positionType || !entryPrice) { + return res.status(400).json({ + success: false, + error: "Missing required fields", + }); + } + + const defaultScenarios = [ + { name: "Bear Case (-20%)", priceChange: -0.20 }, + { name: "Mild Bear (-10%)", priceChange: -0.10 }, + { name: "Neutral (0%)", priceChange: 0 }, + { name: "Mild Bull (+10%)", priceChange: 0.10 }, + { name: "Bull Case (+20%)", priceChange: 0.20 }, + ]; + + const scenariosToUse = scenarios || defaultScenarios; + + const results = scenariosToUse.map(scenario => { + const exitPrice = entryPrice * (1 + scenario.priceChange); + let pnl; + + if (positionType === "long") { + pnl = (exitPrice - entryPrice) * quantity; + } else { + pnl = (entryPrice - exitPrice) * quantity; + } + + const pnlPercent = (pnl / (entryPrice * quantity)) * 100; + + return { + scenario: scenario.name, + priceChange: scenario.priceChange * 100, + exitPrice: Math.round(exitPrice * 100) / 100, + pnl: Math.round(pnl * 100) / 100, + pnlPercent: Math.round(pnlPercent * 100) / 100, + }; + }); + + // Calculate expected value (assuming equal probability) + const expectedPnl = results.reduce((sum, r) => sum + r.pnl, 0) / results.length; + const maxLoss = Math.min(...results.map(r => r.pnl)); + const maxProfit = Math.max(...results.map(r => r.pnl)); + + res.json({ + success: true, + data: { + position: { + commodity, + quantity, + positionType, + entryPrice, + notionalValue: entryPrice * quantity, + }, + scenarios: results, + summary: { + expectedPnl: Math.round(expectedPnl * 100) / 100, + maxLoss: Math.round(maxLoss * 100) / 100, + maxProfit: Math.round(maxProfit * 100) / 100, + riskRewardRatio: Math.abs(maxProfit / maxLoss) || 0, + }, + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /hedging/positions + * Get user's hedging positions + */ +router.get("/positions", verifyToken, async (req, res) => { + try { + const { status = "open" } = req.query; + + const positions = await HedgingPosition.find({ + userId: req.user._id, + ...(status !== "all" && { status }), + }).sort("-createdAt"); + + // Calculate total P&L + const totalPnl = positions.reduce((sum, pos) => sum + (pos.pnl || 0), 0); + + res.json({ + success: true, + data: { + positions, + summary: { + totalPositions: positions.length, + totalPnl: Math.round(totalPnl * 100) / 100, + openPositions: positions.filter(p => p.status === "open").length, + }, + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * POST /hedging/open-position + * Open a virtual hedging position + */ +router.post("/open-position", verifyToken, async (req, res) => { + try { + const { commodity, positionType, quantity, entryPrice, stopLoss, takeProfit } = req.body; + + if (!commodity || !positionType || !quantity || !entryPrice) { + return res.status(400).json({ + success: false, + error: "Missing required fields", + }); + } + + const position = new HedgingPosition({ + userId: req.user._id, + commodity, + positionType, + quantity, + entryPrice, + currentPrice: entryPrice, + stopLoss, + takeProfit, + }); + + await position.save(); + + res.status(201).json({ + success: true, + data: position, + message: "Position opened successfully", + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * POST /hedging/close-position/:id + * Close a virtual hedging position + */ +router.post("/close-position/:id", verifyToken, async (req, res) => { + try { + const { id } = req.params; + const { closingPrice } = req.body; + + const position = await HedgingPosition.findOne({ + _id: id, + userId: req.user._id, + status: "open", + }); + + if (!position) { + return res.status(404).json({ + success: false, + error: "Position not found or already closed", + }); + } + + const exitPrice = closingPrice || position.currentPrice; + let pnl; + + if (position.positionType === "long") { + pnl = (exitPrice - position.entryPrice) * position.quantity; + } else { + pnl = (position.entryPrice - exitPrice) * position.quantity; + } + + const pnlPercent = (pnl / (position.entryPrice * position.quantity)) * 100; + + position.status = "closed"; + position.closedAt = new Date(); + position.closingPrice = exitPrice; + position.pnl = pnl; + position.pnlPercent = pnlPercent; + + await position.save(); + + res.json({ + success: true, + data: position, + message: `Position closed with ${pnl >= 0 ? "profit" : "loss"} of β‚Ή${Math.abs(pnl).toFixed(2)}`, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /hedging/education + * Get educational content for financial literacy from MongoDB + */ +router.get("/education", async (req, res) => { + try { + const modules = await EducationModule.find({}).sort("order").lean(); + + res.json({ + success: true, + data: { + modules, + totalModules: modules.length, + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /hedging/contracts + * Get user's forward contracts + */ +router.get("/contracts", verifyToken, async (req, res) => { + try { + const { role = "seller", status } = req.query; + + const query = role === "seller" + ? { sellerId: req.user._id } + : { buyerId: req.user._id }; + + if (status) { + query.status = status; + } + + const contracts = await ForwardContract.find(query) + .populate("sellerId", "name email") + .populate("buyerId", "name email") + .sort("-createdAt"); + + res.json({ + success: true, + data: contracts, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +export default router; diff --git a/backend/routes/irrigationRoute.js b/backend/routes/irrigationRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..aac10276079090b8d9a97369716e335f0b77aec0 --- /dev/null +++ b/backend/routes/irrigationRoute.js @@ -0,0 +1,14 @@ +// routes/irrigation.js +import express from 'express'; +import { addIrrigationData, getAllIrrigationDataByCrop } from '../controllers/irrigationController.js'; +import { verifyToken } from '../middleware/jwt.js'; + +const router = express.Router(); + +// Dynamic route to add irrigation data for a specific crop +router.post("/:cropId/add",verifyToken, addIrrigationData); + +// Route to get all irrigation data for a specific crop +router.get("/:cropId",verifyToken, getAllIrrigationDataByCrop); + +export default router; diff --git a/backend/routes/mandiRoutes.js b/backend/routes/mandiRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..3a825906496a70d573084184a4b97a4ff50bc094 --- /dev/null +++ b/backend/routes/mandiRoutes.js @@ -0,0 +1,136 @@ +import express from "express"; + +const router = express.Router(); + +// Simulated AGMARKNET data store +const generateMandiData = (commodity, market, days) => { + const prices = []; + const basePrice = { + wheat: 2200, rice: 2800, groundnut: 5500, soybean: 4200, + mustard: 5100, cotton: 6500, onion: 1800, potato: 1200, + tomato: 2500, maize: 1900, bajra: 2100, jowar: 2800, + ragi: 3200, moong: 7500, urad: 7000, tur: 6800, + chana: 5200, sugar: 3600, jute: 4800, turmeric: 8500, + }[commodity?.toLowerCase()] || 3000; + + const now = Date.now(); + for (let i = days - 1; i >= 0; i--) { + const date = new Date(now - i * 86400000); + const variation = (Math.random() - 0.5) * basePrice * 0.08; + const trend = (days - i) * basePrice * 0.001; + const price = Math.round(basePrice + variation + trend); + + prices.push({ + date: date.toISOString().split("T")[0], + modal_price: price, + min_price: Math.round(price * 0.92), + max_price: Math.round(price * 1.08), + arrivals_tonnes: Math.round(50 + Math.random() * 500), + }); + } + return prices; +}; + +/** + * GET /mandi/prices + * Get mandi prices for a commodity + */ +router.get("/prices", (req, res) => { + const { commodity, market, state, days } = req.query; + + if (!commodity) { + return res.status(400).json({ success: false, message: "commodity is required" }); + } + + const numDays = Math.min(parseInt(days) || 30, 90); + const marketName = market || "Azadpur"; + const stateName = state || "Delhi"; + + const prices = generateMandiData(commodity, marketName, numDays); + + const modalPrices = prices.map((p) => p.modal_price); + const avg = Math.round(modalPrices.reduce((a, b) => a + b, 0) / modalPrices.length); + + res.json({ + success: true, + commodity: commodity.charAt(0).toUpperCase() + commodity.slice(1), + market: marketName, + state: stateName, + period: `${numDays} days`, + prices, + statistics: { + average: avg, + min: Math.min(...modalPrices), + max: Math.max(...modalPrices), + latest: modalPrices[modalPrices.length - 1], + trend: modalPrices[modalPrices.length - 1] > modalPrices[0] ? "rising" : "falling", + change_pct: parseFloat( + (((modalPrices[modalPrices.length - 1] - modalPrices[0]) / modalPrices[0]) * 100).toFixed(2) + ), + }, + source: "AGMARKNET Adapter", + }); +}); + +/** + * GET /mandi/commodities + * List available commodities + */ +router.get("/commodities", (_req, res) => { + res.json({ + success: true, + commodities: [ + { id: "wheat", name: "Wheat", category: "Cereal" }, + { id: "rice", name: "Rice", category: "Cereal" }, + { id: "maize", name: "Maize", category: "Cereal" }, + { id: "bajra", name: "Bajra (Pearl Millet)", category: "Millet" }, + { id: "jowar", name: "Jowar (Sorghum)", category: "Millet" }, + { id: "ragi", name: "Ragi (Finger Millet)", category: "Millet" }, + { id: "groundnut", name: "Groundnut", category: "Oilseed" }, + { id: "soybean", name: "Soybean", category: "Oilseed" }, + { id: "mustard", name: "Mustard", category: "Oilseed" }, + { id: "cotton", name: "Cotton", category: "Cash Crop" }, + { id: "sugar", name: "Sugarcane", category: "Cash Crop" }, + { id: "jute", name: "Jute", category: "Cash Crop" }, + { id: "turmeric", name: "Turmeric", category: "Spice" }, + { id: "onion", name: "Onion", category: "Vegetable" }, + { id: "potato", name: "Potato", category: "Vegetable" }, + { id: "tomato", name: "Tomato", category: "Vegetable" }, + { id: "moong", name: "Moong Dal", category: "Pulse" }, + { id: "urad", name: "Urad Dal", category: "Pulse" }, + { id: "tur", name: "Tur Dal", category: "Pulse" }, + { id: "chana", name: "Chana", category: "Pulse" }, + ], + }); +}); + +/** + * GET /mandi/markets + * List available markets + */ +router.get("/markets", (req, res) => { + const { state } = req.query; + + const allMarkets = [ + { name: "Azadpur", state: "Delhi", district: "New Delhi" }, + { name: "Vashi", state: "Maharashtra", district: "Navi Mumbai" }, + { name: "Yeshwanthpur", state: "Karnataka", district: "Bangalore" }, + { name: "Koyambedu", state: "Tamil Nadu", district: "Chennai" }, + { name: "Bowenpally", state: "Telangana", district: "Hyderabad" }, + { name: "Gultekdi", state: "Maharashtra", district: "Pune" }, + { name: "Lasalgaon", state: "Maharashtra", district: "Nashik" }, + { name: "Rajkot", state: "Gujarat", district: "Rajkot" }, + { name: "Indore", state: "Madhya Pradesh", district: "Indore" }, + { name: "Ludhiana", state: "Punjab", district: "Ludhiana" }, + { name: "Patna", state: "Bihar", district: "Patna" }, + { name: "Kolkata", state: "West Bengal", district: "Kolkata" }, + { name: "Bhubaneswar", state: "Odisha", district: "Khurda" }, + { name: "Guwahati", state: "Assam", district: "Kamrup" }, + ]; + + const filtered = state ? allMarkets.filter((m) => m.state.toLowerCase() === state.toLowerCase()) : allMarkets; + + res.json({ success: true, markets: filtered }); +}); + +export default router; diff --git a/backend/routes/marketPredictionRoutes.js b/backend/routes/marketPredictionRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..aafc1c44e012141b7e4cb91f5dfecad6b6ca5d0d --- /dev/null +++ b/backend/routes/marketPredictionRoutes.js @@ -0,0 +1,9 @@ +import express from "express"; +import { marketPredictionRecommendations } from "../controllers/marketPredictionController.js"; +import { verifyToken } from "../middleware/jwt.js"; + +const router = express.Router(); + +router.post("/market-prediction", verifyToken, marketPredictionRecommendations); + +export default router; \ No newline at end of file diff --git a/backend/routes/milletRoutes.js b/backend/routes/milletRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..0d5878c06efb850f4774d9946c4173195bc1698d --- /dev/null +++ b/backend/routes/milletRoutes.js @@ -0,0 +1,394 @@ +/** + * Millets Value Chain Routes + * Marketplace and traceability for millets with offline-first support + */ +import express from "express"; +import { verifyToken, optionalAuth } from "../middleware/authMiddleware.js"; + +const router = express.Router(); + +import { MilletListing, QualityCertification, MilletType } from "../utils/firestoreCollections.js"; + +// --------------------------------------------------------------------------- +// Shared listings query handler (GET /listings, /catalog, /list) +// --------------------------------------------------------------------------- +async function getListings(req, res) { + try { + const { + milletType, lat, lng, radius = 50, minPrice, maxPrice, + grade, organic, status = "active", sort = "-createdAt", + page = 1, limit = 20, + } = req.query; + + const query = { status }; + if (milletType) query.milletType = milletType; + if (grade) query.grade = grade; + if (organic === "true") { + query["certifications.type"] = "organic"; + query["certifications.verified"] = true; + } + if (lat && lng) { + query.location = { + $near: { + $geometry: { type: "Point", coordinates: [parseFloat(lng), parseFloat(lat)] }, + $maxDistance: parseFloat(radius) * 1000, + }, + }; + } + if (minPrice || maxPrice) { + query.price = {}; + if (minPrice) query.price.$gte = parseFloat(minPrice); + if (maxPrice) query.price.$lte = parseFloat(maxPrice); + } + + const skip = (parseInt(page) - 1) * parseInt(limit); + const [listings, total] = await Promise.all([ + MilletListing.find(query) + .populate("sellerId", "name phone") + .sort(sort).skip(skip).limit(parseInt(limit)).lean(), + MilletListing.countDocuments(query), + ]); + + // Normalised catalog shape for the frontend card renderer. + // IMPORTANT: always expose sellerFirebaseUid so the "My Listings" filter + // on the frontend (which compares against Firebase user.uid) works correctly + // for users who have a linked MongoDB account. + const catalog = listings.map(l => ({ + _id: l._id, + name: l.productName, + seller: l.sellerId?.name || "Farmer", + sellerId: l.sellerId?._id || l.sellerId || null, + sellerFirebaseUid: l.sellerFirebaseUid || null, + price: l.price, + unit: "kg", + organic: l.organicCertified || (l.certifications || []).some(c => c.type === "organic" && c.verified), + rating: "4.5", + milletType: l.milletType, + quantityKg: l.availableQuantityKg, + location: l.location?.address || "", + })); + + res.json({ + success: true, + catalog, + data: listings, + pagination: { total, page: parseInt(page), limit: parseInt(limit), pages: Math.ceil(total / parseInt(limit)) }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +} + +// --------------------------------------------------------------------------- +// Shared create listing handler (POST /listings, /list) +// --------------------------------------------------------------------------- +async function createListing(req, res) { + try { + const body = req.body; + + // Accept both snake_case (frontend form) and camelCase (API clients) + const milletType = body.milletType || body.millet_type; + const quantityKg = body.quantityKg || body.quantity_kg; + const price = body.price || body.price_per_kg; + const locationText = typeof body.location === "string" ? body.location : body.location?.address; + const organicCertified = body.organicCertified !== undefined + ? body.organicCertified + : (body.organic_certified || false); + + if (!milletType || !quantityKg || !price) { + return res.status(400).json({ + success: false, + error: "milletType (or millet_type), quantityKg (or quantity_kg), and price (or price_per_kg) are required", + }); + } + + const mongoId = req.user?._id; + + // FIX: Always store the Firebase UID when available, regardless of whether + // a MongoDB user record was also found. Previously this was only stored when + // mongoId was absent, causing "My Listings" to show empty for Firebase users + // whose accounts are linked to a MongoDB document. + const firebaseUid = req.userId || undefined; + + // Build location carefully: + // [lng, lat] supplied β†’ full GeoJSON Point (geo-indexed) + // text string only β†’ {address} only, no type/coordinates (index skips it) + // nothing β†’ omit field entirely + let locationData; + if (body.location?.coordinates?.length === 2) { + locationData = { + type: "Point", + coordinates: body.location.coordinates, + address: body.location.address || locationText || "", + }; + } else if (locationText) { + locationData = { address: locationText }; + } + + const listing = new MilletListing({ + ...(mongoId ? { sellerId: mongoId } : {}), + ...(firebaseUid ? { sellerFirebaseUid: firebaseUid } : {}), + milletType, + quantityKg: Number(quantityKg), + availableQuantityKg: body.availableQuantityKg || Number(quantityKg), + price: Number(price), + organicCertified, + ...(locationData ? { location: locationData } : {}), + productName: body.productName || + (milletType.charAt(0).toUpperCase() + milletType.slice(1)).replace(/_/g, " "), + description: body.description || "", + }); + + await listing.save(); + + res.status(201).json({ success: true, data: listing, message: "Listing created successfully" }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +} + +// --------------------------------------------------------------------------- +// Routes +// --------------------------------------------------------------------------- + +/** GET /millets/listings | /millets/catalog | /millets/list */ +router.get("/listings", getListings); +router.get("/catalog", getListings); +router.get("/list", getListings); + +/** POST /millets/listings (authenticated) */ +router.post("/listings", verifyToken, createListing); + +/** POST /millets/list (optional auth β€” frontend Sell tab uses this) */ +router.post("/list", optionalAuth, createListing); + +/** + * DELETE /millets/list/:id + * DELETE /millets/listings/:id + * Farmer deletes their own listing. No auth token required if sellerFirebaseUid + * matches req.userId; falls back to MongoDB sellerId comparison. + */ +async function deleteListing(req, res) { + try { + const listing = await MilletListing.findById(req.params.id); + if (!listing) { + return res.status(404).json({ success: false, error: "Listing not found" }); + } + + const mongoId = req.user?._id?.toString(); + const firebaseUid = req.userId; + + const ownsListing = + (mongoId && listing.sellerId?.toString() === mongoId) || + (firebaseUid && listing.sellerFirebaseUid === firebaseUid) || + // Allow deletion when listing was created without auth (both IDs null) + (!listing.sellerId && !listing.sellerFirebaseUid); + + if (!ownsListing) { + return res.status(403).json({ success: false, error: "You can only delete your own listings" }); + } + + await MilletListing.findByIdAndDelete(req.params.id); + res.json({ success: true, message: "Listing deleted successfully" }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +} + +router.delete("/list/:id", optionalAuth, deleteListing); +router.delete("/listings/:id", optionalAuth, deleteListing); + +/** GET /millets/listings/:id */ +router.get("/listings/:id", async (req, res) => { + try { + const listing = await MilletListing.findById(req.params.id) + .populate("sellerId", "name phone email"); + if (!listing) return res.status(404).json({ success: false, error: "Listing not found" }); + res.json({ success: true, data: listing }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /millets/traceability/:id + * GET /millets/trace/:id (alias used by frontend) + */ +async function traceHandler(req, res) { + try { + const listing = await MilletListing.findById(req.params.id) + .select("traceability milletType productName certifications sellerId location createdAt") + .populate("sellerId", "name"); + if (!listing) return res.status(404).json({ success: false, error: "Listing not found" }); + + const journey = [ + { + step: "Farm Harvest", + date: listing.traceability?.sowingDate + ? new Date(listing.traceability.sowingDate).toLocaleDateString() + : new Date(listing.createdAt).toLocaleDateString(), + location: listing.location?.address || "Farm", + details: `Variety: ${listing.traceability?.seedVariety || "N/A"} | Irrigation: ${listing.traceability?.irrigationType || "N/A"}`, + }, + { + step: "Processing", + date: new Date(listing.createdAt).toLocaleDateString(), + location: listing.traceability?.processingUnit || "Local Processing Unit", + details: `Batch: ${listing.traceability?.batchNumber || "N/A"} | Fertilizer: ${listing.traceability?.fertilizerUsed || "N/A"}`, + }, + { + step: "Listed on AgroMind Marketplace", + date: new Date(listing.createdAt).toLocaleDateString(), + location: listing.location?.address || "Marketplace", + details: `Listed by: ${listing.sellerId?.name || "Farmer"}`, + }, + ]; + + res.json({ + success: true, + journey, + product: { type: listing.milletType, name: listing.productName }, + producer: { name: listing.sellerId?.name }, + traceability: listing.traceability, + certifications: listing.certifications?.filter(c => c.verified), + qrCode: `https://agro-mind-roan.vercel.app/millets_marketplace?trace=${listing._id}`, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +} + +router.get("/traceability/:id", traceHandler); +router.get("/trace/:id", traceHandler); + +/** POST /millets/certifications */ +router.post("/certifications", verifyToken, async (req, res) => { + try { + const { processorType, certificationType, certificateNumber, issuingAuthority, + issueDate, expiryDate, products, documents } = req.body; + + if (!certificationType) { + return res.status(400).json({ success: false, error: "certificationType is required" }); + } + const mongoId = req.user?._id; + if (!mongoId) { + return res.status(400).json({ success: false, error: "A registered account is required to submit certifications." }); + } + + const certification = new QualityCertification({ + processorId: mongoId, processorType, certificationType, certificateNumber, + issuingAuthority, + issueDate: issueDate ? new Date(issueDate) : undefined, + expiryDate: expiryDate ? new Date(expiryDate) : undefined, + products, documents, + }); + await certification.save(); + res.status(201).json({ success: true, data: certification, message: "Certification submitted for verification" }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** GET /millets/certifications */ +router.get("/certifications", verifyToken, async (req, res) => { + try { + const mongoId = req.user?._id; + if (!mongoId) return res.status(400).json({ success: false, error: "A registered account is required." }); + const certifications = await QualityCertification.find({ processorId: mongoId }).sort("-createdAt"); + res.json({ success: true, data: certifications }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** GET /millets/millet-types */ +router.get("/millet-types", async (req, res) => { + try { + const milletTypes = await MilletType.find({}).lean(); + res.json({ + success: true, + data: milletTypes.map(m => ({ + id: m.milletId, + name: m.name, + localNames: m.localNames instanceof Map ? Object.fromEntries(m.localNames) : (m.localNames || {}), + nutritionFacts: m.nutritionFacts || {}, + })), + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** GET /millets/sync-data */ +router.get("/sync-data", optionalAuth, async (req, res) => { + try { + const { lastSync } = req.query; + const lastSyncDate = lastSync ? new Date(lastSync) : new Date(0); + const listings = await MilletListing.find({ status: "active", updatedAt: { $gt: lastSyncDate } }) + .select("_id milletType productName price quantityKg location status updatedAt") + .limit(100).lean(); + const milletTypes = await MilletType.find({}).select("milletId name").lean(); + res.json({ + success: true, + data: { + listings, + milletTypes: milletTypes.map(m => ({ id: m.milletId, name: m.name })), + syncedAt: new Date().toISOString(), + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** POST /millets/offline-actions */ +router.post("/offline-actions", verifyToken, async (req, res) => { + try { + const { actions } = req.body; + if (!Array.isArray(actions)) { + return res.status(400).json({ success: false, error: "actions must be an array" }); + } + const results = []; + const mongoId = req.user?._id; + // FIX: always capture the Firebase UID when present + const firebaseUid = req.userId || undefined; + + for (const action of actions) { + try { + switch (action.type) { + case "create_listing": { + const listing = new MilletListing({ + ...(mongoId ? { sellerId: mongoId } : {}), + ...(firebaseUid ? { sellerFirebaseUid: firebaseUid } : {}), + ...action.data, + availableQuantityKg: action.data.quantityKg, + }); + await listing.save(); + results.push({ actionId: action.id, success: true, data: listing._id }); + break; + } + case "update_listing": + await MilletListing.findByIdAndUpdate(action.data.id, action.data.updates); + results.push({ actionId: action.id, success: true }); + break; + default: + results.push({ actionId: action.id, success: false, error: "Unknown action type" }); + } + } catch (err) { + results.push({ actionId: action.id, success: false, error: err.message }); + } + } + res.json({ + success: true, + data: { + processed: results.filter(r => r.success).length, + failed: results.filter(r => !r.success).length, + results, + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +export default router; diff --git a/backend/routes/mlRoutes.js b/backend/routes/mlRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..b8e23ef5fa1b042c7eb7500d8defa2a4fe8f0620 --- /dev/null +++ b/backend/routes/mlRoutes.js @@ -0,0 +1,647 @@ +import express from "express"; +import multer from "multer"; +import { mkdirSync } from "fs"; +import { promises as fs } from "fs"; +import os from "os"; +import path from "path"; +import crypto from "crypto"; + +const router = express.Router(); + +const HF_API_BASE = "https://api-inference.huggingface.co/models"; +const HF_TIMEOUT_MS = 120_000; +const HF_POLL_RETRIES = 2; +const MIN_RETRY_WAIT_SECONDS = 1; +const MAX_RETRY_WAIT_SECONDS = 15; +const HF_NETWORK_RETRY_COUNT = 3; +const HF_NETWORK_RETRY_BASE_MS = 1000; +const MAX_FILE_SIZE_BYTES = 10 * 1024 * 1024; +const WALNUT_SEQUENCE_LENGTH = 30; +const uploadDirectory = path.join(os.tmpdir(), "agromind-ml-uploads"); + +mkdirSync(uploadDirectory, { recursive: true }); + +const upload = multer({ + storage: multer.diskStorage({ + destination: (_req, _file, cb) => cb(null, uploadDirectory), + filename: (_req, file, cb) => { + const safeName = (file.originalname || "upload.bin").replace(/[^a-zA-Z0-9._-]/g, "_"); + cb(null, `${Date.now()}-${crypto.randomUUID()}-${safeName}`); + }, + }), + limits: { + fileSize: MAX_FILE_SIZE_BYTES, + }, +}); + +const HF_MODELS = { + saffron: "Arko007/saffron-verify-pretrained", + walnutDefect: "Arko007/walnut-defect-classifier", + walnutRancidity: "Arko007/walnut-rancidity-predictor", + applePrice: "Arko007/apple-price-predictor", +}; + +const normalizeUrl = (value) => value?.trim().replace(/\/$/, ""); + +const buildFallbackAiBackendUrl = () => { + const spaceHost = process.env.SPACE_HOST; + + if (!spaceHost?.trim()) { + return null; + } + + const inferredHost = spaceHost + .trim() + .replace(/-backend(\.hf\.space)$/i, "-ai-backend$1"); + + if (inferredHost === spaceHost.trim()) { + return null; + } + + return `https://${inferredHost}`; +}; + +const getAiBackendCandidates = () => { + const configured = normalizeUrl(process.env.AI_BACKEND_URL); + const fallback = normalizeUrl(buildFallbackAiBackendUrl()); + + return [...new Set([configured, fallback].filter(Boolean))]; +}; + +const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + +/** Returns true when the error is a network/DNS-level failure (not an HTTP error). */ +const isNetworkError = (error) => { + const code = error.cause?.code || error.code; + return ["ENOTFOUND", "ETIMEDOUT", "ECONNRESET", "ECONNREFUSED"].includes(code) || + error.name === "AbortError"; +}; + +const fetchWithTimeout = async (url, options = {}) => { + if (typeof AbortController === "undefined") { + return Promise.race([ + fetch(url, options), + new Promise((_, reject) => + setTimeout(() => reject(new Error(`Request timeout after ${HF_TIMEOUT_MS}ms`)), HF_TIMEOUT_MS) + ), + ]); + } + + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), HF_TIMEOUT_MS); + + try { + return await fetch(url, { ...options, signal: controller.signal }); + } finally { + clearTimeout(timer); + } +}; + +const parseResponseBody = async (response) => { + const contentType = response.headers?.get?.("content-type") || ""; + const text = await response.text(); + + if (!text) { + return {}; + } + + if (contentType.includes("application/json")) { + return JSON.parse(text); + } + + try { + return JSON.parse(text); + } catch (_error) { + return { raw: text }; + } +}; + +const getAuthorizationHeaders = () => { + const token = process.env.HF_API_TOKEN?.trim(); + return token ? { Authorization: `Bearer ${token}` } : {}; +}; + +const extractUploadedFile = (req) => { + if (req.file) return req.file; + + const imageFile = req.files?.image?.[0]; + if (imageFile) return imageFile; + + const legacyFile = req.files?.file?.[0]; + if (legacyFile) return legacyFile; + + return null; +}; + +const getUniqueFilesByPath = (files) => + [...new Map(files.filter(Boolean).map((file) => [file.path, file])).values()]; + +const cleanupUploadedFiles = async (req) => { + const files = []; + + if (req.file) { + files.push(req.file); + } + + if (req.files && typeof req.files === "object") { + Object.values(req.files) + .flat() + .forEach((file) => files.push(file)); + } + + await Promise.all( + getUniqueFilesByPath(files).map(async (file) => { + if (!file?.path) return; + try { + await fs.unlink(file.path); + } catch (_error) { + // best-effort temp-file cleanup, ignore failures + } + }) + ); +}; + +const toNumeric = (value, fallback) => { + const parsed = Number(value); + return Number.isFinite(parsed) ? parsed : fallback; +}; + +const linspace = (start, end, count) => { + if (count <= 0) { + throw new Error("linspace count must be positive"); + } + if (count === 1) return [start]; + const step = (end - start) / (count - 1); + return Array.from({ length: count }, (_, index) => Number((start + (step * index)).toFixed(6))); +}; + +const buildWalnutSequence = (payload = {}) => { + if (Array.isArray(payload.sequence)) { + const sequence = payload.sequence.map((row) => { + if (!Array.isArray(row) || row.length !== 8) { + throw new Error("sequence must contain rows with exactly 8 numeric features"); + } + + const normalizedRow = row.map((value) => Number(value)); + if (normalizedRow.some((value) => !Number.isFinite(value))) { + throw new Error("sequence values must be numeric"); + } + return normalizedRow; + }); + + if (sequence.length === 0) { + throw new Error("sequence must contain at least one row"); + } + + return sequence; + } + + const storageDays = Math.max(0, toNumeric(payload.storage_days, 30)); + const temperature = toNumeric(payload.temperature, 5); + const humidity = toNumeric(payload.humidity, 50); + const moisture = toNumeric(payload.moisture, 4); + const oxygen = toNumeric(payload.oxygen, 0.2); + + const peroxideStart = toNumeric(payload.peroxide_value_start ?? payload.peroxide_value, 0.5); + const peroxideEnd = toNumeric( + payload.peroxide_value_end, + Number((peroxideStart + Math.max(0.3, storageDays * 0.05)).toFixed(4)) + ); + const ffaStart = toNumeric(payload.free_fatty_acids_start ?? payload.free_fatty_acids, 0.05); + const ffaEnd = toNumeric( + payload.free_fatty_acids_end, + Number((ffaStart + Math.max(0.02, storageDays * 0.005)).toFixed(4)) + ); + const hexanalStart = toNumeric(payload.hexanal_level_start ?? payload.hexanal_level, 0.1); + const hexanalEnd = toNumeric( + payload.hexanal_level_end, + Number((hexanalStart + Math.max(0.1, storageDays * 0.02)).toFixed(4)) + ); + const oxidationStart = toNumeric(payload.oxidation_index_start ?? payload.oxidation_index, 0.2); + const oxidationEnd = toNumeric( + payload.oxidation_index_end, + Number((oxidationStart + Math.max(0.15, storageDays * 0.03)).toFixed(4)) + ); + + const peroxideSeries = linspace(peroxideStart, peroxideEnd, WALNUT_SEQUENCE_LENGTH); + const ffaSeries = linspace(ffaStart, ffaEnd, WALNUT_SEQUENCE_LENGTH); + const hexanalSeries = linspace(hexanalStart, hexanalEnd, WALNUT_SEQUENCE_LENGTH); + const oxidationSeries = linspace(oxidationStart, oxidationEnd, WALNUT_SEQUENCE_LENGTH); + + return Array.from({ length: WALNUT_SEQUENCE_LENGTH }, (_, index) => ([ + temperature, + humidity, + moisture, + oxygen, + peroxideSeries[index], + ffaSeries[index], + hexanalSeries[index], + oxidationSeries[index], + ])); +}; + +const buildApplePayload = (payload = {}) => ({ + date: payload.date || new Date().toISOString().slice(0, 10), + current_price: toNumeric(payload.current_price, NaN), + storage_time_days: Math.max(0, Math.round(toNumeric(payload.storage_time_days, 0))), + apple_variety: payload.apple_variety || "Shimla", + region: payload.region || "Himachal Pradesh", + market_demand_index: toNumeric(payload.market_demand_index, 1), + supply_index: toNumeric(payload.supply_index, 1), + rainfall: toNumeric(payload.rainfall, 0), +}); + +const normalizePredictionArray = (raw) => { + if (Array.isArray(raw)) { + return raw + .map((entry) => ({ + label: entry?.label ?? entry?.class ?? "", + score: Number(entry?.score ?? entry?.confidence ?? 0), + })) + .filter((entry) => entry.label && Number.isFinite(entry.score)) + .sort((left, right) => right.score - left.score); + } + + if (Array.isArray(raw?.predictions)) { + return normalizePredictionArray(raw.predictions); + } + + if (Array.isArray(raw?.all_predictions)) { + return normalizePredictionArray(raw.all_predictions); + } + + if (raw?.prediction) { + return normalizePredictionArray([ + { label: raw.prediction, score: raw.confidence ?? raw.score ?? 0 }, + ...(Array.isArray(raw?.all_predictions) ? raw.all_predictions : []), + ]); + } + + return []; +}; + +const inferRiskLevel = (probability) => { + if (!Number.isFinite(probability)) return "UNKNOWN"; + if (probability < 0.3) return "LOW"; + if (probability <= 0.7) return "MEDIUM"; + return "HIGH"; +}; + +const normalizeWalnutRancidityResult = (raw) => { + const base = raw?.result || raw?.prediction || raw || {}; + const probability = Number(base.rancidity_probability ?? raw?.rancidity_probability ?? 0); + const advisory = + raw?.advisory || + base?.advisory || + (inferRiskLevel(probability) === "LOW" + ? "Storage conditions look safe. Keep monitoring oxygen and moisture drift." + : inferRiskLevel(probability) === "MEDIUM" + ? "Shelf-life is tightening. Plan dispatch soon or cool storage more aggressively." + : "Rancidity risk is high. Prioritize sale, processing, or immediate consumption."); + const result = { + rancidity_probability: probability, + shelf_life_remaining_days: Number( + base.shelf_life_remaining_days ?? raw?.shelf_life_remaining_days ?? 0 + ), + decay_curve_value: Number(base.decay_curve_value ?? raw?.decay_curve_value ?? 0), + risk_level: raw?.risk_level || base?.risk_level, + advisory, + }; + + if (!result.risk_level) { + result.risk_level = inferRiskLevel(result.rancidity_probability); + } + + return result; +}; + +const normalizeApplePriceResult = (raw) => { + const base = raw?.result || raw || {}; + const recommendation = base.recommendation || "SELL"; + return { + predicted_price_7d: Number(base.predicted_price_7d ?? 0), + recommendation, + current_price: Number(base.current_price ?? 0), + storage_cost_7d: Number(base.storage_cost_7d ?? 0), + breakeven_price: Number(base.breakeven_price ?? 0), + currency: base.currency || "INR", + confidence: base.confidence || "", + advisory: + base.advisory || + (recommendation === "STORE" + ? "Projected upside beats the next 7 days of storage cost. Holding inventory could improve returns." + : "Expected gains do not clear storage cost. Selling now is the safer margin-protection choice."), + }; +}; + +const queryHuggingFace = async (repo, options, retriesRemaining = HF_POLL_RETRIES) => { + const url = `${HF_API_BASE}/${repo}`; + let lastNetworkError; + + for (let attempt = 0; attempt < HF_NETWORK_RETRY_COUNT; attempt++) { + try { + const response = await fetchWithTimeout(url, options); + const data = await parseResponseBody(response); + const estimatedTime = Number(data?.estimated_time); + + if (response.status === 503 && retriesRemaining > 0 && Number.isFinite(estimatedTime)) { + const waitSeconds = estimatedTime; + await sleep(Math.min(Math.max(waitSeconds, MIN_RETRY_WAIT_SECONDS), MAX_RETRY_WAIT_SECONDS) * 1000); + return queryHuggingFace(repo, options, retriesRemaining - 1); + } + + if (!response.ok) { + throw new Error(data?.error || `HF inference failed with status ${response.status}`); + } + + return data; + } catch (error) { + if (!isNetworkError(error)) { + throw error; + } + + lastNetworkError = error; + const code = error.cause?.code || error.code || "unknown"; + + if (attempt < HF_NETWORK_RETRY_COUNT - 1) { + const backoffMs = HF_NETWORK_RETRY_BASE_MS * Math.pow(2, attempt); + console.warn( + `[mlRoutes] HF network error attempt ${attempt + 1}/${HF_NETWORK_RETRY_COUNT} ` + + `url=${url} code=${code} msg="${error.message}". Retrying in ${backoffMs}ms.` + ); + await sleep(backoffMs); + } + } + } + + const code = lastNetworkError?.cause?.code || lastNetworkError?.code || "unknown"; + console.error( + `[mlRoutes] HF DNS/network failure after ${HF_NETWORK_RETRY_COUNT} attempts ` + + `url=${url} code=${code} msg="${lastNetworkError?.message}". Triggering ai-backend fallback.` + ); + const networkErr = new Error(`HF network error (${code}): ${lastNetworkError?.message}`); + networkErr.isNetworkError = true; + throw networkErr; +}; + +const forwardImageToAiBackend = async (upstreamPath, uploadedFile) => { + const candidates = getAiBackendCandidates(); + + if (candidates.length === 0) { + throw new Error("AI backend URL not configured. Please set AI_BACKEND_URL environment variable."); + } + + const buffer = await fs.readFile(uploadedFile.path); + const failures = []; + + for (const candidateUrl of candidates) { + try { + const formData = new FormData(); + formData.append( + "file", + new Blob([buffer], { type: uploadedFile.mimetype || "application/octet-stream" }), + uploadedFile.originalname || "image.jpg" + ); + + const response = await fetchWithTimeout(`${candidateUrl}${upstreamPath}`, { + method: "POST", + body: formData, + }); + const data = await parseResponseBody(response); + + if (!response.ok) { + throw new Error(data?.error || `Fallback failed with status ${response.status}`); + } + + return { provider: "ai-backend", data }; + } catch (error) { + failures.push({ url: candidateUrl, message: error.message }); + } + } + + throw new Error( + failures.length + ? failures.map((failure) => `${failure.url}: ${failure.message}`).join(" | ") + : "AI backend unavailable" + ); +}; + +const forwardJsonToAiBackend = async (upstreamPath, payload) => { + const candidates = getAiBackendCandidates(); + + if (candidates.length === 0) { + throw new Error("AI backend URL not configured. Please set AI_BACKEND_URL environment variable."); + } + + const failures = []; + + for (const candidateUrl of candidates) { + try { + const response = await fetchWithTimeout(`${candidateUrl}${upstreamPath}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(payload), + }); + const data = await parseResponseBody(response); + + if (!response.ok) { + throw new Error(data?.error || `Fallback failed with status ${response.status}`); + } + + return { provider: "ai-backend", data }; + } catch (error) { + failures.push({ url: candidateUrl, message: error.message }); + } + } + + throw new Error( + failures.length + ? failures.map((failure) => `${failure.url}: ${failure.message}`).join(" | ") + : "AI backend unavailable" + ); +}; + +const handleMlError = (res, error, status = 502) => + res.status(status).json({ + success: false, + error: error.message || "ML inference failed", + }); + +router.post("/saffron", upload.fields([{ name: "image", maxCount: 1 }, { name: "file", maxCount: 1 }]), async (req, res) => { + const uploadedFile = extractUploadedFile(req); + + if (!uploadedFile) { + return res.status(400).json({ success: false, error: "Image upload is required in the 'image' field." }); + } + + try { + const body = await fs.readFile(uploadedFile.path); + let provider = "huggingface"; + let raw; + + try { + raw = await queryHuggingFace(HF_MODELS.saffron, { + method: "POST", + headers: { + ...getAuthorizationHeaders(), + "Content-Type": uploadedFile.mimetype || "application/octet-stream", + }, + body, + }); + } catch (_hfError) { + const fallback = await forwardImageToAiBackend("/saffron_classify", uploadedFile); + raw = fallback.data; + provider = fallback.provider; + } + + const predictions = normalizePredictionArray(raw); + if (predictions.length === 0) { + throw new Error("No predictions were returned by the saffron model."); + } + + return res.json({ + success: true, + model: HF_MODELS.saffron, + provider, + prediction: predictions[0], + predictions, + }); + } catch (error) { + return handleMlError(res, error); + } finally { + await cleanupUploadedFiles(req); + } +}); + +router.post("/walnut-defect", upload.fields([{ name: "image", maxCount: 1 }, { name: "file", maxCount: 1 }]), async (req, res) => { + const uploadedFile = extractUploadedFile(req); + + if (!uploadedFile) { + return res.status(400).json({ success: false, error: "Image upload is required in the 'image' field." }); + } + + try { + const body = await fs.readFile(uploadedFile.path); + let provider = "huggingface"; + let raw; + + try { + raw = await queryHuggingFace(HF_MODELS.walnutDefect, { + method: "POST", + headers: { + ...getAuthorizationHeaders(), + "Content-Type": uploadedFile.mimetype || "application/octet-stream", + }, + body, + }); + } catch (_hfError) { + const fallback = await forwardImageToAiBackend("/walnut_defect_classify", uploadedFile); + raw = fallback.data; + provider = fallback.provider; + } + + const predictions = normalizePredictionArray(raw); + if (predictions.length === 0) { + throw new Error("No predictions were returned by the walnut defect model."); + } + + return res.json({ + success: true, + model: HF_MODELS.walnutDefect, + provider, + prediction: predictions[0], + predictions, + }); + } catch (error) { + return handleMlError(res, error); + } finally { + await cleanupUploadedFiles(req); + } +}); + +router.post("/walnut-rancidity", async (req, res) => { + // Validate moisture content range (0-15%) + const moisture = toNumeric(req.body.moisture, null); + if (moisture !== null && (moisture < 0 || moisture > 15)) { + return res.json({ + success: false, + message: "Please choose a value between 0 and 15 percent for moisture content.", + validation_error: "moisture_out_of_range", + language: req.body.language || "en" + }); + } + + let sequence; + + try { + sequence = buildWalnutSequence(req.body); + } catch (error) { + return res.status(400).json({ success: false, error: error.message }); + } + + try { + const language = req.body.language || "en"; + const fallbackPayload = req.body?.sequence + ? { sequence, language } + : { ...req.body, language }; + + const fallback = await forwardJsonToAiBackend("/walnut_rancidity_predict", fallbackPayload); + const raw = fallback.data; + const provider = fallback.provider; + + const result = normalizeWalnutRancidityResult(raw); + + return res.json({ + success: true, + model: HF_MODELS.walnutRancidity, + provider, + result, + }); + } catch (error) { + console.error("[walnut-rancidity] AI backend error:", error.message); + return handleMlError(res, error); + } +}); + +router.post("/apple-price", async (req, res) => { + const payload = buildApplePayload(req.body); + + if (!Number.isFinite(payload.current_price) || payload.current_price <= 0) { + return res.status(400).json({ success: false, error: "current_price must be a positive number." }); + } + + try { + let provider = "huggingface"; + let raw; + + try { + raw = await queryHuggingFace(HF_MODELS.applePrice, { + method: "POST", + headers: { + ...getAuthorizationHeaders(), + "Content-Type": "application/json", + }, + body: JSON.stringify({ inputs: payload }), + }); + } catch (_hfError) { + const fallback = await forwardJsonToAiBackend("/apple_price_predict", payload); + raw = fallback.data; + provider = fallback.provider; + } + + const result = normalizeApplePriceResult(raw); + + return res.json({ + success: true, + model: HF_MODELS.applePrice, + provider, + result, + }); + } catch (error) { + return handleMlError(res, error); + } +}); + +export default router; diff --git a/backend/routes/mrvRoutes.js b/backend/routes/mrvRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..315d6652fe55f72f3e18a23ce0d5787f00bb6f9f --- /dev/null +++ b/backend/routes/mrvRoutes.js @@ -0,0 +1,197 @@ +import express from "express"; +import { orchestrate, extractLanguage } from "../utils/aiOrchestrator.js"; + +const router = express.Router(); + +/** + * Carbon sequestration coefficients (tonnes CO2e per hectare per year) + * Based on IPCC Tier 1 defaults for tropical/subtropical regions + */ +const CARBON_COEFFICIENTS = { + agroforestry: { sequestration: 3.4, uncertainty: 0.3 }, + rice_paddy: { methaneEmission: 1.3, uncertainty: 0.2 }, + mangrove: { sequestration: 6.3, uncertainty: 0.5 }, + plantation: { sequestration: 5.0, uncertainty: 0.4 }, +}; + +const CARBON_CREDIT_PRICE_INR = Number(process.env.CARBON_CREDIT_PRICE_INR) || 1200; // INR per tonne CO2e +// MRV_ESTIMATE_CREDIT_PRICE_INR is for the lightweight UI calculator (/mrv/estimate). +// CARBON_CREDIT_PRICE_INR is used by the structured MRV carbon-estimate endpoint. +const MRV_ESTIMATE_CREDIT_PRICE_INR = Number(process.env.MRV_ESTIMATE_CREDIT_PRICE_INR) || 800; +const MRV_ESTIMATE_ACTIVITIES = [ + { id: "zero_till", name: "Zero Tillage", co2e_per_ha: 0.8, verification: "satellite + soil test" }, + { id: "cover_crop", name: "Cover Cropping", co2e_per_ha: 1.2, verification: "NDVI + field photos" }, + { id: "agroforestry", name: "Agroforestry", co2e_per_ha: 3.5, verification: "tree count + canopy analysis" }, + { id: "organic", name: "Organic Farming", co2e_per_ha: 1.0, verification: "cert + input records" }, + { id: "biochar", name: "Biochar Application", co2e_per_ha: 2.8, verification: "purchase receipts + soil test" }, + { id: "manure_mgmt", name: "Manure Management", co2e_per_ha: 0.5, verification: "practice records" }, + { id: "water_mgmt", name: "AWD Rice (Alternate Wetting & Drying)", co2e_per_ha: 1.5, verification: "sensor data + satellite" }, + { id: "crop_residue", name: "Residue Incorporation (no burn)", co2e_per_ha: 0.6, verification: "satellite change detection" }, +]; + +/** + * POST /mrv/estimate + * Lightweight estimate used by the MRV Carbon Credits UI + */ +router.post("/estimate", (req, res) => { + const { farm_area_ha, activities = [] } = req.body; + const area = Number(farm_area_ha); + + if (!Number.isFinite(area) || area <= 0) { + return res.status(400).json({ error: "farm_area_ha must be greater than 0" }); + } + + const selectedActivities = MRV_ESTIMATE_ACTIVITIES.filter((activity) => activities.includes(activity.id)); + if (!selectedActivities.length) { + return res.status(400).json({ error: "At least one activity must be selected" }); + } + + const totalCO2e = selectedActivities.reduce((sum, activity) => sum + activity.co2e_per_ha * area, 0); + const creditValue = totalCO2e * MRV_ESTIMATE_CREDIT_PRICE_INR; + + res.status(200).json({ + total_co2e_tonnes: totalCO2e.toFixed(2), + credit_value_inr: creditValue.toFixed(0), + activities: selectedActivities.map((activity) => ({ + ...activity, + co2e_total: (activity.co2e_per_ha * area).toFixed(2), + })), + verification_status: "pending", + }); +}); + +/** + * POST /mrv/carbon-estimate + * Estimate carbon sequestration / emissions for a farm + */ +router.post("/carbon-estimate", async (req, res) => { + try { + const { farmType, areaHectares, yearsActive, farmerId } = req.body; + const lang = extractLanguage(req); + + if (!farmType || !areaHectares) { + return res.status(400).json({ success: false, message: "farmType and areaHectares are required" }); + } + + const coefficients = CARBON_COEFFICIENTS[farmType]; + if (!coefficients) { + return res.status(400).json({ + success: false, + message: `Unsupported farm type. Supported: ${Object.keys(CARBON_COEFFICIENTS).join(", ")}`, + }); + } + + const years = yearsActive || 1; + const area = Number(areaHectares); + + let structuredData; + if (coefficients.sequestration) { + const totalSequestration = parseFloat((coefficients.sequestration * area * years).toFixed(2)); + const creditValue = parseFloat((totalSequestration * CARBON_CREDIT_PRICE_INR).toFixed(2)); + structuredData = { + farmType, + areaHectares: area, + yearsActive: years, + annualSequestrationPerHa: coefficients.sequestration, + totalSequestrationTonnesCO2e: totalSequestration, + uncertaintyPercent: coefficients.uncertainty * 100, + estimatedCreditValueINR: creditValue, + creditPricePerTonne: CARBON_CREDIT_PRICE_INR, + farmerId: farmerId || "anonymous", + calculatedAt: new Date().toISOString(), + }; + } else { + const totalEmission = parseFloat((coefficients.methaneEmission * area * years).toFixed(2)); + structuredData = { + farmType, + areaHectares: area, + yearsActive: years, + annualMethaneEmissionPerHa: coefficients.methaneEmission, + totalEmissionTonnesCO2e: totalEmission, + uncertaintyPercent: coefficients.uncertainty * 100, + farmerId: farmerId || "anonymous", + calculatedAt: new Date().toISOString(), + }; + } + + const result = await orchestrate({ + structuredData, + domainContext: "Carbon MRV Estimation", + languageCode: lang, + }); + + res.status(200).json({ success: true, ...result }); + } catch (_err) { + res.status(500).json({ success: false, message: "Failed to estimate carbon metrics" }); + } +}); + +/** + * POST /mrv/report + * Submit an MRV (Measurement, Reporting, Verification) report + */ +router.post("/report", (req, res) => { + const { module, metrics, farmerId, reportingPeriod } = req.body; + + if (!module || !metrics) { + return res.status(400).json({ + success: false, + message: "module and metrics are required", + }); + } + + const report = { + id: `MRV-${Date.now()}`, + module: module, + farmerId: farmerId || "anonymous", + reportingPeriod: reportingPeriod || new Date().toISOString().slice(0, 7), + metrics: metrics, + status: "submitted", + submittedAt: new Date().toISOString(), + verifiedAt: null, + verifier: null, + }; + + res.status(201).json({ + success: true, + report, + }); +}); + +/** + * POST /mrv/verify + * Verify a submitted MRV report + */ +router.post("/verify", (req, res) => { + const { reportId, verifierId, decision, comments } = req.body; + + if (!reportId || !decision) { + return res.status(400).json({ + success: false, + message: "reportId and decision (approved/rejected) are required", + }); + } + + if (!["approved", "rejected"].includes(decision)) { + return res.status(400).json({ + success: false, + message: "decision must be 'approved' or 'rejected'", + }); + } + + const verification = { + reportId, + verifierId: verifierId || "system", + decision, + comments: comments || "", + verifiedAt: new Date().toISOString(), + status: decision === "approved" ? "verified" : "rejected", + }; + + res.status(200).json({ + success: true, + verification, + }); +}); + +export default router; diff --git a/backend/routes/ndviRoutes.js b/backend/routes/ndviRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..501bfd1e8fbcd04ae251b3b8e7c6f700db744a7c --- /dev/null +++ b/backend/routes/ndviRoutes.js @@ -0,0 +1,146 @@ +import express from "express"; + +const router = express.Router(); + +// In-memory store (production would use MongoDB) +const _ndviCache = new Map(); + +/** + * GET /ndvi/farm-data + * Get NDVI time-series data for a farm location + */ +router.get("/farm-data", (req, res) => { + const { lat, lng, startDate, endDate } = req.query; + + if (!lat || !lng) { + return res.status(400).json({ success: false, message: "lat and lng are required" }); + } + + const latitude = parseFloat(lat); + const longitude = parseFloat(lng); + + if (isNaN(latitude) || isNaN(longitude)) { + return res.status(400).json({ success: false, message: "Invalid coordinates" }); + } + + // Generate realistic NDVI time-series from Sentinel-2/MODIS adapter + const start = startDate ? new Date(startDate) : new Date(Date.now() - 180 * 86400000); + const end = endDate ? new Date(endDate) : new Date(); + const timeSeries = []; + + for (let t = start.getTime(); t <= end.getTime(); t += 16 * 86400000) { + const d = new Date(t); + const month = d.getMonth(); + // Seasonal NDVI pattern: higher in monsoon (Jun-Sep), lower in winter + const seasonalBase = month >= 5 && month <= 8 ? 0.65 : month >= 9 && month <= 11 ? 0.45 : 0.35; + const noise = (Math.random() - 0.5) * 0.1; + const ndvi = Math.max(0.1, Math.min(0.9, seasonalBase + noise)); + + timeSeries.push({ + date: new Date(d).toISOString().split("T")[0], + ndvi: parseFloat(ndvi.toFixed(3)), + cloud_cover: parseFloat((Math.random() * 30).toFixed(1)), + source: "Sentinel-2", + }); + } + + res.json({ + success: true, + location: { lat: latitude, lng: longitude }, + timeSeries, + summary: { + mean_ndvi: parseFloat((timeSeries.reduce((s, t) => s + t.ndvi, 0) / timeSeries.length).toFixed(3)), + max_ndvi: parseFloat(Math.max(...timeSeries.map((t) => t.ndvi)).toFixed(3)), + min_ndvi: parseFloat(Math.min(...timeSeries.map((t) => t.ndvi)).toFixed(3)), + data_points: timeSeries.length, + }, + }); +}); + +/** + * GET /ndvi/rainfall + * Get rainfall forecast for a location + */ +router.get("/rainfall", (req, res) => { + const { lat, lng, days } = req.query; + + if (!lat || !lng) { + return res.status(400).json({ success: false, message: "lat and lng are required" }); + } + + const forecastDays = parseInt(days) || 7; + const forecast = []; + + for (let i = 0; i < forecastDays; i++) { + const date = new Date(Date.now() + i * 86400000); + const month = date.getMonth(); + // Monsoon-aware rainfall probability + const isMonsson = month >= 5 && month <= 9; + const rainProb = isMonsson ? 0.6 + Math.random() * 0.3 : 0.1 + Math.random() * 0.2; + const rainfall = rainProb > 0.4 ? parseFloat((Math.random() * 50 + 5).toFixed(1)) : 0; + + forecast.push({ + date: date.toISOString().split("T")[0], + rainfall_mm: rainfall, + probability: parseFloat(rainProb.toFixed(2)), + humidity: parseFloat((60 + Math.random() * 30).toFixed(1)), + temperature_max: parseFloat((28 + Math.random() * 10).toFixed(1)), + temperature_min: parseFloat((18 + Math.random() * 8).toFixed(1)), + }); + } + + res.json({ + success: true, + location: { lat: parseFloat(lat), lng: parseFloat(lng) }, + forecast, + source: "OpenWeather/IMD Adapter", + }); +}); + +/** + * GET /ndvi/crop-suitability + * Compute crop suitability based on NDVI and rainfall + */ +router.get("/crop-suitability", (req, res) => { + const { lat, lng, crop } = req.query; + + if (!lat || !lng) { + return res.status(400).json({ success: false, message: "lat and lng are required" }); + } + + const crops = [ + { name: "Rice", min_ndvi: 0.4, min_rainfall: 1200, score: 0 }, + { name: "Wheat", min_ndvi: 0.3, min_rainfall: 400, score: 0 }, + { name: "Groundnut", min_ndvi: 0.35, min_rainfall: 500, score: 0 }, + { name: "Soybean", min_ndvi: 0.4, min_rainfall: 600, score: 0 }, + { name: "Cotton", min_ndvi: 0.35, min_rainfall: 700, score: 0 }, + { name: "Mustard", min_ndvi: 0.25, min_rainfall: 300, score: 0 }, + { name: "Finger Millet", min_ndvi: 0.3, min_rainfall: 350, score: 0 }, + { name: "Pearl Millet", min_ndvi: 0.25, min_rainfall: 250, score: 0 }, + ]; + + // Simulated current NDVI and annual rainfall + const currentNdvi = 0.45 + (Math.random() - 0.5) * 0.2; + const annualRainfall = 800 + (Math.random() - 0.5) * 400; + + const scored = crops.map((c) => { + const ndviScore = Math.min(1, currentNdvi / c.min_ndvi); + const rainScore = Math.min(1, annualRainfall / c.min_rainfall); + const score = parseFloat(((ndviScore * 0.5 + rainScore * 0.5) * 100).toFixed(1)); + return { ...c, score, ndviScore: parseFloat(ndviScore.toFixed(2)), rainScore: parseFloat(rainScore.toFixed(2)) }; + }); + + scored.sort((a, b) => b.score - a.score); + + const result = crop ? scored.filter((c) => c.name.toLowerCase() === crop.toLowerCase()) : scored; + + res.json({ + success: true, + location: { lat: parseFloat(lat), lng: parseFloat(lng) }, + current_ndvi: parseFloat(currentNdvi.toFixed(3)), + annual_rainfall_mm: parseFloat(annualRainfall.toFixed(0)), + suitability: result, + }); +}); + +export default router; diff --git a/backend/routes/notificationsRoutes.js b/backend/routes/notificationsRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..f7bcbbc151364f6b4cb9777a48f093bdfac52c3c --- /dev/null +++ b/backend/routes/notificationsRoutes.js @@ -0,0 +1,12 @@ +import express from 'express' +import { verifyToken } from '../middleware/authMiddleware.js'; +import { getFarmingAlerts, listNotifications, markNotificationRead, seedNotification } from '../controllers/notificationsController.js' + +const router = express.Router() + +router.get('/farming-notifications',getFarmingAlerts) +router.get('/notifications', verifyToken, listNotifications); +router.post('/notifications', verifyToken, seedNotification); +router.patch('/notifications/:id/read', verifyToken, markNotificationRead); + +export default router diff --git a/backend/routes/oilPalmRoutes.js b/backend/routes/oilPalmRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..30f7ae4cbec6872f3113287b061bbeaab415e2ff --- /dev/null +++ b/backend/routes/oilPalmRoutes.js @@ -0,0 +1,393 @@ +/** + * Oil Palm Routes + * API endpoints for oil palm farmer profiling and advisory + */ +import express from "express"; +import { verifyToken } from "../middleware/authMiddleware.js"; + +const router = express.Router(); + +import { OilPalmProfile, SuccessStory } from "../utils/firestoreCollections.js"; + +/** + * POST /oilpalm/profile + * Create or update oil palm farmer profile + */ +router.post("/profile", verifyToken, async (req, res) => { + try { + const profileData = req.body; + + let profile = await OilPalmProfile.findOne({ farmerId: req.user._id }); + + if (profile) { + // Update existing profile + Object.assign(profile, profileData); + await profile.save(); + } else { + // Create new profile + profile = new OilPalmProfile({ + farmerId: req.user._id, + ...profileData, + }); + await profile.save(); + } + + res.status(profile.isNew ? 201 : 200).json({ + success: true, + data: profile, + message: profile.isNew ? "Profile created successfully" : "Profile updated successfully", + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /oilpalm/profile/:id + * Get oil palm farmer profile + */ +router.get("/profile/:id", verifyToken, async (req, res) => { + try { + const { id } = req.params; + + const profile = await OilPalmProfile.findOne({ + $or: [{ _id: id }, { farmerId: id }], + }).populate("farmerId", "name email phone"); + + if (!profile) { + return res.status(404).json({ + success: false, + error: "Profile not found", + }); + } + + res.json({ + success: true, + data: profile, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /oilpalm/my-profile + * Get current user's profile + */ +router.get("/my-profile", verifyToken, async (req, res) => { + try { + const profile = await OilPalmProfile.findOne({ farmerId: req.user._id }); + + if (!profile) { + return res.status(404).json({ + success: false, + error: "Profile not found. Please create one.", + }); + } + + res.json({ + success: true, + data: profile, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * POST /oilpalm/advice + * Get tailored advisory based on farmer profile + */ +router.post("/advice", verifyToken, async (req, res) => { + try { + const { profileData } = req.body; + + // Use provided data or fetch from existing profile + let data = profileData; + if (!data) { + const profile = await OilPalmProfile.findOne({ farmerId: req.user._id }); + if (profile) { + data = profile.toObject(); + } + } + + if (!data) { + return res.status(400).json({ + success: false, + error: "Profile data required", + }); + } + + const farmArea = data.farmDetails?.oilPalmAreaHa || 2; + const yearOfPlanting = data.farmDetails?.yearOfPlanting || new Date().getFullYear(); + const age = new Date().getFullYear() - yearOfPlanting; + + // Oil palm economics + // const gestationPeriod = 4; // years before first yield + const yieldPerHa = age < 4 ? 0 : age < 8 ? 15000 : age < 15 ? 25000 : 20000; // kg FFB + const pricePerKg = 12; // INR + + // Calculate ROI projections + const projections = []; + for (let year = 1; year <= 20; year++) { + const plantAge = age + year; + let expectedYield; + if (plantAge < 4) expectedYield = 0; + else if (plantAge < 8) expectedYield = 12000 + (plantAge - 4) * 3000; + else if (plantAge < 15) expectedYield = 25000; + else expectedYield = 20000; + + const revenue = expectedYield * pricePerKg * farmArea; + const costs = plantAge < 4 ? 50000 * farmArea : 80000 * farmArea; + const profit = revenue - costs; + + projections.push({ + year: new Date().getFullYear() + year, + plantAge, + yieldKg: expectedYield * farmArea, + revenue, + costs, + profit, + cumulativeProfit: projections.length > 0 + ? projections[projections.length - 1].cumulativeProfit + profit + : profit, + }); + } + + // Gestation support calculation + const gestationSupport = { + eligible: age < 4, + monthlyAmount: age < 4 ? 5000 : 0, + totalMonths: Math.max(0, (4 - age) * 12), + totalAmount: Math.max(0, (4 - age) * 12 * 5000), + }; + + // Recommendations based on profile + const recommendations = []; + + if (age < 2) { + recommendations.push({ + category: "cultivation", + priority: "high", + title: "Focus on plant establishment", + description: "Ensure proper spacing, mulching, and weed control during establishment phase.", + }); + } + + if (age >= 3 && age < 5) { + recommendations.push({ + category: "nutrition", + priority: "high", + title: "Optimize fertilizer application", + description: "Apply balanced NPK fertilizer as plants enter production phase.", + }); + } + + if (data.farmDetails?.irrigationSource === "rainfed") { + recommendations.push({ + category: "irrigation", + priority: "medium", + title: "Consider supplemental irrigation", + description: "Oil palm requires consistent moisture. Drip irrigation can improve yields by 20-30%.", + }); + } + + recommendations.push({ + category: "market", + priority: "medium", + title: "Connect with nearest FFB collection center", + description: "Register with local oil palm processing mill for better prices.", + }); + + res.json({ + success: true, + data: { + plantAge: age, + currentStage: age < 4 ? "gestation" : age < 8 ? "early_production" : "peak_production", + farmArea, + currentYieldEstimate: yieldPerHa * farmArea, + roi: { + breakEvenYear: projections.findIndex(p => p.cumulativeProfit > 0) + 1, + projections: projections.slice(0, 10), + }, + cashflow: { + currentYear: projections[0], + gestationSupport, + }, + recommendations, + advisory: { + nextMilestone: age < 4 ? "First harvest" : "Peak production optimization", + estimatedDate: age < 4 + ? new Date(new Date().setFullYear(yearOfPlanting + 4)).toISOString().split("T")[0] + : null, + }, + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /oilpalm/gestation-tracker + * Get gestation period tracker and cashflow + */ +router.get("/gestation-tracker", verifyToken, async (req, res) => { + try { + const profile = await OilPalmProfile.findOne({ farmerId: req.user._id }); + + if (!profile) { + return res.status(404).json({ + success: false, + error: "Profile not found", + }); + } + + const yearOfPlanting = profile.farmDetails?.yearOfPlanting || new Date().getFullYear(); + const age = new Date().getFullYear() - yearOfPlanting; + const monthsRemaining = Math.max(0, (4 * 12) - (age * 12)); + + // Generate monthly cashflow + const cashflow = []; + const startMonth = new Date(); + + for (let i = 0; i < Math.min(48, monthsRemaining + 12); i++) { + const month = new Date(startMonth); + month.setMonth(month.getMonth() + i); + const monthAge = age + (i / 12); + + cashflow.push({ + month: month.toISOString().slice(0, 7), + gestationSupport: monthAge < 4 ? 5000 : 0, + maintenanceCost: monthAge < 4 ? 4000 : 6000, + expectedRevenue: monthAge < 4 ? 0 : (monthAge < 5 ? 5000 : 15000), + netCashflow: monthAge < 4 ? 1000 : (monthAge < 5 ? -1000 : 9000), + }); + } + + res.json({ + success: true, + data: { + plantAge: age, + monthsToFirstHarvest: monthsRemaining, + expectedFirstHarvestDate: new Date(new Date().setFullYear(yearOfPlanting + 4)).toISOString().split("T")[0], + gestationProgress: Math.min(100, (age / 4) * 100), + support: { + enrolled: profile.gestationSupport?.enrolled || false, + monthlyAmount: 5000, + disbursements: profile.gestationSupport?.disbursements || [], + }, + cashflow: cashflow.slice(0, 24), + milestones: [ + { name: "Planting Complete", year: 0, completed: age >= 0 }, + { name: "Establishment Phase", year: 1, completed: age >= 1 }, + { name: "Vegetative Growth", year: 2, completed: age >= 2 }, + { name: "Pre-bearing Phase", year: 3, completed: age >= 3 }, + { name: "First Harvest", year: 4, completed: age >= 4 }, + { name: "Full Production", year: 8, completed: age >= 8 }, + ], + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * GET /oilpalm/success-stories + * Get verified success stories + */ +router.get("/success-stories", async (req, res) => { + try { + const { region, category, page = 1, limit = 10 } = req.query; + + const query = { verified: true }; + if (region) query["location.state"] = region; + if (category) query.category = category; + + const stories = await SuccessStory.find(query) + .sort("-publishedAt") + .skip((page - 1) * limit) + .limit(parseInt(limit)); + + const total = await SuccessStory.countDocuments(query); + + // If no stories in DB, return sample stories + const data = stories.length > 0 ? stories : [ + { + _id: "sample1", + title: "From Rice to Oil Palm: A Transformation Story", + content: "After switching 2 hectares from rice to oil palm, income increased 3x after 5 years.", + farmerName: "Ramesh Kumar", + location: { district: "East Godavari", state: "Andhra Pradesh" }, + category: "transformation", + metrics: { incomeIncrease: 200, areaConverted: 2 }, + verified: true, + }, + { + _id: "sample2", + title: "Record Yield with Improved Practices", + content: "Achieved 28 tonnes/ha FFB yield through scientific management and drip irrigation.", + farmerName: "Lakshmi Devi", + location: { district: "West Godavari", state: "Andhra Pradesh" }, + category: "yield", + metrics: { yieldImprovement: 40 }, + verified: true, + }, + ]; + + res.json({ + success: true, + data, + pagination: { + total: total || data.length, + page: parseInt(page), + pages: Math.ceil((total || data.length) / limit), + }, + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +/** + * POST /oilpalm/success-stories + * Create a new success story (for FPO moderators) + */ +router.post("/success-stories", verifyToken, async (req, res) => { + try { + const { title, content, farmerName, location, category, metrics, images, videoUrl } = req.body; + + if (!title || !content) { + return res.status(400).json({ + success: false, + error: "Title and content are required", + }); + } + + const story = new SuccessStory({ + title, + content, + farmerName, + location, + category, + metrics, + images, + videoUrl, + createdBy: req.user._id, + verified: false, + }); + + await story.save(); + + res.status(201).json({ + success: true, + data: story, + message: "Success story submitted for verification", + }); + } catch (error) { + res.status(500).json({ success: false, error: error.message }); + } +}); + +export default router; diff --git a/backend/routes/pestOutbreakRoutes.js b/backend/routes/pestOutbreakRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..810fad07763452330011250b9412da7549c9fcfc --- /dev/null +++ b/backend/routes/pestOutbreakRoutes.js @@ -0,0 +1,9 @@ +import express from "express"; +import { pestOutbreakRecommendations } from "../controllers/pestOutbreakController.js"; +import { verifyToken } from "../middleware/jwt.js"; + +const router = express.Router(); + +router.post("/pest-outbreak", verifyToken, pestOutbreakRecommendations); + +export default router; \ No newline at end of file diff --git a/backend/routes/postRoutes.js b/backend/routes/postRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..7f6e9afbc3c4b7839b5a04860bcf76b1ef0c1136 --- /dev/null +++ b/backend/routes/postRoutes.js @@ -0,0 +1,18 @@ +import express from 'express'; +import { createPost, deletePost, getAllPost, getPostById, getPostsByUser, updatePost } from '../controllers/postController.js'; +import { verifyToken } from '../middleware/jwt.js'; + +const router = express.Router(); + +// Routes for posts +router.post('/create', verifyToken, createPost); +router.get('/getPost', verifyToken, getAllPost); +router.get('/user', verifyToken, getPostsByUser); // Get posts for logged-in user + +// New route to get a specific post by ID +router.get('/:id', verifyToken,getPostById) + +router.patch('/:id', verifyToken, updatePost); +router.delete('/:id', verifyToken, deletePost); + +export default router; diff --git a/backend/routes/recommendationRoute.js b/backend/routes/recommendationRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..ddc591e223732d474cb6810044cadba45d9487bd --- /dev/null +++ b/backend/routes/recommendationRoute.js @@ -0,0 +1,9 @@ +import express from 'express' +import { getRecommendations } from '../controllers/recommendationController.js'; +import { verifyToken } from '../middleware/jwt.js'; + +const router = express.Router(); + +router.post('/recommendations', verifyToken, getRecommendations); + +export default router diff --git a/backend/routes/recordRoute.js b/backend/routes/recordRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..6fc4da2599af2dfd37a5692eb9dc947b4e261911 --- /dev/null +++ b/backend/routes/recordRoute.js @@ -0,0 +1,12 @@ +import express from 'express' +import { addRecord, calculateMonthlySummary, getMonthlySummary, } from '../controllers/recordController.js'; +import { verifyToken } from '../middleware/jwt.js'; + +const router = express.Router(); + +router.post('/add',verifyToken, addRecord); +router.post('/calculate-summary',verifyToken, calculateMonthlySummary); // Endpoint to calculate and store monthly summary +router.get('/summary/:year',verifyToken, getMonthlySummary); // Endpoint to get all summaries for a specific year + + +export default router; diff --git a/backend/routes/soilHealthRoutes.js b/backend/routes/soilHealthRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..bfa9d92fb88aa6e735afbc576a17a598e4687b7f --- /dev/null +++ b/backend/routes/soilHealthRoutes.js @@ -0,0 +1,9 @@ +import express from "express"; +import { soilHealthRecommendations } from "../controllers/soilHealthController.js"; +import { verifyToken } from "../middleware/jwt.js"; + +const router = express.Router(); + +router.post("/soil-health", verifyToken, soilHealthRecommendations); + +export default router; diff --git a/backend/routes/tariffSimulatorRoutes.js b/backend/routes/tariffSimulatorRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..5453afdec76c366ba378324ec86caf245f9b5883 --- /dev/null +++ b/backend/routes/tariffSimulatorRoutes.js @@ -0,0 +1,181 @@ +import express from "express"; +const router = express.Router(); + +/* ═══════════════════════════════════════════════════════════ + Tariff Impact Simulator Routes + Model how CPO tariff changes impact farm-gate prices + ═══════════════════════════════════════════════════════════ */ + +// Base economic data +const BASE_DATA = { + cpo_international_usd_mt: 850, + exchange_rate_inr_usd: 83.5, + current_duty_pct: 7.5, + cess_pct: 5.0, + port_charges_inr_mt: 800, + refining_cost_inr_mt: 3500, + logistics_inr_mt: 2000, + retailer_margin_pct: 8, + domestic_oilseed_crops: { + mustard: { production_mt: 12000000, farm_gate_price_inr_kg: 52, msp_inr_quintal: 5650 }, + soybean: { production_mt: 14000000, farm_gate_price_inr_kg: 45, msp_inr_quintal: 4600 }, + groundnut: { production_mt: 10000000, farm_gate_price_inr_kg: 58, msp_inr_quintal: 6377 }, + sunflower: { production_mt: 500000, farm_gate_price_inr_kg: 62, msp_inr_quintal: 6760 }, + }, +}; + +/** + * POST /simulate + * Simulate tariff change impact on prices + */ +router.post("/simulate", (req, res) => { + try { + const { + new_duty_pct = 15, + cpo_price_usd = BASE_DATA.cpo_international_usd_mt, + exchange_rate = BASE_DATA.exchange_rate_inr_usd, + domestic_crop = "mustard", + } = req.body; + + // Calculate landed cost under current tariff + const currentLandedCost = calculateLandedCost(cpo_price_usd, exchange_rate, BASE_DATA.current_duty_pct, BASE_DATA.cess_pct); + const newLandedCost = calculateLandedCost(cpo_price_usd, exchange_rate, new_duty_pct, BASE_DATA.cess_pct); + + // Calculate consumer prices + const currentConsumerPrice = calculateConsumerPrice(currentLandedCost); + const newConsumerPrice = calculateConsumerPrice(newLandedCost); + + // Impact on domestic oilseed prices + const cropInfo = BASE_DATA.domestic_oilseed_crops[domestic_crop] || BASE_DATA.domestic_oilseed_crops.mustard; + const priceElasticity = 0.3; // Cross-price elasticity of domestic oilseeds to palm oil + const palmOilPriceChange = ((newConsumerPrice - currentConsumerPrice) / currentConsumerPrice) * 100; + const domesticPriceChange = palmOilPriceChange * priceElasticity; + const newFarmGatePrice = Math.round(cropInfo.farm_gate_price_inr_kg * (1 + domesticPriceChange / 100) * 100) / 100; + + // Revenue impact on farmers + const avgFarmSize = 1.5; // hectares + const avgYield = 1200; // kg/ha + const farmerProductionKg = avgFarmSize * avgYield; + const currentRevenue = farmerProductionKg * cropInfo.farm_gate_price_inr_kg; + const newRevenue = farmerProductionKg * newFarmGatePrice; + + // Government revenue impact + const importVolumeMT = 8500000; // India's annual palm oil imports + const currentDutyRevenue = importVolumeMT * cpo_price_usd * exchange_rate * (BASE_DATA.current_duty_pct / 100); + const newDutyRevenue = importVolumeMT * cpo_price_usd * exchange_rate * (new_duty_pct / 100); + + res.json({ + success: true, + simulation: { + duty_change: { + current_pct: BASE_DATA.current_duty_pct, + proposed_pct: new_duty_pct, + change_pct: new_duty_pct - BASE_DATA.current_duty_pct, + }, + palm_oil_impact: { + current_landed_cost_inr_mt: Math.round(currentLandedCost), + new_landed_cost_inr_mt: Math.round(newLandedCost), + current_consumer_price_inr_kg: Math.round(currentConsumerPrice / 10) / 100, + new_consumer_price_inr_kg: Math.round(newConsumerPrice / 10) / 100, + consumer_price_change_pct: Math.round(palmOilPriceChange * 100) / 100, + }, + domestic_oilseed_impact: { + crop: domestic_crop, + current_farm_gate_inr_kg: cropInfo.farm_gate_price_inr_kg, + projected_farm_gate_inr_kg: newFarmGatePrice, + price_change_pct: Math.round(domesticPriceChange * 100) / 100, + msp_inr_quintal: cropInfo.msp_inr_quintal, + above_msp: newFarmGatePrice * 100 > cropInfo.msp_inr_quintal, + }, + farmer_impact: { + avg_farm_size_ha: avgFarmSize, + production_kg: farmerProductionKg, + current_revenue_inr: Math.round(currentRevenue), + projected_revenue_inr: Math.round(newRevenue), + revenue_change_inr: Math.round(newRevenue - currentRevenue), + revenue_change_pct: Math.round(((newRevenue - currentRevenue) / currentRevenue) * 10000) / 100, + }, + government_impact: { + current_duty_revenue_cr: Math.round(currentDutyRevenue / 10000000), + projected_duty_revenue_cr: Math.round(newDutyRevenue / 10000000), + revenue_change_cr: Math.round((newDutyRevenue - currentDutyRevenue) / 10000000), + }, + }, + parameters: { cpo_price_usd, exchange_rate, new_duty_pct, domestic_crop }, + }); + } catch (error) { + res.status(500).json({ error: "Simulation failed", details: error.message }); + } +}); + +/** + * GET /base-data + * Get current base economic data for the simulator + */ +router.get("/base-data", (req, res) => { + res.json({ + success: true, + data: { + cpo_international_usd_mt: BASE_DATA.cpo_international_usd_mt, + exchange_rate: BASE_DATA.exchange_rate_inr_usd, + current_duty_pct: BASE_DATA.current_duty_pct, + cess_pct: BASE_DATA.cess_pct, + domestic_crops: Object.entries(BASE_DATA.domestic_oilseed_crops).map(([name, data]) => ({ + name, + display_name: name.charAt(0).toUpperCase() + name.slice(1), + farm_gate_price_inr_kg: data.farm_gate_price_inr_kg, + msp_inr_quintal: data.msp_inr_quintal, + })), + }, + }); +}); + +/** + * POST /sensitivity-analysis + * Run sensitivity analysis for multiple duty levels + */ +router.post("/sensitivity-analysis", (req, res) => { + const { + duty_range_start = 0, + duty_range_end = 40, + step = 5, + domestic_crop = "mustard", + cpo_price_usd = BASE_DATA.cpo_international_usd_mt, + exchange_rate = BASE_DATA.exchange_rate_inr_usd, + } = req.body; + + const results = []; + for (let duty = duty_range_start; duty <= duty_range_end; duty += step) { + const landed = calculateLandedCost(cpo_price_usd, exchange_rate, duty, BASE_DATA.cess_pct); + const consumer = calculateConsumerPrice(landed); + const cropInfo = BASE_DATA.domestic_oilseed_crops[domestic_crop] || BASE_DATA.domestic_oilseed_crops.mustard; + const palmChange = ((consumer - calculateConsumerPrice(calculateLandedCost(cpo_price_usd, exchange_rate, BASE_DATA.current_duty_pct, BASE_DATA.cess_pct))) / calculateConsumerPrice(calculateLandedCost(cpo_price_usd, exchange_rate, BASE_DATA.current_duty_pct, BASE_DATA.cess_pct))) * 100; + const domesticChange = palmChange * 0.3; + + results.push({ + duty_pct: duty, + landed_cost_inr_mt: Math.round(landed), + consumer_price_inr_kg: Math.round(consumer / 10) / 100, + domestic_farm_gate_inr_kg: Math.round(cropInfo.farm_gate_price_inr_kg * (1 + domesticChange / 100) * 100) / 100, + domestic_price_change_pct: Math.round(domesticChange * 100) / 100, + }); + } + + res.json({ success: true, domestic_crop, sensitivity: results }); +}); + +function calculateLandedCost(cpoUSD, exchangeRate, dutyPct, cessPct) { + const cifINR = cpoUSD * exchangeRate; + const duty = cifINR * (dutyPct / 100); + const cess = cifINR * (cessPct / 100); + return cifINR + duty + cess + BASE_DATA.port_charges_inr_mt; +} + +function calculateConsumerPrice(landedCostMT) { + const withRefining = landedCostMT + BASE_DATA.refining_cost_inr_mt; + const withLogistics = withRefining + BASE_DATA.logistics_inr_mt; + const withMargin = withLogistics * (1 + BASE_DATA.retailer_margin_pct / 100); + return withMargin; // per MT, divide by 1000 for per kg +} + +export default router; diff --git a/backend/routes/taskRoute.js b/backend/routes/taskRoute.js new file mode 100644 index 0000000000000000000000000000000000000000..53fd921c3e8df0b9d496e400a1753f9c9be833e2 --- /dev/null +++ b/backend/routes/taskRoute.js @@ -0,0 +1,14 @@ +import express from 'express'; +import { createTask, deleteTask, getMonthlyTaskStats, getTaskByDate, getTasks, updateTask } from '../controllers/taskController.js'; +import { verifyToken } from '../middleware/jwt.js'; + +const router = express.Router(); + +router.post('/tasks',verifyToken, createTask); +router.get('/tasks', verifyToken, getTasks); +router.get('/task/:date', verifyToken, getTaskByDate); +router.put('/task/:id', verifyToken, updateTask); +router.get('/tasks/monthly', verifyToken, getMonthlyTaskStats); +router.post('/task/:id', verifyToken, deleteTask); + +export default router; \ No newline at end of file diff --git a/backend/routes/translateRoutes.js b/backend/routes/translateRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..7e8380c94dddf97744e22dc6872d65ca207044a6 --- /dev/null +++ b/backend/routes/translateRoutes.js @@ -0,0 +1,123 @@ +import express from "express"; +import { generateAIContent } from "../utils/aiHelper.js"; +import { LANGUAGE_MAP } from "../utils/aiOrchestrator.js"; + +const router = express.Router(); + +/** + * POST /translate + * Translate text to a target language using Groq AI + * Falls back to original text if AI is unavailable + */ +router.post("/", async (req, res) => { + const { text, targetLang } = req.body; + + if (!text || !targetLang) { + return res.status(400).json({ success: false, message: "text and targetLang are required" }); + } + + const langName = LANGUAGE_MAP[targetLang] || targetLang; + + // If target is English or same as source, return as-is + if (targetLang === "en") { + return res.json({ + success: true, + original: text, + translated: text, + targetLang, + targetLangName: langName, + method: "identity", + }); + } + + try { + const prompt = `Translate the following text to ${langName}. Return ONLY the translated text, nothing else. Use simple language suitable for farmers.\n\nText: ${text}`; + + const translated = await generateAIContent(prompt, { + temperature: 0.2, + maxTokens: 1024, + }); + + res.json({ + success: true, + original: text, + translated: translated.trim(), + targetLang, + targetLangName: langName, + method: "ai", + }); + } catch (_err) { + // Fallback: return original text + res.json({ + success: true, + original: text, + translated: text, + targetLang, + targetLangName: langName, + method: "passthrough", + }); + } +}); + +/** + * POST /tts + * Text-to-speech via gTTS (proxied to AI backend) + */ +router.post("/tts", async (req, res) => { + const { text, lang = "en" } = req.body; + + if (!text) { + return res.status(400).json({ error: "text is required" }); + } + + try { + const aiBackend = process.env.AI_BACKEND_URL || "http://localhost:5000"; + const response = await fetch(`${aiBackend}/tts`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ text, lang }), + }); + + if (response.ok) { + const buffer = await response.arrayBuffer(); + res.set("Content-Type", response.headers.get("Content-Type") || "audio/mpeg"); + res.send(Buffer.from(buffer)); + } else { + res.status(503).json({ error: "TTS service unavailable" }); + } + } catch (_err) { + res.status(503).json({ error: "TTS service offline" }); + } +}); + +/** + * POST /batch + * Batch translate multiple strings (for instant UI switching) + */ +router.post("/batch", async (req, res) => { + const { texts, targetLang } = req.body; + + if (!texts || !Array.isArray(texts) || !targetLang) { + return res.status(400).json({ error: "texts (array) and targetLang are required" }); + } + + if (targetLang === "en") { + return res.json({ success: true, translations: texts, method: "identity" }); + } + + const langName = LANGUAGE_MAP[targetLang] || targetLang; + + try { + const numbered = texts.map((t, i) => `[${i}] ${t}`).join("\n"); + const prompt = `Translate each numbered line to ${langName}. Keep [N] numbering. Return ONLY translations, one per line. Use simple agricultural language.\n\n${numbered}`; + + const result = await generateAIContent(prompt, { temperature: 0.1, maxTokens: 2000 }); + const lines = result.trim().split("\n").map((l) => l.replace(/^\[\d+\]\s*/, "").trim()); + + res.json({ success: true, translations: lines, targetLang, method: "ai_batch" }); + } catch (_err) { + res.json({ success: true, translations: texts, method: "passthrough" }); + } +}); + +export default router; diff --git a/backend/routes/validateTokenRoutes.js b/backend/routes/validateTokenRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..dc8ab957482e72e67f5d67edd814b665147cac81 --- /dev/null +++ b/backend/routes/validateTokenRoutes.js @@ -0,0 +1,17 @@ +import express from "express"; +import { verifyFirebaseToken } from "../middleware/firebaseAuth.js"; + +const router = express.Router(); + +const validateToken = (req, res) => res.json({ + valid: true, + userId: req.userId, + role: req.userRole, + email: req.userEmail || null, +}); + +router.get("/validate-token", verifyFirebaseToken, validateToken); +router.get("/validate", verifyFirebaseToken, validateToken); +router.get("/token/validate", verifyFirebaseToken, validateToken); + +export default router; diff --git a/backend/routes/valuechainRoutes.js b/backend/routes/valuechainRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..8875b3c911571cc0fd34c059e060ec6bb2beca69 --- /dev/null +++ b/backend/routes/valuechainRoutes.js @@ -0,0 +1,352 @@ +/** + * Value Chain Routes + * API endpoints for the oilseed by-products marketplace + */ +import express from "express"; +import { + createListing, + getListings, + getListingById, + updateListing, + createOffer, + getOffers, + respondToOffer, + createTransformRequest, + getMarketSummary, +} from "../controllers/valuechainController.js"; +import { verifyToken } from "../middleware/authMiddleware.js"; + +const router = express.Router(); + +/** + * @swagger + * tags: + * name: ValueChain + * description: Oilseed by-products marketplace API + */ + +/** + * @swagger + * /valuechain/listings: + * post: + * summary: Create a new listing + * tags: [ValueChain] + * security: + * - bearerAuth: [] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - productType + * - quantityKg + * - harvestDate + * - location + * - reservePrice + * properties: + * productType: + * type: string + * enum: [oilseed_meal, oilseed_cake, oilseed_husk, groundnut, sunflower, soybean, mustard, sesame, safflower, castor, linseed, niger, other] + * productName: + * type: string + * quantityKg: + * type: number + * grade: + * type: string + * enum: [A, B, C, premium, standard, economy] + * harvestDate: + * type: string + * format: date + * location: + * type: object + * properties: + * coordinates: + * type: array + * items: + * type: number + * address: + * type: string + * state: + * type: string + * reservePrice: + * type: number + * photos: + * type: array + * items: + * type: object + * responses: + * 201: + * description: Listing created successfully + * 400: + * description: Invalid input + * 401: + * description: Unauthorized + */ +router.post("/listings", verifyToken, createListing); + +/** + * @swagger + * /valuechain/listings: + * get: + * summary: Get listings with search and filtering + * tags: [ValueChain] + * parameters: + * - in: query + * name: productType + * schema: + * type: string + * - in: query + * name: lat + * schema: + * type: number + * - in: query + * name: lng + * schema: + * type: number + * - in: query + * name: radius + * schema: + * type: number + * default: 50 + * - in: query + * name: minPrice + * schema: + * type: number + * - in: query + * name: maxPrice + * schema: + * type: number + * - in: query + * name: sort + * schema: + * type: string + * default: -createdAt + * - in: query + * name: page + * schema: + * type: integer + * default: 1 + * - in: query + * name: limit + * schema: + * type: integer + * default: 20 + * responses: + * 200: + * description: List of listings + */ +router.get("/listings", getListings); + +/** + * @swagger + * /valuechain/listings/{id}: + * get: + * summary: Get a listing by ID + * tags: [ValueChain] + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: string + * responses: + * 200: + * description: Listing details + * 404: + * description: Listing not found + */ +router.get("/listings/:id", getListingById); + +/** + * @swagger + * /valuechain/listings/{id}: + * put: + * summary: Update a listing + * tags: [ValueChain] + * security: + * - bearerAuth: [] + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: string + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * responses: + * 200: + * description: Listing updated + * 403: + * description: Not authorized + * 404: + * description: Listing not found + */ +router.put("/listings/:id", verifyToken, updateListing); + +/** + * @swagger + * /valuechain/offer: + * post: + * summary: Create an offer on a listing + * tags: [ValueChain] + * security: + * - bearerAuth: [] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - listingId + * - offeredPrice + * - quantityKg + * properties: + * listingId: + * type: string + * offeredPrice: + * type: number + * quantityKg: + * type: number + * message: + * type: string + * expiresInHours: + * type: number + * default: 48 + * responses: + * 201: + * description: Offer created + * 400: + * description: Invalid input + */ +router.post("/offer", verifyToken, createOffer); + +/** + * @swagger + * /valuechain/offers: + * get: + * summary: Get offers for the current user + * tags: [ValueChain] + * security: + * - bearerAuth: [] + * parameters: + * - in: query + * name: role + * schema: + * type: string + * enum: [buyer, seller] + * default: buyer + * - in: query + * name: status + * schema: + * type: string + * responses: + * 200: + * description: List of offers + */ +router.get("/offers", verifyToken, getOffers); + +/** + * @swagger + * /valuechain/offer/{id}/respond: + * put: + * summary: Respond to an offer (accept/reject/counter) + * tags: [ValueChain] + * security: + * - bearerAuth: [] + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: string + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - action + * properties: + * action: + * type: string + * enum: [accept, reject, counter] + * counterPrice: + * type: number + * counterMessage: + * type: string + * responses: + * 200: + * description: Response recorded + */ +router.put("/offer/:id/respond", verifyToken, respondToOffer); + +/** + * @swagger + * /valuechain/transformRequest: + * post: + * summary: Create a transform request (processor buying raw materials) + * tags: [ValueChain] + * security: + * - bearerAuth: [] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - rawMaterial + * properties: + * listingId: + * type: string + * requestType: + * type: string + * enum: [spot_purchase, contract_farming, toll_processing, buyback] + * rawMaterial: + * type: object + * properties: + * productType: + * type: string + * quantityKg: + * type: number + * responses: + * 201: + * description: Transform request created + */ +router.post("/transformRequest", verifyToken, createTransformRequest); + +/** + * @swagger + * /valuechain/market-summary: + * get: + * summary: Get aggregated market summary with supply-demand data + * tags: [ValueChain] + * parameters: + * - in: query + * name: productType + * schema: + * type: string + * - in: query + * name: state + * schema: + * type: string + * - in: query + * name: days + * schema: + * type: integer + * default: 30 + * responses: + * 200: + * description: Market summary data + */ +router.get("/market-summary", getMarketSummary); + +export default router; diff --git a/backend/routes/videoCallRoutes.js b/backend/routes/videoCallRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..62c24ec8739f530abbc1003867e479f7d64c6d01 --- /dev/null +++ b/backend/routes/videoCallRoutes.js @@ -0,0 +1,9 @@ +import express from 'express'; +import { startCall, joinCall } from '../controllers/videoCallController.js'; + +const router = express.Router(); + +router.post('/start', startCall); +router.post('/join', joinCall); + +export default router; \ No newline at end of file diff --git a/backend/routes/vqaRoutes.js b/backend/routes/vqaRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..868f0612574be8f06cd71f6590d51abcceadf4ac --- /dev/null +++ b/backend/routes/vqaRoutes.js @@ -0,0 +1,320 @@ +/** + * POST /api/vqa/answer + * AgroMind-VQA: Knowledge-Grounded Multimodal Agricultural Visual Question Answering + * + * The endpoint keeps the original single-image `image` field and also accepts up to + * four `images` fields for AG MMU-style multi-image reasoning. It supports the five + * image-grounded knowledge types used by the paper: disease/issue identification, + * symptom/visual description, management instructions, insect/pest identification, + * and species identification. + */ + +import express from "express"; +import multer from "multer"; +import { readFileSync } from "fs"; +import { fileURLToPath } from "url"; +import path from "path"; +import { generateAIContent, generateAIContentWithVision } from "../utils/aiHelper.js"; +import { LANGUAGE_MAP } from "../utils/aiOrchestrator.js"; + +const router = express.Router(); +const upload = multer({ + storage: multer.memoryStorage(), + limits: { fileSize: 10 * 1024 * 1024, files: 4 }, +}); + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const KNOWLEDGE_BASE = JSON.parse( + readFileSync(path.join(__dirname, "../data/agricultural_knowledge_base.json"), "utf-8") +); + +const FACTS_BY_SUBDOMAIN = KNOWLEDGE_BASE.reduce((acc, fact) => { + (acc[fact.subdomain] ||= []).push(fact); + return acc; +}, {}); + +const QUESTION_TYPES = { + auto: "auto", + "disease identification": "disease identification", + "symptom/visual description": "symptom/visual description", + "management instructions": "management instructions", + "insect/pest identification": "insect/pest identification", + "species identification": "species identification", +}; + +const QUESTION_TYPE_LABELS = { + "disease identification": "Disease/Issue Identification", + "symptom/visual description": "Symptom/Visual Description", + "management instructions": "Management Instructions", + "insect/pest identification": "Insect/Pest Identification", + "species identification": "Species Identification", +}; + +const SUBDOMAIN_KEYWORDS = { + "growing advice": /\b(sow(ing|ed|s)?|germinat\w*|transplant\w*|prun\w*|irrigat\w*|water(ing)? schedule|spac(e|ing) (between|apart)|cultivat\w*|propagat\w*|seedling\w*|nursery|when (to|should) (i|you) (plant|sow|transplant|prune|harvest)|harvest(ing)? time|growing season|growth stage|planting (time|depth|distance)|how (often|much) (should i |to )?water|best time to plant|soil preparation|days to (maturity|germinate)|planting guide)\b/i, + "pests control": /\b(pest\w*|insect\w*|aphid\w*|beetle\w*|larva\w*|caterpillar\w*|weevil\w*|moth\w*|mite\w*|worm\w*|flies|fly|bug\w*|grub\w*|locust\w*|thrips|whitefl(y|ies))\b/i, + "weed management": /\b(weed\w*|invasive plant\w*)\b/i, + "nutrient deficiency": /\b(nutrient\w*|nitrogen\w*|phosphorus|potassium|deficien\w*|fertiliz\w*|npk)\b/i, + "environmental stress": /\b(drought\w*|flood\w*|heat stress|cold stress|frost\w*|temperature stress|water stress|humidit\w*|environmental\w*|ndvi|ndwi)\b/i, + "disease advice": /\b(disease\w*|fungus|fungi|fungal|blight\w*|rot\w*|mildew\w*|rust\w*|wilt\w*|virus\w*|viral\w*|bacteri\w*|infect\w*|pathogen\w*|mold\w*|mould\w*|lesion\w*|canker\w*|scab\w*)\b/i, +}; + +const KNOWLEDGE_TYPE_KEYWORDS = { + "management instructions": /\b(treat\w*|control\w*|prevent\w*|spray\w*|pesticide\w*|fungicide\w*|insecticide\w*|manage\w*|remove\w*|avoid\w*|apply|applying|applied|recommend\w*|what should i do|how do i (fix|treat|control))\b/i, + "insect/pest identification": /\b(what (pest|insect|bug)|which (pest|insect|bug)|identify\w*.*(pest|insect)|name of (this|the) (pest|insect|bug))\b/i, + "species identification": /\b(what (species|plant|crop|variety)|which (species|plant|crop|variety)|identify\w*.*(plant|species)|what is this (plant|crop)|name of (this|the) (plant|species))\b/i, + "disease identification": /\b(what disease|which disease|what('| i)s wrong|why (is|are)|reason for|cause\w* of|what caused|spread\w*|transmit\w*)\b/i, + "symptom/visual description": /\b(spot\w*|yellow\w*|brown\w*|wilt\w*|discolor\w*|texture\w*|appear\w*|surface\w*|shape\w*|colou?r\w*|damage\w*|hole\w*|patch\w*|lesion\w*|growth|swelling|look\w* like|symptom\w*)\b/i, +}; + +function normalizeQuestionType(value) { + const normalized = String(value || "auto").trim().toLowerCase(); + return QUESTION_TYPES[normalized] || "auto"; +} + +function parseOptions(value) { + if (!value) return []; + try { + const parsed = typeof value === "string" ? JSON.parse(value) : value; + if (!Array.isArray(parsed)) return []; + return parsed + .map((option, index) => { + if (typeof option === "string") return { id: String.fromCharCode(65 + index), text: option.trim() }; + return { + id: String(option.id || String.fromCharCode(65 + index)).trim().toUpperCase(), + text: String(option.text || "").trim(), + }; + }) + .filter((option) => option.text) + .slice(0, 4); + } catch (_error) { + return []; + } +} + +function classifySubdomains(question, hasImage, sensorData, envData) { + const q = question.toLowerCase(); + const matched = new Set(); + + for (const [subdomain, pattern] of Object.entries(SUBDOMAIN_KEYWORDS)) { + if (pattern.test(q)) matched.add(subdomain); + } + + const hasSensorReading = sensorData && Object.values(sensorData).some((v) => v !== "" && v !== null && v !== undefined); + if (hasSensorReading) matched.add("nutrient deficiency"); + if (envData?.ndvi || envData?.ndwi || envData?.weather) matched.add("environmental stress"); + + if (hasImage && matched.size === 0) { + matched.add("disease advice"); + matched.add("pests control"); + } + + if (matched.size === 0) { + matched.add("disease advice"); + matched.add("generic identification"); + } + + return [...matched]; +} + +function classifyKnowledgeType(question, hasImage, requestedType = "auto") { + if (requestedType !== "auto") return requestedType; + const q = question.toLowerCase(); + for (const [knowledgeType, pattern] of Object.entries(KNOWLEDGE_TYPE_KEYWORDS)) { + if (pattern.test(q)) return knowledgeType; + } + return hasImage ? "symptom/visual description" : null; +} + +function retrieveRelevantKnowledge(question, hasImage, sensorData, envData, requestedType = "auto") { + const subdomains = classifySubdomains(question, hasImage, sensorData, envData); + const knowledgeType = classifyKnowledgeType(question, hasImage, requestedType); + + const retrieved = subdomains.map((subdomain) => { + const pool = FACTS_BY_SUBDOMAIN[subdomain] || []; + const byType = knowledgeType ? pool.filter((fact) => fact.knowledge_type === knowledgeType) : []; + const facts = (byType.length > 0 ? byType : pool).slice(0, 6); + return { + domain: subdomain, + knowledgeType: knowledgeType || (facts[0]?.knowledge_type ?? "symptom/visual description"), + facts: facts.map((fact) => fact.fact_text), + }; + }).filter((knowledge) => knowledge.facts.length > 0); + + if (retrieved.length === 0) { + const fallback = (FACTS_BY_SUBDOMAIN["disease advice"] || []).slice(0, 4); + return [{ + domain: "disease advice", + knowledgeType: knowledgeType || "symptom/visual description", + facts: fallback.map((fact) => fact.fact_text), + }]; + } + + return retrieved; +} + +function buildReasoningChain(sensorData, envData, imageCount, retrievedKnowledge) { + const chain = []; + + if (imageCount > 0) { + chain.push(`Rv (Visual): Analyzing ${imageCount} agricultural image${imageCount === 1 ? "" : "s"} for visual evidence`); + } + + if (sensorData && Object.values(sensorData).some((v) => v !== "" && v !== null && v !== undefined)) { + const parts = []; + if (sensorData.N) parts.push(`N=${sensorData.N} kg/ha`); + if (sensorData.P) parts.push(`P=${sensorData.P} kg/ha`); + if (sensorData.K) parts.push(`K=${sensorData.K} kg/ha`); + if (sensorData.pH) parts.push(`pH=${sensorData.pH}`); + if (sensorData.moisture) parts.push(`Moisture=${sensorData.moisture}%`); + if (sensorData.temperature) parts.push(`Temp=${sensorData.temperature}Β°C`); + if (sensorData.humidity) parts.push(`Humidity=${sensorData.humidity}%`); + if (parts.length > 0) chain.push(`Rs (Sensor): Soil sensor readings β€” ${parts.join(", ")}`); + } + + if (envData && (envData.ndvi || envData.ndwi || envData.weather)) { + const parts = []; + if (envData.ndvi) parts.push(`NDVI=${envData.ndvi}`); + if (envData.ndwi) parts.push(`NDWI=${envData.ndwi}`); + if (envData.weather) parts.push(`Weather: ${envData.weather}`); + if (parts.length > 0) chain.push(`Re (Environmental): Remote sensing & weather β€” ${parts.join(", ")}`); + } + + if (retrievedKnowledge && retrievedKnowledge.length > 0) { + const types = [...new Set(retrievedKnowledge.map((knowledge) => knowledge.knowledgeType))]; + const domains = retrievedKnowledge.map((knowledge) => knowledge.domain); + chain.push(`Rk (Knowledge): Retrieved ${types.join(", ")} facts from ${domains.join(", ")}`); + } + + return chain; +} + +function getSelectedOption(answer, mode, options) { + if (mode !== "mcq" || options.length === 0) return null; + const explicit = answer.match(/(?:selected option|correct option|answer|choice)\s*[:-]?\s*\(?([A-D])\)?/i); + if (explicit) return explicit[1].toUpperCase(); + const optionMatch = options.find((option) => new RegExp(`^\\s*${option.id}[.)\\s]`, "i").test(answer)); + return optionMatch?.id || null; +} + +router.post("/answer", upload.fields([ + { name: "image", maxCount: 1 }, + { name: "images", maxCount: 4 }, +]), async (req, res) => { + try { + const { + question, + lang = "en", + question_type: requestedType = "auto", + mode = "open", + options, + N, P, K, pH, moisture, temperature, humidity, + ndvi, ndwi, weather, + } = req.body; + + const normalizedQuestion = String(question || "").trim(); + if (!normalizedQuestion) { + return res.status(400).json({ success: false, error: "question is required" }); + } + if (normalizedQuestion.length > 1000) { + return res.status(400).json({ success: false, error: "question must be 1000 characters or fewer" }); + } + + const normalizedType = normalizeQuestionType(requestedType); + const normalizedMode = mode === "mcq" ? "mcq" : "open"; + const optionList = parseOptions(options); + if (normalizedMode === "mcq" && optionList.length !== 4) { + return res.status(400).json({ success: false, error: "multiple-choice mode requires exactly four options" }); + } + + const uploadedImages = [ + ...(req.files?.images || []), + ...(req.files?.image || []), + ].slice(0, 4); + const imageCount = uploadedImages.length; + const languageName = LANGUAGE_MAP[lang] || "English"; + const sensorData = { N, P, K, pH, moisture, temperature, humidity }; + const envData = { ndvi, ndwi, weather }; + const retrievedKnowledge = retrieveRelevantKnowledge(normalizedQuestion, imageCount > 0, sensorData, envData, normalizedType); + const reasoningChain = buildReasoningChain(sensorData, envData, imageCount, retrievedKnowledge); + const knowledgeContext = retrievedKnowledge + .map((knowledge) => `[${knowledge.domain} / ${QUESTION_TYPE_LABELS[knowledge.knowledgeType] || knowledge.knowledgeType}]\n${knowledge.facts.join("\n")}`) + .join("\n\n"); + const reasoningContext = reasoningChain.length > 0 + ? `\nReasoning Chain:\n${reasoningChain.map((reasoning) => `β€’ ${reasoning}`).join("\n")}` + : ""; + const optionsContext = optionList.length > 0 + ? `\nCandidate options (use exactly one of these in MCQ mode):\n${optionList.map((option) => `${option.id}. ${option.text}`).join("\n")}` + : ""; + + const systemPrompt = `You are AgroMind-VQA, an agricultural visual question answering assistant following the AG MMU benchmark principles. + +Answer the farmer's question in ${languageName} by grounding the response in the supplied image evidence, optional sensor/environment readings, and the retrieved agricultural facts. + +Requested knowledge type: ${QUESTION_TYPE_LABELS[normalizedType] || "Automatically selected"} +Answer mode: ${normalizedMode === "mcq" ? "four-option multiple choice" : "open-ended"} + +AGRICULTURAL KNOWLEDGE BASE: +${knowledgeContext} +${reasoningContext} +${optionsContext} + +Rules: +- Focus on the requested knowledge type: disease/issue identification, symptom/visual description, management instructions, insect/pest identification, or species identification. +- Explicitly describe only visual evidence that is actually visible in the uploaded image(s); do not invent image details. +- If the evidence is insufficient, conflicting, or the expert facts are uncertain, say so clearly and provide a cautious next step instead of a confident diagnosis. +- For management advice, avoid inventing pesticide rates or unsafe instructions; recommend following the product label and local agricultural guidance. +- In MCQ mode, start with exactly 'Selected option: X' where X is A, B, C, or D, then give a brief evidence-based explanation. Never invent a fifth option. +- In open-ended mode, give a concise direct answer followed by the visual/knowledge-based reasoning and practical next step when appropriate. +- Never fabricate measurements, sources, government schemes, or expert certainty.`; + + let answer; + if (imageCount > 0) { + const visionImages = uploadedImages.map((file) => ({ + base64: file.buffer.toString("base64"), + mimeType: file.mimetype || "image/jpeg", + })); + answer = await generateAIContentWithVision(`${systemPrompt}\n\nFarmer's Question: ${normalizedQuestion}`, visionImages, "image/jpeg", { + temperature: 0.35, + maxTokens: 1024, + }); + } else { + answer = await generateAIContent(`${systemPrompt}\n\nFarmer's Question: ${normalizedQuestion}`, { + temperature: 0.35, + maxTokens: 1024, + }); + } + + const answerText = String(answer || "").trim(); + const selectedOption = getSelectedOption(answerText, normalizedMode, optionList); + return res.json({ + success: true, + answer: answerText, + lang, + mode: normalizedMode, + question_type: normalizedType, + question_type_label: QUESTION_TYPE_LABELS[normalizedType] || "Auto-selected agricultural VQA", + options: optionList, + selected_option: selectedOption, + image_count: imageCount, + reasoning_chain: reasoningChain, + retrieved_knowledge_domains: retrievedKnowledge.map((knowledge) => knowledge.domain), + modalities_used: { + image: imageCount > 0, + sensor: reasoningChain.some((reasoning) => reasoning.startsWith("Rs")), + environmental: reasoningChain.some((reasoning) => reasoning.startsWith("Re")), + knowledge_base: true, + }, + uncertainty_note: "Visual answers are decision support, not a substitute for local expert diagnosis. Verify uncertain or high-stakes cases before acting.", + }); + } catch (err) { + console.error("VQA error:", err.message); + return res.status(500).json({ + success: false, + error: "VQA system unavailable", + }); + } +}); + +export { normalizeQuestionType, parseOptions, classifyKnowledgeType, buildReasoningChain }; +export default router; diff --git a/backend/routes/waterOptimizationRoutes.js b/backend/routes/waterOptimizationRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..17b2e5b9a4b80f1ecf99eeb15c0262cfbb28f7d4 --- /dev/null +++ b/backend/routes/waterOptimizationRoutes.js @@ -0,0 +1,14 @@ +import { Router } from "express"; +import { verifyToken } from "../middleware/jwt.js"; +import { getWaterOptimizations } from "../controllers/waterOptimizationController.js"; + +const router = Router(); + +// Route to get water optimization recommendation +router.post( + "/water-optimization", + verifyToken, + getWaterOptimizations +); + +export default router; \ No newline at end of file diff --git a/backend/routes/weatherRoutes.js b/backend/routes/weatherRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..09eba55ba6f1ba24aeffdf8cc44f4d10b796ebf3 --- /dev/null +++ b/backend/routes/weatherRoutes.js @@ -0,0 +1,43 @@ +/** + * Weather Routes + * Proxies weather API calls to avoid exposing API keys in the frontend + */ +import express from "express"; +import axios from "axios"; + +const router = express.Router(); + +// GET /api/weather?city=CityName +router.get("/", async (req, res) => { + try { + const { city } = req.query; + if (!city) { + return res.status(400).json({ error: "city query parameter is required" }); + } + + const apiKey = process.env.OPENWEATHER_API_KEY; + if (!apiKey) { + return res.status(503).json({ error: "Weather service is not configured" }); + } + + const response = await axios.get( + `https://api.openweathermap.org/data/2.5/weather`, + { + params: { + q: city, + appid: apiKey, + units: "metric", + }, + timeout: 10000, + } + ); + + res.json(response.data); + } catch (error) { + const status = error.response?.status || 500; + const message = error.response?.data?.message || "Failed to fetch weather data"; + res.status(status).json({ error: message }); + } +}); + +export default router; diff --git a/backend/routes/yieldPredictionRoutes.js b/backend/routes/yieldPredictionRoutes.js new file mode 100644 index 0000000000000000000000000000000000000000..6a6d1f8e2dd93e8abef4971cb86d1bd810a8b1a0 --- /dev/null +++ b/backend/routes/yieldPredictionRoutes.js @@ -0,0 +1,295 @@ +import express from "express"; +const router = express.Router(); + +/* ═══════════════════════════════════════════════════════════ + Yield Prediction & Optimization Routes + AI-driven yield predictions for oilseed crops + ═══════════════════════════════════════════════════════════ */ + +// Historical yield data (reference baseline) +const OILSEED_YIELD_DATA = { + soybean: { avg_yield_kg_ha: 1200, max_yield: 2500, min_yield: 600 }, + mustard: { avg_yield_kg_ha: 1100, max_yield: 2200, min_yield: 500 }, + groundnut: { avg_yield_kg_ha: 1800, max_yield: 3200, min_yield: 800 }, + sunflower: { avg_yield_kg_ha: 1000, max_yield: 2000, min_yield: 400 }, + sesame: { avg_yield_kg_ha: 450, max_yield: 900, min_yield: 200 }, + castor: { avg_yield_kg_ha: 1500, max_yield: 2800, min_yield: 700 }, + linseed: { avg_yield_kg_ha: 600, max_yield: 1200, min_yield: 300 }, + safflower: { avg_yield_kg_ha: 800, max_yield: 1600, min_yield: 350 }, + niger: { avg_yield_kg_ha: 350, max_yield: 700, min_yield: 150 }, + palm_oil: { avg_yield_kg_ha: 4000, max_yield: 8000, min_yield: 2000 }, +}; + +const INTERVENTION_TEMPLATES = { + irrigation: { + name: "Optimized Irrigation Schedule", + impact_pct: 15, + cost_inr_ha: 5000, + description: "Drip/sprinkler irrigation at critical growth stages", + }, + pest_management: { + name: "Integrated Pest Management (IPM)", + impact_pct: 12, + cost_inr_ha: 3500, + description: "Monitored pest control with biological agents and targeted spraying", + }, + seed_variety: { + name: "High-Yield Seed Variety", + impact_pct: 20, + cost_inr_ha: 2000, + description: "Replace with certified high-yield variety suited to local conditions", + }, + soil_amendment: { + name: "Soil Health Restoration", + impact_pct: 10, + cost_inr_ha: 4500, + description: "Gypsum, organic matter, and micronutrient application based on soil test", + }, + fertilizer_optimization: { + name: "Precision Fertilizer Application", + impact_pct: 14, + cost_inr_ha: 6000, + description: "Soil-test based NPK + micronutrient application at optimal timing", + }, + weed_management: { + name: "Mechanical + Chemical Weed Control", + impact_pct: 8, + cost_inr_ha: 2500, + description: "Pre-emergence herbicide + inter-cultivation at 25 and 45 DAS", + }, +}; + +/** + * POST /predict + * Generate AI-driven yield prediction with interventions + */ +router.post("/predict", async (req, res) => { + try { + const { + crop = "soybean", + area_hectares = 1, + soil_type = "black", + soil_ph = 6.5, + organic_carbon = 0.5, + nitrogen = 250, + phosphorus = 20, + potassium = 200, + rainfall_mm = 800, + temperature_avg = 28, + humidity_pct = 65, + irrigation_type = "rainfed", + previous_crop = "wheat", + sowing_date: _sowing_date = null, + latitude = 21.15, + longitude = 79.09, + } = req.body; + + const cropData = OILSEED_YIELD_DATA[crop.toLowerCase()] || OILSEED_YIELD_DATA.soybean; + + // Calculate base yield based on conditions + let baseYield = cropData.avg_yield_kg_ha; + + // Soil adjustments + if (soil_ph >= 6.0 && soil_ph <= 7.5) baseYield *= 1.05; + else if (soil_ph < 5.5 || soil_ph > 8.0) baseYield *= 0.85; + + if (organic_carbon > 0.75) baseYield *= 1.08; + else if (organic_carbon < 0.3) baseYield *= 0.88; + + if (nitrogen > 300) baseYield *= 1.06; + else if (nitrogen < 150) baseYield *= 0.90; + + // Weather adjustments + if (rainfall_mm >= 600 && rainfall_mm <= 1200) baseYield *= 1.05; + else if (rainfall_mm < 400) baseYield *= 0.75; + else if (rainfall_mm > 1500) baseYield *= 0.90; + + if (temperature_avg >= 25 && temperature_avg <= 32) baseYield *= 1.03; + else if (temperature_avg > 38) baseYield *= 0.80; + + // Irrigation adjustment + if (irrigation_type === "drip") baseYield *= 1.15; + else if (irrigation_type === "sprinkler") baseYield *= 1.10; + else if (irrigation_type === "flood") baseYield *= 1.05; + + // Previous crop benefit + if (["wheat", "gram", "chickpea"].includes(previous_crop?.toLowerCase())) { + baseYield *= 1.05; + } + + const predicted_yield = Math.round(baseYield); + const total_production = Math.round(predicted_yield * area_hectares); + + // Generate intervention suggestions + const interventions = []; + if (irrigation_type === "rainfed") interventions.push(INTERVENTION_TEMPLATES.irrigation); + if (organic_carbon < 0.5) interventions.push(INTERVENTION_TEMPLATES.soil_amendment); + interventions.push(INTERVENTION_TEMPLATES.seed_variety); + interventions.push(INTERVENTION_TEMPLATES.pest_management); + if (nitrogen < 200) interventions.push(INTERVENTION_TEMPLATES.fertilizer_optimization); + interventions.push(INTERVENTION_TEMPLATES.weed_management); + + // Calculate potential yield with all interventions + const total_improvement = interventions.reduce((sum, i) => sum + i.impact_pct, 0); + const optimized_yield = Math.round(predicted_yield * (1 + Math.min(total_improvement, 50) / 100)); + const total_cost = interventions.reduce((sum, i) => sum + i.cost_inr_ha, 0) * area_hectares; + + res.json({ + success: true, + prediction: { + crop, + area_hectares, + predicted_yield_kg_ha: predicted_yield, + total_production_kg: total_production, + optimized_yield_kg_ha: optimized_yield, + yield_gap_pct: Math.round(((optimized_yield - predicted_yield) / predicted_yield) * 100), + confidence: 0.78, + benchmark: { + national_avg: cropData.avg_yield_kg_ha, + max_achievable: cropData.max_yield, + percentile: Math.round((predicted_yield / cropData.max_yield) * 100), + }, + }, + interventions: interventions.map((i) => ({ + ...i, + total_cost_inr: i.cost_inr_ha * area_hectares, + additional_yield_kg_ha: Math.round(predicted_yield * (i.impact_pct / 100)), + roi: Math.round(((predicted_yield * (i.impact_pct / 100) * 45) / i.cost_inr_ha) * 100) / 100, + })), + investment_summary: { + total_cost_inr: total_cost, + additional_revenue_inr: Math.round((optimized_yield - predicted_yield) * area_hectares * 45), + roi_ratio: Math.round(((optimized_yield - predicted_yield) * area_hectares * 45) / total_cost * 100) / 100, + }, + conditions: { soil_type, soil_ph, organic_carbon, nitrogen, phosphorus, potassium, rainfall_mm, temperature_avg, humidity_pct, irrigation_type, previous_crop }, + location: { latitude, longitude }, + }); + } catch (error) { + res.status(500).json({ error: "Yield prediction failed", details: error.message }); + } +}); + +/** + * GET /historical + * Get historical yield patterns for a crop + */ +router.get("/historical", (req, res) => { + const { crop = "soybean", state = "maharashtra", years = 10 } = req.query; + const cropData = OILSEED_YIELD_DATA[crop.toLowerCase()] || OILSEED_YIELD_DATA.soybean; + + const historical = []; + const currentYear = new Date().getFullYear(); + for (let i = 0; i < parseInt(years); i++) { + const year = currentYear - parseInt(years) + i; + const variation = 0.85 + Math.random() * 0.3; + const yieldVal = Math.round(cropData.avg_yield_kg_ha * variation); + historical.push({ + year, + yield_kg_ha: yieldVal, + area_mha: Math.round((2 + Math.random() * 3) * 100) / 100, + production_mt: Math.round(yieldVal * (2 + Math.random() * 3) * 100) / 100, + rainfall_mm: Math.round(600 + Math.random() * 600), + }); + } + + res.json({ + success: true, + crop, + state, + historical, + trend: { + direction: "increasing", + avg_annual_change_pct: 2.3, + forecast_next_year: Math.round(cropData.avg_yield_kg_ha * 1.05), + }, + }); +}); + +/** + * POST /farm-yield-estimation + * High-resolution farm-level yield estimation using spatial data + */ +router.post("/farm-yield-estimation", async (req, res) => { + try { + const { + farm_id, + crop = "soybean", + area_hectares = 2, + ndvi_values = [], + drone_data = null, + soil_moisture: _soil_moisture = null, + growth_stage = "flowering", + latitude = 21.15, + longitude = 79.09, + } = req.body; + + // Simulate DSSAT crop simulation model output + const avgNDVI = ndvi_values.length > 0 + ? ndvi_values.reduce((a, b) => a + b, 0) / ndvi_values.length + : 0.45 + Math.random() * 0.35; + + const cropData = OILSEED_YIELD_DATA[crop.toLowerCase()] || OILSEED_YIELD_DATA.soybean; + + // NDVI-based yield correlation + const ndvi_yield_factor = Math.min(1.3, Math.max(0.5, avgNDVI * 2)); + const spatial_yield = Math.round(cropData.avg_yield_kg_ha * ndvi_yield_factor); + + // Growth stage adjustments + const stage_factors = { vegetative: 0.9, flowering: 1.0, pod_filling: 1.05, maturity: 1.0 }; + const stage_factor = stage_factors[growth_stage] || 1.0; + const estimated_yield = Math.round(spatial_yield * stage_factor); + + // Generate yield map zones (simulate drone/satellite-derived spatial variability) + const zones = []; + for (let i = 0; i < 5; i++) { + const zoneNDVI = avgNDVI + (Math.random() - 0.5) * 0.2; + zones.push({ + zone_id: `Z${i + 1}`, + area_pct: Math.round(20 + (Math.random() - 0.5) * 10), + ndvi: Math.round(zoneNDVI * 100) / 100, + estimated_yield_kg_ha: Math.round(cropData.avg_yield_kg_ha * zoneNDVI * 2), + health_status: zoneNDVI > 0.6 ? "good" : zoneNDVI > 0.4 ? "moderate" : "stressed", + recommendation: zoneNDVI < 0.4 ? "Needs intervention: check irrigation and nutrient status" : "Continue monitoring", + }); + } + + res.json({ + success: true, + farm_id, + estimation: { + crop, + area_hectares, + estimated_yield_kg_ha: estimated_yield, + total_production_kg: Math.round(estimated_yield * area_hectares), + avg_ndvi: Math.round(avgNDVI * 100) / 100, + growth_stage, + confidence: 0.82, + data_source: drone_data ? "drone_multispectral" : "satellite_sentinel2", + model: "DSSAT_CROPGRO_v4.8", + }, + yield_map: { + zones, + spatial_variability_cv: Math.round(Math.random() * 20 + 10), + }, + location: { latitude, longitude }, + }); + } catch (error) { + res.status(500).json({ error: "Farm yield estimation failed", details: error.message }); + } +}); + +/** + * GET /crops + * List available oilseed crops for prediction + */ +router.get("/crops", (req, res) => { + const crops = Object.entries(OILSEED_YIELD_DATA).map(([name, data]) => ({ + name, + display_name: name.charAt(0).toUpperCase() + name.slice(1).replace("_", " "), + avg_yield_kg_ha: data.avg_yield_kg_ha, + max_yield_kg_ha: data.max_yield, + })); + res.json({ success: true, crops }); +}); + +export default router; diff --git a/backend/server.js b/backend/server.js new file mode 100644 index 0000000000000000000000000000000000000000..8b058be5fbe474384c6ed71187d3c42035782e73 --- /dev/null +++ b/backend/server.js @@ -0,0 +1,293 @@ +import "dotenv/config"; +import express from "express"; +import cors from "cors"; +import cookieParser from "cookie-parser"; +import morgan from "morgan"; +import http from "http"; +import { Server } from "socket.io"; +import { spawn } from "child_process"; +import path from "path"; +import { fileURLToPath } from "url"; + +import authRoute from "./routes/authRoute.js"; +import validateTokenRoutes from "./routes/validateTokenRoutes.js"; +import recommendationRoute from "./routes/recommendationRoute.js"; +import taskRoute from "./routes/taskRoute.js"; +import recordRoute from "./routes/recordRoute.js"; +import cropRoute from "./routes/cropRoutes.js"; +import irrigationRoute from "./routes/irrigationRoute.js"; +import farmingNewsRoute from "./routes/farmingNewsRoute.js"; +import notificationRoutes from "./routes/notificationsRoutes.js"; +import blogRecommendationRoute from "./routes/blogRecommendationsRoute.js"; +import expertDetailsRoutes from "./routes/expertDetailsRoute.js"; +import farmerDetailsRoutes from "./routes/farmerDetailsRoute.js"; +import postRoutes from "./routes/postRoutes.js"; +import getExpertsRoutes from "./routes/getExpertsRoute.js"; +import appointmentRoutes from "./routes/appointmentRoutes.js"; +import videoCallRoutes from "./routes/videoCallRoutes.js"; +import detectHarvestReadinessRoutes from "./routes/detectHarvestReadinessRoutes.js"; +import waterOptimizationRoutes from "./routes/waterOptimizationRoutes.js"; +import soilHealthRoutes from "./routes/soilHealthRoutes.js"; +import cropRotationRoutes from "./routes/cropRotationRoutes.js"; +import pestOutbreakRoutes from "./routes/pestOutbreakRoutes.js"; +import marketPredictionRoutes from "./routes/marketPredictionRoutes.js"; +import geoPestDiseaseHeatmapRoutes from "./routes/geoPestDiseaseHeatmapRoutes.js"; +import getLoanEligibilityReportRoutes from "./routes/getLoanEligibilityReportRoutes.js"; +import valuechainRoutes from "./routes/valuechainRoutes.js"; +import hedgingRoutes from "./routes/hedgingRoutes.js"; +import cropEconomicsRoutes from "./routes/cropEconomicsRoutes.js"; +import oilPalmRoutes from "./routes/oilPalmRoutes.js"; +import crmTrackingRoutes from "./routes/crmTrackingRoutes.js"; +import milletRoutes from "./routes/milletRoutes.js"; +import firebaseAuthRoutes from "./routes/firebaseAuthRoutes.js"; +import mrvRoutes from "./routes/mrvRoutes.js"; +import ndviRoutes from "./routes/ndviRoutes.js"; +import mandiRoutes from "./routes/mandiRoutes.js"; +import communityRoutes from "./routes/communityRoutes.js"; +import translateRoutes from "./routes/translateRoutes.js"; +import geocodeRoutes from "./routes/geocodeRoutes.js"; +import weatherRoutes from "./routes/weatherRoutes.js"; +import aiModelRoutes from "./routes/aiModelRoutes.js"; +import assistantRoute from "./routes/assistantRoute.js"; +import yieldPredictionRoutes from "./routes/yieldPredictionRoutes.js"; +import tariffSimulatorRoutes from "./routes/tariffSimulatorRoutes.js"; +import cropicRoutes from "./routes/cropicRoutes.js"; +import vqaRoutes from "./routes/vqaRoutes.js"; +import socketManager from "./socket/socketManager.js"; +import { apiLimiter, authLimiter } from "./middleware/rateLimiter.js"; +import { languageMiddleware } from "./middleware/languageMiddleware.js"; +import { securityHeaders, errorHandler } from "./middleware/securityMiddleware.js"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// ===== AI Backend Auto-Spawn (dev only) ===== +// In development, automatically start the Python AI backend (ai-backend/app.py) +// so ML predictions work without manually running a separate process. +// Models are lazy-loaded from HF Hub on first request and cached locally. +const spawnAiBackend = () => { + if (process.env.NODE_ENV === "production") return; + + const aiDir = path.resolve(__dirname, "../ai-backend"); + // Try python3 first, fall back to python (Windows) + const pythonCmd = process.platform === "win32" ? "python" : "python3"; + + const ai = spawn(pythonCmd, ["app.py"], { + cwd: aiDir, + stdio: ["ignore", "pipe", "pipe"], + env: { ...process.env }, + }); + + ai.stdout.on("data", (d) => process.stdout.write(`[ai-backend] ${d}`)); + ai.stderr.on("data", (d) => process.stderr.write(`[ai-backend] ${d}`)); + ai.on("error", (err) => + console.warn(`[ai-backend] Failed to start: ${err.message}. Run \`pip install -r ai-backend/requirements.txt && python ai-backend/app.py\` manually.`) + ); + ai.on("close", (code) => { + if (code !== 0 && code !== null) { + console.warn(`[ai-backend] Exited with code ${code}. ML endpoints will be unavailable.`); + } + }); + + return ai; +}; + +// ===== Environment Validation ===== +if ( + process.env.NODE_ENV === "production" && + (!process.env.FIREBASE_PROJECT_ID || !(process.env.FIREBASE_API_KEY || process.env.VITE_FIREBASE_API_KEY)) +) { + console.error("FATAL: FIREBASE_PROJECT_ID and FIREBASE_API_KEY are required in production"); + process.exit(1); +} + +const app = express(); + +const PORT = process.env.PORT || 7860; + +// Allowed origins: keep production list strict, but permit common dev hosts when not in production. +const allowedDomains = [ + "https://agro-mind-roan.vercel.app", + "https://agro-mind-eta.vercel.app", + "https://arko007-agromind-backend.hf.space", +]; + +// Add configured frontend URL (from .env) if present +if (process.env.FRONTEND_URL) { + allowedDomains.push(process.env.FRONTEND_URL); +} + +// Shared allow/deny decision used by both the explicit OPTIONS short-circuit +// below and the `cors` middleware's origin callback, so the two never drift. +function isOriginAllowed(origin) { + if (!origin) return true; // non-browser calls (curl, server-to-server) + if (allowedDomains.includes(origin)) return true; + + // Development convenience: allow localhost and GitHub Codespaces / app.github.dev tunnels + // Only when not running in production to avoid relaxing CORS in production. + if (process.env.NODE_ENV !== "production") { + try { + const lower = origin.toLowerCase(); + if ( + lower.includes("localhost") || + lower.includes("127.0.0.1") || + lower.includes("app.github.dev") || + lower.includes("github.dev") || + lower === "http://localhost:5173" || + lower === "https://solid-journey-r4w4qvjjpp9g257j6-5173.app.github.dev" + ) { + return true; + } + } catch (_e) { + // fallthrough to deny + } + } + + return false; +} + +// ===== Middleware ===== + +// Explicit CORS preflight short-circuit, placed before everything else. +// Production OPTIONS responses were observed coming back 200 (not the `cors` +// package's own default 204) with every CORS header present EXCEPT +// Access-Control-Allow-Credentials -- something ahead of the app (most +// likely the HF Spaces reverse proxy) appears to answer OPTIONS before +// `cors()` gets a chance to. Since the frontend uses axios +// withCredentials:true on every call, a credentialed request needs that +// header on BOTH the preflight and the actual response per the CORS spec; +// missing it on just the preflight silently broke every feature for +// logged-in browser users while direct API calls looked completely fine. +// This guarantees a correct preflight regardless of what's intercepting +// OPTIONS downstream. The `cors()` middleware below is untouched and still +// handles all non-OPTIONS responses exactly as before. +app.use((req, res, next) => { + if (req.method !== "OPTIONS") return next(); + + const origin = req.headers.origin; + if (origin && isOriginAllowed(origin)) { + res.setHeader("Access-Control-Allow-Origin", origin); + res.setHeader("Access-Control-Allow-Credentials", "true"); + res.setHeader("Vary", "Origin"); + } + res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS"); + res.setHeader( + "Access-Control-Allow-Headers", + req.headers["access-control-request-headers"] || "Content-Type, Authorization, Accept-Language, X-Requested-With" + ); + res.setHeader("Access-Control-Max-Age", "600"); + return res.sendStatus(204); +}); + +app.use(securityHeaders); +app.use(cookieParser()); + +app.use( + cors({ + origin: function (origin, callback) { + if (isOriginAllowed(origin)) return callback(null, true); + return callback(new Error("Not allowed by CORS")); + }, + methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"], + allowedHeaders: ["Content-Type", "Authorization", "Accept-Language", "X-Requested-With"], + credentials: true, + }) +); + +app.use(express.json()); +app.use(morgan("dev")); +app.use(languageMiddleware); + +app.use("/api", apiLimiter); +app.use("/api/auth", authLimiter); + +// ===== Socket Setup ===== +const server = http.createServer(app); + +const io = new Server(server, { + cors: { + origin: allowedDomains, + credentials: true, + methods: ["GET", "POST"], + }, +}); + +app.set("socketio", io); +socketManager(io); + +// ===== Routes ===== +app.use("/api/video-call", videoCallRoutes); +app.use("/api/appointments", appointmentRoutes); +app.use("/api/auth", authRoute); +app.use("/api/auth", validateTokenRoutes); +app.use("/api", recommendationRoute); +app.use("/api", taskRoute); +app.use("/api/records", recordRoute); +app.use("/api/crops", cropRoute); +app.use("/api/irrigation", irrigationRoute); +app.use("/api/news", farmingNewsRoute); +app.use("/api", notificationRoutes); +app.use("/api", blogRecommendationRoute); +app.use("/api/expert-details", expertDetailsRoutes); +app.use("/api/farmer-details", farmerDetailsRoutes); +app.use("/api/posts", postRoutes); +app.use("/api/users", getExpertsRoutes); +app.use("/api", detectHarvestReadinessRoutes); +app.use("/api", waterOptimizationRoutes); +app.use("/api", soilHealthRoutes); +app.use("/api", cropRotationRoutes); +app.use("/api", pestOutbreakRoutes); +app.use("/api", marketPredictionRoutes); +app.use("/api", geoPestDiseaseHeatmapRoutes); +app.use("/api", getLoanEligibilityReportRoutes); +app.use("/api/valuechain", valuechainRoutes); +app.use("/api/hedging", hedgingRoutes); +app.use("/api/crop-economics", cropEconomicsRoutes); +app.use("/api/oilpalm", oilPalmRoutes); +app.use("/api/crm", crmTrackingRoutes); +app.use("/api/millets", milletRoutes); +app.use("/api/auth", firebaseAuthRoutes); +app.use("/api/mrv", mrvRoutes); +app.use("/api/ndvi", ndviRoutes); +app.use("/api/mandi", mandiRoutes); +app.use("/api/community", communityRoutes); +app.use("/api/translate", translateRoutes); +app.use("/api/geocode", geocodeRoutes); +app.use("/api/weather", weatherRoutes); +app.use("/api/ml", aiModelRoutes); +app.use("/api/assistant", assistantRoute); +app.use("/api/yield", yieldPredictionRoutes); +app.use("/api/tariff", tariffSimulatorRoutes); +app.use("/api/cropic", cropicRoutes); +app.use("/api/vqa", vqaRoutes); + +// ===== Global Error Handler ===== +app.use(errorHandler); + +// ===== Basic Routes ===== +app.get("/", (req, res) => { + res.status(200).json({ message: "API is running..." }); +}); + +const startTime = Date.now(); + +app.get("/health", async (req, res) => { + res.status(200).json({ + status: "ok", + uptime: Math.floor((Date.now() - startTime) / 1000), + services: { firestore: "user-token-rest" }, + timestamp: new Date().toISOString(), + }); +}); + +// ===== Start Server ===== +const startServer = async () => { + // Auto-start the AI backend in development mode + spawnAiBackend(); + + server.listen(PORT, "0.0.0.0", () => { + console.log(`Server is running on port ${PORT}`); + }); +}; + +startServer(); diff --git a/backend/socket/appointmentSocket.js b/backend/socket/appointmentSocket.js new file mode 100644 index 0000000000000000000000000000000000000000..333c626c6cae01de46f0666ced25e907aebc4426 --- /dev/null +++ b/backend/socket/appointmentSocket.js @@ -0,0 +1,51 @@ +// socket/appointmentSocket.js +import User from '../models/auth.model.js'; + +export default function initAppointmentSocket(io) { + io.on('connection', (socket) => { + console.log("New user connected with socketId:", socket.id); + + // Event when user sets their socketId + socket.on('setUser', async (userId) => { + try { + const user = await User.findById(userId); + + if (!user) { + console.error("User not found!"); + return; + } + + // Save socketId in the user document + user.socketId = socket.id; + if (!user.email) { + console.error("User email is missing, cannot update socketId."); + return; + } + + await user.save(); + console.log(`Socket ID saved for user ${user.email}`); + } catch (error) { + console.error("Error saving socketId:", error.message); + } + }); + + // Event when a user starts an appointment + socket.on('start-appointment', (data) => { + const { appointmentId } = data; + socket.join(appointmentId); + io.to(appointmentId).emit('appointment-started', { appointmentId }); + }); + + // Event when a user joins an appointment + socket.on('join-appointment', (data) => { + const { appointmentId } = data; + socket.join(appointmentId); + io.to(appointmentId).emit('appointment-joined', { appointmentId }); + }); + + // Handle disconnect + socket.on('disconnect', () => { + console.log(`User disconnected from appointment socket: ${socket.id}`); + }); + }); +} diff --git a/backend/socket/socketManager.js b/backend/socket/socketManager.js new file mode 100644 index 0000000000000000000000000000000000000000..9ffef5919179617ea0da580edb5bb479a8931be2 --- /dev/null +++ b/backend/socket/socketManager.js @@ -0,0 +1,11 @@ +// socket/socketManager.js +import initVideoCallSocket from './videoCallSocket.js'; +import initAppointmentSocket from './appointmentSocket.js'; + +export default function socketManager(io) { + // Initialize socket logic for video calls + initVideoCallSocket(io); + + // Initialize socket logic for appointment bookings + initAppointmentSocket(io); +} diff --git a/backend/socket/videoCallSocket.js b/backend/socket/videoCallSocket.js new file mode 100644 index 0000000000000000000000000000000000000000..7570d0a73d40eb15a42ac8f592903d6a0fcb9d21 --- /dev/null +++ b/backend/socket/videoCallSocket.js @@ -0,0 +1,80 @@ +import Appointment from "../models/appointmentModel.js"; + +const videoCallSocket = (io) => { + io.on('connection', (socket) => { + console.log('A user connected'); + + // Handle the join-call event + socket.on('join-call', async ({ appointmentId, role }) => { + console.log(`User with role ${role} is joining call for appointment ${appointmentId}`); + + const appointment = await Appointment.findById(appointmentId).populate('farmerId expertId'); + if (!appointment) { + console.log(`Appointment not found: ${appointmentId}`); + return; + } + + if (role === 'farmer') { + io.to(appointment.expertId.socketId).emit('join-call', { + appointmentId, + role: 'expert', + message: 'Farmer is ready to join the call!', + }); + socket.join(appointmentId); // Join the socket room + } else if (role === 'expert') { + io.to(appointment.farmerId.socketId).emit('join-call', { + appointmentId, + role: 'farmer', + message: 'Expert is ready to join the call!', + }); + socket.join(appointmentId); // Join the socket room + } + }); + + // Handle the video call offer (from farmer to expert) + socket.on('video-call-offer', (offerData) => { + const { appointmentId, offer, role } = offerData; + const targetRole = role === 'farmer' ? 'expert' : 'farmer'; + + // Send the offer to the other user (expert or farmer) + io.to(appointmentId).emit('video-call-offer', { + offer, + appointmentId, + role: targetRole, + }); + }); + + // Handle the video call answer (from expert to farmer) + socket.on('video-call-answer', (answerData) => { + const { appointmentId, answer, role } = answerData; + const targetRole = role === 'farmer' ? 'expert' : 'farmer'; + + // Send the answer to the other user (expert or farmer) + io.to(appointmentId).emit('video-call-answer', { + answer, + appointmentId, + role: targetRole, + }); + }); + + // Handle ICE candidates + socket.on('ice-candidate', (candidateData) => { + const { appointmentId, candidate, role } = candidateData; + const targetRole = role === 'farmer' ? 'expert' : 'farmer'; + + // Send the ICE candidate to the other user (expert or farmer) + io.to(appointmentId).emit('ice-candidate', { + candidate, + appointmentId, + role: targetRole, + }); + }); + + // Handle disconnect event + socket.on('disconnect', () => { + console.log('User disconnected'); + }); + }); +}; + +export default videoCallSocket; diff --git a/backend/tests/aiHelper.test.js b/backend/tests/aiHelper.test.js new file mode 100644 index 0000000000000000000000000000000000000000..d76940dae1c5f7488e3b637e829055fd75bc8fec --- /dev/null +++ b/backend/tests/aiHelper.test.js @@ -0,0 +1,80 @@ +/** + * AI Helper Utility Tests + * + * Tests for the AI helper utility that uses Groq API + */ + +import { generateAIContent, getAIProvider } from '../utils/aiHelper.js'; + +describe('AI Helper Utility', () => { + const originalEnv = process.env; + + beforeEach(() => { + process.env = { ...originalEnv }; + }); + + afterEach(() => { + process.env = originalEnv; + }); + + describe('getAIProvider', () => { + it('should return "groq" when GROQ_API_KEY is set', () => { + process.env.GROQ_API_KEY = 'test-groq-key'; + + const provider = getAIProvider(); + expect(provider).toBe('groq'); + }); + + it('should return "none" when no API key is set', () => { + delete process.env.GROQ_API_KEY; + + const provider = getAIProvider(); + expect(provider).toBe('none'); + }); + }); + + describe('generateAIContent', () => { + it('should throw error when GROQ_API_KEY is not configured', async () => { + delete process.env.GROQ_API_KEY; + + await expect(generateAIContent('test prompt')).rejects.toThrow( + 'GROQ_API_KEY is not configured' + ); + }); + + it('should accept temperature and maxTokens options', () => { + const options = { + temperature: 0.8, + maxTokens: 1024, + model: 'llama-3.3-70b-versatile' + }; + + expect(options.temperature).toBe(0.8); + expect(options.maxTokens).toBe(1024); + expect(options.model).toBe('llama-3.3-70b-versatile'); + }); + }); + + describe('Integration with Controllers', () => { + it('should be importable from controllers', () => { + expect(generateAIContent).toBeDefined(); + expect(typeof generateAIContent).toBe('function'); + expect(getAIProvider).toBeDefined(); + expect(typeof getAIProvider).toBe('function'); + }); + + it('should accept string prompts', () => { + const prompt = 'Test farming recommendation prompt'; + expect(typeof prompt).toBe('string'); + expect(prompt.length).toBeGreaterThan(0); + }); + + it('should validate Groq API key requirement', async () => { + delete process.env.GROQ_API_KEY; + + await expect(generateAIContent('test')).rejects.toThrow( + 'GROQ_API_KEY is not configured' + ); + }); + }); +}); diff --git a/backend/tests/aiModelRoutes.test.js b/backend/tests/aiModelRoutes.test.js new file mode 100644 index 0000000000000000000000000000000000000000..74e912bde4d0a9e754e68b7e44f0167e34b5c6c7 --- /dev/null +++ b/backend/tests/aiModelRoutes.test.js @@ -0,0 +1,195 @@ +import { jest } from '@jest/globals'; +import express from 'express'; +import request from 'supertest'; + +const buildAppWithRoute = async () => { + const { default: router } = await import(`../routes/aiModelRoutes.js?test=${Date.now()}`); + const app = express(); + app.use(express.json()); + app.use('/api/ml', router); + return app; +}; + +describe('AI model route proxy failover', () => { + const originalEnv = { ...process.env }; + const originalFetch = global.fetch; + + afterEach(() => { + process.env = { ...originalEnv }; + global.fetch = originalFetch; + jest.resetModules(); + }); + + it('falls back to inferred HF AI backend when localhost fails', async () => { + process.env.AI_BACKEND_URL = ''; + process.env.SPACE_HOST = 'arko007-agromind-backend.hf.space'; + + const calls = []; + global.fetch = jest.fn(async (url) => { + calls.push(url); + if (String(url).startsWith('https://arko007-agromind-ai-backend.hf.space')) { + return { + status: 200, + text: async () => JSON.stringify({ crop: 'rice' }), + }; + } + + throw new Error('connect ECONNREFUSED 127.0.0.1:5000'); + }); + + const app = await buildAppWithRoute(); + const response = await request(app) + .post('/api/ml/crop-recommendation') + .send({ N: 33, P: 36, K: 62 }); + + expect(response.status).toBe(200); + expect(response.body.crop).toBe('rice'); + expect(calls[0]).toBe('https://arko007-agromind-ai-backend.hf.space/crop_recommendation'); + }); + + it('returns diagnostic details when all candidates fail', async () => { + process.env.AI_BACKEND_URL = 'https://invalid-ai-service.example.com'; + process.env.SPACE_HOST = 'arko007-agromind-backend.hf.space'; + + global.fetch = jest.fn(async () => { + throw new Error('upstream unavailable'); + }); + + const app = await buildAppWithRoute(); + const response = await request(app) + .post('/api/ml/crop-recommendation') + .send({ N: 33, P: 36, K: 62 }); + + expect(response.status).toBe(502); + expect(response.body.error).toBe('AI model service unavailable'); + expect(Array.isArray(response.body.details)).toBe(true); + expect(response.body.details.length).toBeGreaterThan(0); + }); +}); + +describe('AI analysis endpoint', () => { + it('returns 400 when model_type or prediction is missing', async () => { + const app = await buildAppWithRoute(); + + const res1 = await request(app) + .post('/api/ml/analyze-prediction') + .send({ prediction: 'Rice' }); + expect(res1.status).toBe(400); + expect(res1.body.error).toMatch(/model_type/); + + const res2 = await request(app) + .post('/api/ml/analyze-prediction') + .send({ model_type: 'crop_recommendation' }); + expect(res2.status).toBe(400); + expect(res2.body.error).toMatch(/prediction/); + }); + + it('returns explicit error without fallback analysis when GROQ_API_KEY is missing', async () => { + const origKey = process.env.GROQ_API_KEY; + delete process.env.GROQ_API_KEY; + + const app = await buildAppWithRoute(); + const res = await request(app) + .post('/api/ml/analyze-prediction') + .send({ + model_type: 'crop_recommendation', + prediction: 'Rice', + input_data: { nitrogen: 50, phosphorus: 30, potassium: 40 }, + }); + + // Without the API key the handler should return 500 without synthetic fallback output + expect(res.status).toBe(500); + expect(res.body.success).toBe(false); + expect(res.body.error).toBe('Failed to generate analysis'); + expect(res.body.analysis).toBeUndefined(); + + process.env.GROQ_API_KEY = origKey; + }); +}); + +describe('New ML model proxy routes', () => { + const originalEnv = { ...process.env }; + const originalFetch = global.fetch; + + afterEach(() => { + process.env = { ...originalEnv }; + global.fetch = originalFetch; + jest.resetModules(); + }); + + it('walnut-rancidity forwards JSON to AI backend', async () => { + process.env.AI_BACKEND_URL = ''; + process.env.SPACE_HOST = 'arko007-agromind-backend.hf.space'; + + global.fetch = jest.fn(async (url) => { + if (String(url).includes('/walnut_rancidity_predict')) { + return { + ok: true, + status: 200, + text: async () => JSON.stringify({ + model: 'walnut-rancidity-predictor', + prediction: { rancidity_probability: 0.15, shelf_life_remaining_days: 120 }, + risk_level: 'LOW', + }), + }; + } + throw new Error('connect ECONNREFUSED'); + }); + + const app = await buildAppWithRoute(); + const response = await request(app) + .post('/api/ml/walnut-rancidity') + .send({ storage_days: 10, temperature: 5, humidity: 50, moisture: 4 }); + + expect(response.status).toBe(200); + expect(response.body.result.risk_level).toBe('LOW'); + }); + + it('apple-price forwards JSON to AI backend', async () => { + process.env.AI_BACKEND_URL = ''; + process.env.SPACE_HOST = 'arko007-agromind-backend.hf.space'; + + global.fetch = jest.fn(async (url) => { + if (String(url).includes('/apple_price_predict')) { + return { + ok: true, + status: 200, + text: async () => JSON.stringify({ + model: 'apple-price-predictor', + predicted_price_7d: 127.5, + recommendation: 'STORE', + }), + }; + } + throw new Error('connect ECONNREFUSED'); + }); + + const app = await buildAppWithRoute(); + const response = await request(app) + .post('/api/ml/apple-price') + .send({ current_price: 120, apple_variety: 'Kinnauri', region: 'Himachal Pradesh' }); + + expect(response.status).toBe(200); + expect(response.body.result.recommendation).toBe('STORE'); + }); + + it('saffron returns 400 when no file is provided', async () => { + const app = await buildAppWithRoute(); + const response = await request(app) + .post('/api/ml/saffron') + .send({}); + + expect(response.status).toBe(400); + expect(response.body.error).toMatch(/image/i); + }); + + it('walnut-defect returns 400 when no file is provided', async () => { + const app = await buildAppWithRoute(); + const response = await request(app) + .post('/api/ml/walnut-defect') + .send({}); + + expect(response.status).toBe(400); + expect(response.body.error).toMatch(/image/i); + }); +}); diff --git a/backend/tests/aiOrchestrator.test.js b/backend/tests/aiOrchestrator.test.js new file mode 100644 index 0000000000000000000000000000000000000000..f9b2d6d0639942c29f05ef64f4670eebaac3057b --- /dev/null +++ b/backend/tests/aiOrchestrator.test.js @@ -0,0 +1,142 @@ +/** + * AI Orchestrator Tests + * + * Tests for the unified AI orchestration pipeline + */ + +import { + orchestrate, + extractLanguage, + getLanguageName, + LANGUAGE_MAP, +} from '../utils/aiOrchestrator.js'; + +describe('AI Orchestrator', () => { + const originalEnv = process.env; + + beforeEach(() => { + process.env = { ...originalEnv }; + }); + + afterEach(() => { + process.env = originalEnv; + }); + + describe('LANGUAGE_MAP', () => { + it('should contain all 22 official Indian languages', () => { + expect(Object.keys(LANGUAGE_MAP)).toHaveLength(22); + }); + + it('should include English', () => { + expect(LANGUAGE_MAP.en).toBe('English'); + }); + + it('should include Hindi', () => { + expect(LANGUAGE_MAP.hi).toBe('Hindi'); + }); + + it('should include all scheduled languages', () => { + const expectedCodes = [ + 'en', 'hi', 'bn', 'mr', 'ta', 'te', 'pa', 'gu', + 'kn', 'ml', 'or', 'as', 'ur', 'sa', 'kok', 'mni', + 'brx', 'sat', 'mai', 'doi', 'ne', 'ks', + ]; + for (const code of expectedCodes) { + expect(LANGUAGE_MAP[code]).toBeDefined(); + } + }); + }); + + describe('getLanguageName', () => { + it('should return language name for valid code', () => { + expect(getLanguageName('hi')).toBe('Hindi'); + expect(getLanguageName('ta')).toBe('Tamil'); + expect(getLanguageName('bn')).toBe('Bengali'); + }); + + it('should return English for unknown code', () => { + expect(getLanguageName('xx')).toBe('English'); + }); + }); + + describe('extractLanguage', () => { + it('should extract from query param', () => { + const req = { query: { lang: 'hi' }, body: {}, headers: {} }; + expect(extractLanguage(req)).toBe('hi'); + }); + + it('should extract from body.language', () => { + const req = { query: {}, body: { language: 'ta' }, headers: {} }; + expect(extractLanguage(req)).toBe('ta'); + }); + + it('should extract from body.lang', () => { + const req = { query: {}, body: { lang: 'bn' }, headers: {} }; + expect(extractLanguage(req)).toBe('bn'); + }); + + it('should extract from Accept-Language header', () => { + const req = { query: {}, body: {}, headers: { 'accept-language': 'te-IN,te;q=0.9,en;q=0.8' } }; + expect(extractLanguage(req)).toBe('te'); + }); + + it('should default to en if nothing provided', () => { + const req = { query: {}, body: {}, headers: {} }; + expect(extractLanguage(req)).toBe('en'); + }); + + it('should default to en for unsupported language', () => { + const req = { query: { lang: 'xx' }, body: {}, headers: {} }; + expect(extractLanguage(req)).toBe('en'); + }); + + it('should prioritize query over body', () => { + const req = { query: { lang: 'hi' }, body: { lang: 'ta' }, headers: {} }; + expect(extractLanguage(req)).toBe('hi'); + }); + }); + + describe('orchestrate', () => { + it('should return fallback when GROQ_API_KEY is not set', async () => { + delete process.env.GROQ_API_KEY; + + const result = await orchestrate({ + structuredData: { temperature: 32, humidity: 75, crop: 'wheat' }, + domainContext: 'Weather Advisory', + languageCode: 'en', + }); + + expect(result).toHaveProperty('summary'); + expect(result).toHaveProperty('structuredData'); + expect(result).toHaveProperty('language', 'English'); + expect(result).toHaveProperty('languageCode', 'en'); + expect(result).toHaveProperty('verified', true); + expect(result.structuredData.temperature).toBe(32); + }); + + it('should include structured data in response', async () => { + delete process.env.GROQ_API_KEY; + + const data = { yield: 4.5, unit: 'tonnes/hectare' }; + const result = await orchestrate({ + structuredData: data, + domainContext: 'Yield Estimate', + }); + + expect(result.structuredData).toEqual(data); + }); + + it('should respect language code', async () => { + delete process.env.GROQ_API_KEY; + + const result = await orchestrate({ + structuredData: { value: 100 }, + domainContext: 'Test', + languageCode: 'hi', + }); + + expect(result.language).toBe('Hindi'); + expect(result.languageCode).toBe('hi'); + }); + }); +}); diff --git a/backend/tests/assistantRoute.test.js b/backend/tests/assistantRoute.test.js new file mode 100644 index 0000000000000000000000000000000000000000..f430ee124117c6d321da722469276d6880c453d2 --- /dev/null +++ b/backend/tests/assistantRoute.test.js @@ -0,0 +1,30 @@ +import { + ASSISTANT_MAX_TOKENS, + buildSystemPrompt, + resolveAssistantLanguage, +} from "../routes/assistantRoute.js"; + +describe("assistant route localization helpers", () => { + it("prefers selected_language when it is supported", () => { + expect(resolveAssistantLanguage({ lang: "en", selected_language: "ta" })).toBe("ta"); + }); + + it("falls back to lang when selected_language is missing or unsupported", () => { + expect(resolveAssistantLanguage({ lang: "hi" })).toBe("hi"); + expect(resolveAssistantLanguage({ lang: "bn", selected_language: "xx" })).toBe("bn"); + }); + + it("defaults to English for unsupported payloads", () => { + expect(resolveAssistantLanguage({ lang: "xx", selected_language: "yy" })).toBe("en"); + }); + + it("builds a prompt that forces the selected language", () => { + const prompt = buildSystemPrompt("ml"); + expect(prompt).toContain("user's selected language: Malayalam"); + expect(prompt).toContain("reply in Malayalam"); + }); + + it("uses the expanded multilingual token limit", () => { + expect(ASSISTANT_MAX_TOKENS).toBe(4096); + }); +}); diff --git a/backend/tests/auth.test.js b/backend/tests/auth.test.js new file mode 100644 index 0000000000000000000000000000000000000000..a1dc70fcb79a11fc14c65f949f5ddfa58b2cb26f --- /dev/null +++ b/backend/tests/auth.test.js @@ -0,0 +1,23 @@ +import express from "express"; +import request from "supertest"; +import authRoute from "../routes/authRoute.js"; + +describe("Firebase-only authentication contract", () => { + const app = express(); + app.use(express.json()); + app.use("/api/auth", authRoute); + + it("rejects obsolete server-side password signup", async () => { + const response = await request(app) + .post("/api/auth/signup") + .send({ email: "user@example.com", password: "secret" }); + expect(response.status).toBe(410); + }); + + it("rejects obsolete server-side password sign-in", async () => { + const response = await request(app) + .post("/api/auth/signin") + .send({ email: "user@example.com", password: "secret" }); + expect(response.status).toBe(410); + }); +}); diff --git a/backend/tests/community.test.js b/backend/tests/community.test.js new file mode 100644 index 0000000000000000000000000000000000000000..541ad2d831474d33abbdecdfde5519bc45153fdb --- /dev/null +++ b/backend/tests/community.test.js @@ -0,0 +1,81 @@ +/** + * Community Q&A Routes Tests + */ +describe('Community Questions', () => { + it('should validate required fields for question', () => { + const valid = { title: 'Help with pest', body: 'My tomatoes have spots' }; + expect(valid.title).toBeDefined(); + expect(valid.body).toBeDefined(); + }); + + it('should reject questions without title', () => { + const invalid = { body: 'Some text' }; + expect(invalid.title).toBeUndefined(); + }); + + it('should flag unsafe content', () => { + const unsafeKeywords = ['pesticide mix', 'illegal', 'banned chemical', 'poison']; + const safeBody = 'My tomatoes are showing brown spots'; + const unsafeBody = 'Should I use banned chemical on crops?'; + + const safeResult = unsafeKeywords.some(kw => safeBody.toLowerCase().includes(kw)); + const unsafeResult = unsafeKeywords.some(kw => unsafeBody.toLowerCase().includes(kw)); + + expect(safeResult).toBe(false); + expect(unsafeResult).toBe(true); + }); +}); + +describe('Community Answers', () => { + it('should support voting', () => { + let votes = 0; + votes += 1; // upvote + expect(votes).toBe(1); + votes -= 1; // downvote + expect(votes).toBe(0); + }); + + it('should validate answer body is required', () => { + const invalid = {}; + expect(invalid.body).toBeUndefined(); + }); + + it('should flag unsafe advice', () => { + const unsafeKeywords = ['mix pesticides', 'banned', 'toxic', 'illegal spray']; + const advice = 'Try neem oil spray for aphids'; + const hasUnsafe = unsafeKeywords.some(kw => advice.toLowerCase().includes(kw)); + expect(hasUnsafe).toBe(false); + }); + + it('should identify best remedy by votes', () => { + const answers = [ + { id: 1, votes: 5, flagged: false }, + { id: 2, votes: 10, flagged: false }, + { id: 3, votes: 15, flagged: true }, + ]; + + const sorted = answers.sort((a, b) => b.votes - a.votes); + const best = sorted.find(a => !a.flagged); + expect(best.id).toBe(2); + }); +}); + +describe('Community Moderation', () => { + it('should support flagging answers', () => { + const answer = { id: 1, flagged: false }; + answer.flagged = true; + answer.flagReason = 'Harmful advice'; + expect(answer.flagged).toBe(true); + expect(answer.flagReason).toBe('Harmful advice'); + }); + + it('should filter by crop', () => { + const questions = [ + { crop: 'rice', title: 'Q1' }, + { crop: 'wheat', title: 'Q2' }, + { crop: 'rice', title: 'Q3' }, + ]; + const filtered = questions.filter(q => q.crop === 'rice'); + expect(filtered).toHaveLength(2); + }); +}); diff --git a/backend/tests/firebaseRest.test.js b/backend/tests/firebaseRest.test.js new file mode 100644 index 0000000000000000000000000000000000000000..8af956cb93d651bf684e2178f3bf3945d5fb70ff --- /dev/null +++ b/backend/tests/firebaseRest.test.js @@ -0,0 +1,117 @@ +import { jest } from "@jest/globals"; +import { + getFirestoreDocument, + getFirebaseIdToken, + lookupFirebaseIdToken, + setFirestoreDocument, + toFirestoreValue, + withFirebaseToken, +} from "../utils/firebaseRest.js"; + +describe("Firebase REST utilities", () => { + const originalFetch = global.fetch; + const originalProjectId = process.env.FIREBASE_PROJECT_ID; + const originalApiKey = process.env.FIREBASE_API_KEY; + + beforeEach(() => { + process.env.FIREBASE_PROJECT_ID = "agromind-a62c1"; + process.env.FIREBASE_API_KEY = "test-web-api-key"; + global.fetch = jest.fn(); + }); + + afterEach(() => { + global.fetch = originalFetch; + if (originalProjectId === undefined) delete process.env.FIREBASE_PROJECT_ID; + else process.env.FIREBASE_PROJECT_ID = originalProjectId; + if (originalApiKey === undefined) delete process.env.FIREBASE_API_KEY; + else process.env.FIREBASE_API_KEY = originalApiKey; + }); + + test("looks up a Firebase ID token through Identity Toolkit", async () => { + global.fetch.mockResolvedValue({ + ok: true, + status: 200, + json: async () => ({ + users: [{ + localId: "uid-123", + email: "farmer@example.com", + displayName: "Farmer", + photoUrl: "https://example.com/avatar.png", + emailVerified: true, + }], + }), + }); + + await expect(lookupFirebaseIdToken("firebase-id-token")).resolves.toMatchObject({ + uid: "uid-123", + email: "farmer@example.com", + name: "Farmer", + emailVerified: true, + }); + expect(global.fetch).toHaveBeenCalledWith( + expect.stringContaining("identitytoolkit.googleapis.com/v1/accounts:lookup?key=test-web-api-key"), + expect.objectContaining({ method: "POST", body: JSON.stringify({ idToken: "firebase-id-token" }) }), + ); + }); + + test("carries the verified user token through asynchronous work", async () => { + await withFirebaseToken("verified-token", async () => { + await Promise.resolve(); + expect(getFirebaseIdToken()).toBe("verified-token"); + }); + }); + + test("writes and decodes Firestore REST documents with the user token", async () => { + global.fetch.mockResolvedValue({ + ok: true, + status: 200, + json: async () => ({ + name: "projects/agromind-a62c1/databases/(default)/documents/users/uid-123", + fields: { + firebaseUid: { stringValue: "uid-123" }, + createdAt: { timestampValue: "2026-08-17T00:00:00.000Z" }, + devices: { arrayValue: { values: [{ mapValue: { fields: { label: { stringValue: "Browser" } } } }] } }, + }, + }), + }); + + await withFirebaseToken("verified-token", async () => { + const document = await setFirestoreDocument("users", "uid-123", { + firebaseUid: "uid-123", + createdAt: new Date("2026-08-17T00:00:00.000Z"), + devices: [{ label: "Browser" }], + }); + expect(document.data.firebaseUid).toBe("uid-123"); + expect(document.data.createdAt).toEqual(new Date("2026-08-17T00:00:00.000Z")); + expect(global.fetch).toHaveBeenCalledWith( + expect.stringContaining("firestore.googleapis.com/v1/projects/agromind-a62c1/databases/(default)/documents/users/uid-123"), + expect.objectContaining({ + method: "PATCH", + headers: expect.objectContaining({ Authorization: "Bearer verified-token" }), + }), + ); + }); + }); + + test("returns null for a missing Firestore document", async () => { + global.fetch.mockResolvedValue({ + ok: false, + status: 404, + statusText: "Not Found", + json: async () => ({ error: { message: "NOT_FOUND" } }), + }); + await expect(getFirestoreDocument("users", "missing")).resolves.toBeNull(); + }); + + test("encodes nested values for Firestore", () => { + expect(toFirestoreValue({ count: 2, active: true, tags: ["a", "b"] })).toEqual({ + mapValue: { + fields: { + count: { integerValue: "2" }, + active: { booleanValue: true }, + tags: { arrayValue: { values: [{ stringValue: "a" }, { stringValue: "b" }] } }, + }, + }, + }); + }); +}); diff --git a/backend/tests/health.test.js b/backend/tests/health.test.js new file mode 100644 index 0000000000000000000000000000000000000000..7f29a33a7170e360f76956848f081f0c21931c54 --- /dev/null +++ b/backend/tests/health.test.js @@ -0,0 +1,57 @@ +/** + * Health Endpoint Tests + * + * Run with: npm test + */ + +describe('Health Endpoint', () => { + it('should return ok status', () => { + const healthResponse = { + status: 'ok', + version: '1.0.0', + uptime: 120, + database: 'connected', + timestamp: new Date().toISOString(), + }; + + expect(healthResponse.status).toBe('ok'); + expect(healthResponse.version).toBeDefined(); + expect(typeof healthResponse.uptime).toBe('number'); + expect(healthResponse.uptime).toBeGreaterThanOrEqual(0); + }); + + it('should include version string', () => { + const version = process.env.npm_package_version || '1.0.0'; + expect(version).toMatch(/^\d+\.\d+\.\d+/); + }); + + it('should report database status', () => { + const validStatuses = ['connected', 'disconnected']; + const dbStatus = 'disconnected'; // no DB in test + expect(validStatuses).toContain(dbStatus); + }); + + it('should include ISO timestamp', () => { + const timestamp = new Date().toISOString(); + expect(timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/); + }); +}); + +describe('Firebase Auth Verify Token', () => { + it('should require Authorization header', () => { + const headers = {}; + const hasAuth = headers.authorization && headers.authorization.startsWith('Bearer '); + expect(hasAuth).toBeFalsy(); + }); + + it('should parse Bearer token correctly', () => { + const authHeader = 'Bearer test-token-123'; + const token = authHeader.startsWith('Bearer ') ? authHeader.substring(7) : null; + expect(token).toBe('test-token-123'); + }); + + it('should reject missing tokens', () => { + const token = null; + expect(token).toBeNull(); + }); +}); diff --git a/backend/tests/jwtMiddleware.test.js b/backend/tests/jwtMiddleware.test.js new file mode 100644 index 0000000000000000000000000000000000000000..f4c89ca2920d3f02febc8ec8e379c7979ba18dac --- /dev/null +++ b/backend/tests/jwtMiddleware.test.js @@ -0,0 +1,23 @@ +import { jest } from "@jest/globals"; +import { verifyToken } from "../middleware/jwt.js"; + +const createRes = () => { + const res = {}; + res.status = (code) => { res.statusCode = code; return res; }; + res.json = (payload) => { res.payload = payload; return res; }; + return res; +}; + +describe("Firebase auth compatibility middleware", () => { + test("returns 401 when Firebase token is missing", async () => { + const req = { cookies: {}, headers: {} }; + const res = createRes(); + const next = jest.fn(); + + await verifyToken(req, res, next); + + expect(res.statusCode).toBe(401); + expect(res.payload).toEqual({ success: false, message: "Access denied. No Firebase token provided." }); + expect(next).not.toHaveBeenCalled(); + }); +}); diff --git a/backend/tests/languagePreference.test.js b/backend/tests/languagePreference.test.js new file mode 100644 index 0000000000000000000000000000000000000000..b449d1c0358e991876d54b231df1ab26c155f60a --- /dev/null +++ b/backend/tests/languagePreference.test.js @@ -0,0 +1,16 @@ +import express from "express"; +import request from "supertest"; +import farmerDetailsRoutes from "../routes/farmerDetailsRoute.js"; + +describe("Language preference route", () => { + const app = express(); + app.use(express.json()); + app.use("/api/farmer-details", farmerDetailsRoutes); + + it("rejects an unauthenticated preference update", async () => { + const response = await request(app) + .post("/api/farmer-details/user/preferences/language") + .send({ language: "hi" }); + expect(response.status).toBe(401); + }); +}); diff --git a/backend/tests/mandi.test.js b/backend/tests/mandi.test.js new file mode 100644 index 0000000000000000000000000000000000000000..2320d191814f4f11bcfa4cff2fb780765ebbde12 --- /dev/null +++ b/backend/tests/mandi.test.js @@ -0,0 +1,45 @@ +/** + * Mandi Prices Routes Tests + */ +describe('Mandi Prices', () => { + it('should generate price data for commodity', () => { + const basePrice = 2200; // wheat + const days = 30; + const prices = Array.from({ length: days }, () => { + const variation = (Math.random() - 0.5) * basePrice * 0.08; + return Math.round(basePrice + variation); + }); + + expect(prices).toHaveLength(30); + prices.forEach(p => { + expect(p).toBeGreaterThan(0); + }); + }); + + it('should calculate statistics correctly', () => { + const prices = [2200, 2300, 2100, 2250, 2180]; + const avg = Math.round(prices.reduce((a, b) => a + b, 0) / prices.length); + const min = Math.min(...prices); + const max = Math.max(...prices); + const trend = prices[prices.length - 1] > prices[0] ? 'rising' : 'falling'; + + expect(avg).toBe(2206); + expect(min).toBe(2100); + expect(max).toBe(2300); + expect(trend).toBe('falling'); + }); + + it('should have valid commodity list', () => { + const commodities = ['wheat', 'rice', 'groundnut', 'soybean', 'mustard', 'cotton']; + expect(commodities.length).toBeGreaterThan(5); + commodities.forEach(c => { + expect(typeof c).toBe('string'); + expect(c.length).toBeGreaterThan(0); + }); + }); + + it('should limit days to max 90', () => { + const days = Math.min(parseInt('100'), 90); + expect(days).toBe(90); + }); +}); diff --git a/backend/tests/mlRoutes.test.js b/backend/tests/mlRoutes.test.js new file mode 100644 index 0000000000000000000000000000000000000000..d0dbe3935d6e2eb0826e83a99dcd15d9b4d7f843 --- /dev/null +++ b/backend/tests/mlRoutes.test.js @@ -0,0 +1,142 @@ +import { jest } from "@jest/globals"; +import express from "express"; +import request from "supertest"; + +const buildAppWithRoute = async () => { + const { default: router } = await import(`../routes/mlRoutes.js?test=${Date.now()}`); + const app = express(); + app.use(express.json()); + app.use("/api/ml", router); + return app; +}; + +describe("ML route integrations", () => { + const originalEnv = { ...process.env }; + const originalFetch = global.fetch; + + afterEach(() => { + process.env = { ...originalEnv }; + global.fetch = originalFetch; + jest.resetModules(); + }); + + it("normalizes saffron HF image-classification responses", async () => { + global.fetch = jest.fn(async (url) => { + if (String(url).includes("api-inference.huggingface.co/models/Arko007/saffron-verify-pretrained")) { + return { + ok: true, + status: 200, + headers: { get: () => "application/json" }, + text: async () => + JSON.stringify([ + { label: "mogra", score: 0.91 }, + { label: "lacha", score: 0.07 }, + ]), + }; + } + + throw new Error(`Unexpected url: ${url}`); + }); + + const app = await buildAppWithRoute(); + const response = await request(app) + .post("/api/ml/saffron") + .attach("image", Buffer.from("fake-image"), "sample.jpg"); + + expect(response.status).toBe(200); + expect(response.body.success).toBe(true); + expect(response.body.model).toBe("Arko007/saffron-verify-pretrained"); + expect(response.body.provider).toBe("huggingface"); + expect(response.body.prediction.label).toBe("mogra"); + expect(response.body.predictions).toHaveLength(2); + }); + + it("requires an image upload for walnut defect inference", async () => { + const app = await buildAppWithRoute(); + const response = await request(app).post("/api/ml/walnut-defect").send({}); + + expect(response.status).toBe(400); + expect(response.body.success).toBe(false); + expect(response.body.error).toMatch(/image/i); + }); + + it("forwards walnut rancidity requests to the AI backend fallback and normalizes the result", async () => { + // Unlike walnut-defect/saffron, the walnut-rancidity route has no + // HuggingFace-first attempt -- it calls forwardJsonToAiBackend directly, + // so the AI-backend candidate URL must be configured for the route to + // have anywhere to send the request. + process.env.AI_BACKEND_URL = ""; + process.env.SPACE_HOST = "arko007-agromind-backend.hf.space"; + + global.fetch = jest.fn(async (url) => { + if (String(url).includes("/walnut_rancidity_predict")) { + return { + ok: true, + status: 200, + headers: { get: () => "application/json" }, + text: async () => + JSON.stringify({ + rancidity_probability: 0.22, + shelf_life_remaining_days: 142, + decay_curve_value: 0.18, + risk_level: "LOW", + }), + }; + } + + throw new Error(`Unexpected url: ${url}`); + }); + + const app = await buildAppWithRoute(); + const response = await request(app).post("/api/ml/walnut-rancidity").send({ + storage_days: 18, + temperature: 7, + humidity: 58, + moisture: 4.3, + oxygen: 0.2, + }); + + expect(response.status).toBe(200); + expect(response.body.success).toBe(true); + expect(response.body.result.risk_level).toBe("LOW"); + expect(response.body.result.shelf_life_remaining_days).toBe(142); + }); + + it("normalizes apple price predictor responses", async () => { + global.fetch = jest.fn(async (url) => { + if (String(url).includes("api-inference.huggingface.co/models/Arko007/apple-price-predictor")) { + return { + ok: true, + status: 200, + headers: { get: () => "application/json" }, + text: async () => + JSON.stringify({ + predicted_price_7d: 127.5, + recommendation: "STORE", + current_price: 120, + storage_cost_7d: 5.25, + breakeven_price: 125.25, + currency: "INR", + confidence: "hybrid Prophet+ARIMA (0.6/0.4)", + }), + }; + } + + throw new Error(`Unexpected url: ${url}`); + }); + + const app = await buildAppWithRoute(); + const response = await request(app).post("/api/ml/apple-price").send({ + current_price: 120, + storage_time_days: 10, + apple_variety: "Kinnauri", + region: "Himachal Pradesh", + date: "2026-03-07", + }); + + expect(response.status).toBe(200); + expect(response.body.success).toBe(true); + expect(response.body.result.recommendation).toBe("STORE"); + expect(response.body.result.predicted_price_7d).toBe(127.5); + }); +}); diff --git a/backend/tests/mrv.test.js b/backend/tests/mrv.test.js new file mode 100644 index 0000000000000000000000000000000000000000..eee9d34ca436457c3dbaa7f9511bfd135c4f9ed4 --- /dev/null +++ b/backend/tests/mrv.test.js @@ -0,0 +1,90 @@ +/** + * MRV Routes Tests + * + * Run with: npm test + */ + +describe('MRV Report', () => { + it('should validate required fields for report submission', () => { + const validReport = { + module: 'crop_shift', + metrics: { carbon_saved_kg: 150, water_saved_liters: 2000 }, + farmerId: 'farmer123', + reportingPeriod: '2026-01', + }; + + expect(validReport.module).toBeDefined(); + expect(validReport.metrics).toBeDefined(); + expect(typeof validReport.module).toBe('string'); + expect(typeof validReport.metrics).toBe('object'); + }); + + it('should reject reports without module', () => { + const invalidReport = { + metrics: { carbon_saved_kg: 100 }, + }; + + expect(invalidReport.module).toBeUndefined(); + }); + + it('should reject reports without metrics', () => { + const invalidReport = { + module: 'crop_shift', + }; + + expect(invalidReport.metrics).toBeUndefined(); + }); + + it('should generate a unique report ID', () => { + const id1 = `MRV-${Date.now()}`; + const id2 = `MRV-${Date.now() + 1}`; + + expect(id1).not.toBe(id2); + expect(id1).toMatch(/^MRV-\d+$/); + }); + + it('should set default status to submitted', () => { + const report = { + status: 'submitted', + submittedAt: new Date().toISOString(), + verifiedAt: null, + verifier: null, + }; + + expect(report.status).toBe('submitted'); + expect(report.verifiedAt).toBeNull(); + }); +}); + +describe('MRV Verification', () => { + it('should validate decision values', () => { + const validDecisions = ['approved', 'rejected']; + + validDecisions.forEach(decision => { + expect(['approved', 'rejected']).toContain(decision); + }); + }); + + it('should reject invalid decisions', () => { + const invalidDecision = 'pending'; + expect(['approved', 'rejected']).not.toContain(invalidDecision); + }); + + it('should set verification timestamp', () => { + const verification = { + reportId: 'MRV-123', + verifierId: 'verifier1', + decision: 'approved', + verifiedAt: new Date().toISOString(), + }; + + expect(verification.verifiedAt).toBeDefined(); + expect(new Date(verification.verifiedAt)).toBeInstanceOf(Date); + }); + + it('should map decision to correct status', () => { + const mapDecision = (d) => d === 'approved' ? 'verified' : 'rejected'; + expect(mapDecision('approved')).toBe('verified'); + expect(mapDecision('rejected')).toBe('rejected'); + }); +}); diff --git a/backend/tests/mrvEstimate.test.js b/backend/tests/mrvEstimate.test.js new file mode 100644 index 0000000000000000000000000000000000000000..64db71ea0f63560b58d9236e3074f6a18d7c4223 --- /dev/null +++ b/backend/tests/mrvEstimate.test.js @@ -0,0 +1,36 @@ +import express from "express"; +import request from "supertest"; + +const buildAppWithRoute = async () => { + const { default: router } = await import(`../routes/mrvRoutes.js?test=${Date.now()}`); + const app = express(); + app.use(express.json()); + app.use("/api/mrv", router); + return app; +}; + +describe("MRV estimate endpoint", () => { + it("returns an estimate for valid activity inputs", async () => { + const app = await buildAppWithRoute(); + + const response = await request(app) + .post("/api/mrv/estimate") + .send({ farm_area_ha: 2, activities: ["zero_till"] }); + + expect(response.status).toBe(200); + expect(response.body.total_co2e_tonnes).toBeDefined(); + expect(response.body.credit_value_inr).toBeDefined(); + expect(Array.isArray(response.body.activities)).toBe(true); + }); + + it("returns 400 when no activities are selected", async () => { + const app = await buildAppWithRoute(); + + const response = await request(app) + .post("/api/mrv/estimate") + .send({ farm_area_ha: 2, activities: [] }); + + expect(response.status).toBe(400); + expect(response.body.error).toMatch(/activity/i); + }); +}); diff --git a/backend/tests/ndvi.test.js b/backend/tests/ndvi.test.js new file mode 100644 index 0000000000000000000000000000000000000000..37c4c5475bad9d3dc1822f5a2ca0ed8ec0538e97 --- /dev/null +++ b/backend/tests/ndvi.test.js @@ -0,0 +1,55 @@ +/** + * NDVI Routes Tests + */ +describe('NDVI Farm Data', () => { + it('should validate lat/lng parameters', () => { + const validParams = { lat: '18.52', lng: '73.85' }; + expect(parseFloat(validParams.lat)).toBeGreaterThanOrEqual(-90); + expect(parseFloat(validParams.lat)).toBeLessThanOrEqual(90); + expect(parseFloat(validParams.lng)).toBeGreaterThanOrEqual(-180); + expect(parseFloat(validParams.lng)).toBeLessThanOrEqual(180); + }); + + it('should generate seasonal NDVI values', () => { + const month = 7; // August (monsoon) + const seasonalBase = month >= 5 && month <= 8 ? 0.65 : 0.35; + expect(seasonalBase).toBe(0.65); + }); + + it('should require coordinates', () => { + const params = {}; + const hasCoords = params.lat && params.lng; + expect(hasCoords).toBeFalsy(); + }); +}); + +describe('NDVI Rainfall Forecast', () => { + it('should generate forecast for specified days', () => { + const days = 7; + const forecast = Array.from({ length: days }, (_, i) => ({ + date: new Date(Date.now() + i * 86400000).toISOString().split('T')[0], + rainfall_mm: Math.random() * 50, + })); + expect(forecast).toHaveLength(7); + forecast.forEach(f => { + expect(f.date).toMatch(/^\d{4}-\d{2}-\d{2}$/); + expect(f.rainfall_mm).toBeGreaterThanOrEqual(0); + }); + }); +}); + +describe('Crop Suitability', () => { + it('should score crops based on NDVI and rainfall', () => { + const crop = { name: 'Rice', min_ndvi: 0.4, min_rainfall: 1200 }; + const currentNdvi = 0.5; + const annualRainfall = 1000; + + const ndviScore = Math.min(1, currentNdvi / crop.min_ndvi); + const rainScore = Math.min(1, annualRainfall / crop.min_rainfall); + const score = (ndviScore * 0.5 + rainScore * 0.5) * 100; + + expect(score).toBeGreaterThan(0); + expect(score).toBeLessThanOrEqual(100); + expect(ndviScore).toBeGreaterThan(0); + }); +}); diff --git a/backend/tests/setup.js b/backend/tests/setup.js new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/backend/tests/validateToken.test.js b/backend/tests/validateToken.test.js new file mode 100644 index 0000000000000000000000000000000000000000..152c93916c4cd1e191928d05de36e9b727d28e8f --- /dev/null +++ b/backend/tests/validateToken.test.js @@ -0,0 +1,16 @@ +import express from "express"; +import cookieParser from "cookie-parser"; +import request from "supertest"; +import validateTokenRoutes from "../routes/validateTokenRoutes.js"; + +describe("Firebase token validation route", () => { + const app = express(); + app.use(cookieParser()); + app.use("/api/auth", validateTokenRoutes); + + test("rejects requests without a Firebase token", async () => { + const response = await request(app).get("/api/auth/validate-token"); + expect(response.status).toBe(401); + expect(response.body).toEqual({ success: false, message: "Access denied. No Firebase token provided." }); + }); +}); diff --git a/backend/tests/valuechain.test.js b/backend/tests/valuechain.test.js new file mode 100644 index 0000000000000000000000000000000000000000..8472962508079cf51da395329cff46f568c685d4 --- /dev/null +++ b/backend/tests/valuechain.test.js @@ -0,0 +1,153 @@ +/** + * Value Chain API Tests + * + * Run with: npm test + */ + +describe('Value Chain Controller', () => { + describe('createListing', () => { + it('should validate required fields', () => { + const requiredFields = ['productType', 'quantityKg', 'harvestDate', 'location', 'reservePrice']; + + requiredFields.forEach(field => { + expect(field).toBeDefined(); + }); + }); + + it('should validate location has coordinates', () => { + const validLocation = { + coordinates: [73.85, 18.52], + address: 'Test Address', + state: 'Maharashtra', + }; + + expect(validLocation.coordinates).toHaveLength(2); + expect(validLocation.coordinates[0]).toBeGreaterThanOrEqual(-180); + expect(validLocation.coordinates[0]).toBeLessThanOrEqual(180); + expect(validLocation.coordinates[1]).toBeGreaterThanOrEqual(-90); + expect(validLocation.coordinates[1]).toBeLessThanOrEqual(90); + }); + + it('should validate product types', () => { + const validProductTypes = [ + 'oilseed_meal', + 'oilseed_cake', + 'oilseed_husk', + 'groundnut', + 'sunflower', + 'soybean', + 'mustard', + ]; + + validProductTypes.forEach(type => { + expect(typeof type).toBe('string'); + expect(type.length).toBeGreaterThan(0); + }); + }); + }); + + describe('getListings', () => { + it('should support pagination parameters', () => { + const params = { + page: 1, + limit: 20, + sort: '-createdAt', + }; + + expect(params.page).toBeGreaterThan(0); + expect(params.limit).toBeGreaterThan(0); + expect(params.limit).toBeLessThanOrEqual(100); + }); + + it('should support geospatial filtering', () => { + const geoParams = { + lat: 18.52, + lng: 73.85, + radius: 50, + }; + + expect(geoParams.lat).toBeGreaterThanOrEqual(-90); + expect(geoParams.lat).toBeLessThanOrEqual(90); + expect(geoParams.lng).toBeGreaterThanOrEqual(-180); + expect(geoParams.lng).toBeLessThanOrEqual(180); + expect(geoParams.radius).toBeGreaterThan(0); + }); + }); + + describe('createOffer', () => { + it('should validate offer fields', () => { + const offer = { + listingId: 'listing123', + offeredPrice: 55, + quantityKg: 1000, + expiresInHours: 48, + }; + + expect(offer.offeredPrice).toBeGreaterThan(0); + expect(offer.quantityKg).toBeGreaterThan(0); + expect(offer.expiresInHours).toBeGreaterThan(0); + }); + + it('should calculate total amount correctly', () => { + const pricePerKg = 55; + const quantityKg = 1000; + const expectedTotal = pricePerKg * quantityKg; + + expect(expectedTotal).toBe(55000); + }); + }); + + describe('respondToOffer', () => { + it('should support valid actions', () => { + const validActions = ['accept', 'reject', 'counter']; + + validActions.forEach(action => { + expect(['accept', 'reject', 'counter']).toContain(action); + }); + }); + + it('should require counter price for counter offers', () => { + const counterOffer = { + action: 'counter', + counterPrice: 52, + counterMessage: 'Best I can do', + }; + + if (counterOffer.action === 'counter') { + expect(counterOffer.counterPrice).toBeDefined(); + expect(counterOffer.counterPrice).toBeGreaterThan(0); + } + }); + }); +}); + +describe('Market Summary', () => { + it('should calculate supply-demand correctly', () => { + const supplyData = [ + { productType: 'groundnut', totalQuantity: 10000 }, + { productType: 'soybean', totalQuantity: 15000 }, + ]; + + const demandData = [ + { productType: 'groundnut', totalDemand: 8000 }, + { productType: 'soybean', totalDemand: 12000 }, + ]; + + const totalSupply = supplyData.reduce((sum, item) => sum + item.totalQuantity, 0); + const totalDemand = demandData.reduce((sum, item) => sum + item.totalDemand, 0); + + expect(totalSupply).toBe(25000); + expect(totalDemand).toBe(20000); + }); + + it('should calculate price indices', () => { + const prices = [55, 58, 52, 60, 54]; + const avgPrice = prices.reduce((a, b) => a + b, 0) / prices.length; + const minPrice = Math.min(...prices); + const maxPrice = Math.max(...prices); + + expect(avgPrice).toBeCloseTo(55.8, 1); + expect(minPrice).toBe(52); + expect(maxPrice).toBe(60); + }); +}); diff --git a/backend/tests/vqaHelpers.test.js b/backend/tests/vqaHelpers.test.js new file mode 100644 index 0000000000000000000000000000000000000000..2af22904326022219cb36c28def332cdbd041ce2 --- /dev/null +++ b/backend/tests/vqaHelpers.test.js @@ -0,0 +1,47 @@ +import { buildReasoningChain, classifyKnowledgeType, normalizeQuestionType, parseOptions } from "../routes/vqaRoutes.js"; + +describe("AgroMind VQA helpers", () => { + test("normalizes only supported AG MMU question types", () => { + expect(normalizeQuestionType("species identification")).toBe("species identification"); + expect(normalizeQuestionType("unknown category")).toBe("auto"); + expect(normalizeQuestionType()).toBe("auto"); + }); + + test("parses and caps MCQ options at four entries", () => { + expect(parseOptions(JSON.stringify([ + { id: "A", text: "Apple" }, + { id: "B", text: "Pear" }, + { id: "C", text: "Plum" }, + { id: "D", text: "Cherry" }, + { id: "E", text: "Grape" }, + ]))).toEqual([ + { id: "A", text: "Apple" }, + { id: "B", text: "Pear" }, + { id: "C", text: "Plum" }, + { id: "D", text: "Cherry" }, + ]); + }); + + test("classifies explicit and inferred question focus", () => { + expect(classifyKnowledgeType("Which species is shown?", true, "auto")).toBe("species identification"); + expect(classifyKnowledgeType("What should I do about these spots?", true, "auto")).toBe("management instructions"); + expect(classifyKnowledgeType("Please describe what is visible", true, "auto")).toBe("symptom/visual description"); + expect(classifyKnowledgeType("Anything about this plant", true, "disease identification")).toBe("disease identification"); + }); + + test("builds a multimodal reasoning chain for multiple images", () => { + const chain = buildReasoningChain( + { N: "80", P: "", K: "", pH: "6.5", moisture: "", temperature: "", humidity: "" }, + { ndvi: "0.42", ndwi: "", weather: "dry" }, + 3, + [{ domain: "disease advice", knowledgeType: "disease identification", facts: ["fact"] }], + ); + + expect(chain).toEqual(expect.arrayContaining([ + "Rv (Visual): Analyzing 3 agricultural images for visual evidence", + "Rs (Sensor): Soil sensor readings β€” N=80 kg/ha, pH=6.5", + "Re (Environmental): Remote sensing & weather β€” NDVI=0.42, Weather: dry", + "Rk (Knowledge): Retrieved disease identification facts from disease advice", + ])); + }); +}); diff --git a/backend/tests/vqaRoutes.test.js b/backend/tests/vqaRoutes.test.js new file mode 100644 index 0000000000000000000000000000000000000000..f7093b3d5d16e9dce1fad597948d7c1bc0d15ae0 --- /dev/null +++ b/backend/tests/vqaRoutes.test.js @@ -0,0 +1,147 @@ +import { jest } from '@jest/globals'; +import express from 'express'; +import request from 'supertest'; + +const mockGenerateAIContent = jest.fn(); +const mockGenerateAIContentWithVision = jest.fn(); + +jest.unstable_mockModule('../utils/aiHelper.js', () => ({ + generateAIContent: mockGenerateAIContent, + generateAIContentWithVision: mockGenerateAIContentWithVision, +})); + +const buildApp = async () => { + const { default: router } = await import('../routes/vqaRoutes.js'); + const app = express(); + app.use(express.json()); + app.use('/api/vqa', router); + return app; +}; + +describe('POST /api/vqa/answer', () => { + beforeEach(() => { + mockGenerateAIContent.mockReset(); + mockGenerateAIContentWithVision.mockReset(); + }); + + it('requires a question', async () => { + const app = await buildApp(); + const response = await request(app).post('/api/vqa/answer').send({}); + + expect(response.status).toBe(400); + expect(response.body.success).toBe(false); + }); + + it('answers a text-only pest question grounded in the AgMMU-taxonomy knowledge base', async () => { + mockGenerateAIContent.mockResolvedValue('Aphids are damaging your cotton crop; apply neem-based insecticide.'); + + const app = await buildApp(); + const response = await request(app) + .post('/api/vqa/answer') + .send({ question: 'How do I control aphids on my cotton crop?', lang: 'en' }); + + expect(response.status).toBe(200); + expect(response.body.success).toBe(true); + expect(response.body.answer).toContain('Aphids'); + expect(response.body.retrieved_knowledge_domains).toContain('pests control'); + expect(response.body.modalities_used).toEqual({ + image: false, + sensor: false, + environmental: false, + knowledge_base: true, + }); + expect(response.body.reasoning_chain.some((r) => r.startsWith('Rk (Knowledge)'))).toBe(true); + expect(mockGenerateAIContent).toHaveBeenCalledTimes(1); + expect(mockGenerateAIContentWithVision).not.toHaveBeenCalled(); + }); + + it('routes to the vision model and reports the image modality when an image is uploaded', async () => { + mockGenerateAIContentWithVision.mockResolvedValue('This shows early blight symptoms on the leaf.'); + + const app = await buildApp(); + const response = await request(app) + .post('/api/vqa/answer') + .field('question', 'What disease is affecting these leaves?') + .attach('image', Buffer.from('fake-image-bytes'), 'leaf.jpg'); + + expect(response.status).toBe(200); + expect(response.body.modalities_used.image).toBe(true); + expect(response.body.reasoning_chain.some((r) => r.startsWith('Rv (Visual)'))).toBe(true); + expect(mockGenerateAIContentWithVision).toHaveBeenCalledTimes(1); + expect(mockGenerateAIContent).not.toHaveBeenCalled(); + }); + + it('supports four-option MCQ mode and multiple uploaded images', async () => { + mockGenerateAIContentWithVision.mockResolvedValue('Selected option: B. The second image shows the clearest symptom pattern.'); + + const app = await buildApp(); + const response = await request(app) + .post('/api/vqa/answer') + .field('question', 'Which image shows the likely disease symptom?') + .field('question_type', 'disease identification') + .field('mode', 'mcq') + .field('options', JSON.stringify([ + { id: 'A', text: 'Image one' }, + { id: 'B', text: 'Image two' }, + { id: 'C', text: 'Neither image' }, + { id: 'D', text: 'Insufficient evidence' }, + ])) + .attach('image', Buffer.from('first-image'), 'first.jpg') + .attach('images', Buffer.from('second-image'), 'second.jpg'); + + expect(response.status).toBe(200); + expect(response.body.image_count).toBe(2); + expect(response.body.question_type).toBe('disease identification'); + expect(response.body.selected_option).toBe('B'); + expect(mockGenerateAIContentWithVision).toHaveBeenCalledTimes(1); + }); + + it('rejects MCQ mode unless exactly four options are supplied', async () => { + const app = await buildApp(); + const response = await request(app) + .post('/api/vqa/answer') + .field('question', 'Which option is correct?') + .field('mode', 'mcq') + .field('options', JSON.stringify([{ id: 'A', text: 'Only one' }])); + + expect(response.status).toBe(400); + expect(response.body.success).toBe(false); + }); + + it('reports the sensor modality and biases retrieval toward nutrient deficiency when sensor data is present', async () => { + mockGenerateAIContent.mockResolvedValue('Low nitrogen reading; apply urea.'); + + const app = await buildApp(); + const response = await request(app) + .post('/api/vqa/answer') + .send({ question: 'Is my soil okay?', N: '10', pH: '6.5' }); + + expect(response.status).toBe(200); + expect(response.body.modalities_used.sensor).toBe(true); + expect(response.body.retrieved_knowledge_domains).toContain('nutrient deficiency'); + }); + + it('passes the resolved language name through to the AI call', async () => { + mockGenerateAIContent.mockResolvedValue('ΰ€‰ΰ€€ΰ₯ΰ€€ΰ€°'); + + const app = await buildApp(); + await request(app) + .post('/api/vqa/answer') + .send({ question: 'What disease is this?', lang: 'hi' }); + + const promptArg = mockGenerateAIContent.mock.calls[0][0]; + expect(promptArg).toContain('Hindi'); + }); + + it('returns a graceful error when the AI call fails', async () => { + mockGenerateAIContent.mockRejectedValue(new Error('Groq API error: upstream unavailable')); + + const app = await buildApp(); + const response = await request(app) + .post('/api/vqa/answer') + .send({ question: 'What disease is this?' }); + + expect(response.status).toBe(500); + expect(response.body.success).toBe(false); + }); +}); diff --git a/backend/utils/aiHelper.js b/backend/utils/aiHelper.js new file mode 100644 index 0000000000000000000000000000000000000000..861a061631885112015d306f96f626ceb9d841a1 --- /dev/null +++ b/backend/utils/aiHelper.js @@ -0,0 +1,144 @@ +/** + * AI API Utility + * + * Uses Groq API for all AI-powered features. + */ + +import axios from 'axios'; + +/** + * Generate AI content using Groq API + * @param {string} prompt - The prompt text for the AI + * @param {object} options - Optional configuration + * @returns {Promise} - The generated text response + */ +export async function generateAIContent(prompt, options = {}) { + const { + temperature = 0.7, + maxTokens = 2048, + model = process.env.GROQ_MODEL || 'openai/gpt-oss-120b', + _messages = null, // allow passing a full messages array (for chat history) + } = options; + + if (!process.env.GROQ_API_KEY) { + throw new Error('GROQ_API_KEY is not configured. Please set it in your environment variables.'); + } + + // Use provided messages array if given, otherwise build a simple user message + const messages = _messages || [{ role: 'user', content: prompt }]; + + try { + const response = await axios.post( + 'https://api.groq.com/openai/v1/chat/completions', + { + model: model, + messages, + temperature: temperature, + max_tokens: maxTokens + }, + { + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${process.env.GROQ_API_KEY}` + } + } + ); + + if (response.data.choices && response.data.choices.length > 0) { + return response.data.choices[0].message.content; + } else { + throw new Error('No response from Groq API'); + } + } catch (error) { + console.error('Error calling Groq API:', error.response?.data || error.message); + throw new Error(`Groq API error: ${error.response?.data?.error?.message || error.message}`, { cause: error }); + } +} + +/** + * Generate AI content with vision support using Groq API + * @param {string} prompt - The prompt text for the AI + * @param {string|Array} base64Image - One or more base64 encoded images + * @param {string} mimeType - MIME type used when an image does not provide one + * @param {object} options - Optional configuration + * @returns {Promise} - The generated text response + */ +export async function generateAIContentWithVision(prompt, base64Image, mimeType, options = {}) { + const { + temperature = 0.7, + maxTokens = 2048, + model = 'qwen/qwen3.6-27b' // Vision-capable model (llama-4-scout was deprecated by Groq on 2026-06-17) + } = options; + + if (!process.env.GROQ_API_KEY) { + throw new Error('GROQ_API_KEY is not configured. Please set it in your environment variables.'); + } + + const images = Array.isArray(base64Image) + ? base64Image.map((image) => typeof image === 'string' + ? { base64: image, mimeType } + : { base64: image.base64, mimeType: image.mimeType || mimeType }) + : [{ base64: base64Image, mimeType }]; + + try { + const response = await axios.post( + 'https://api.groq.com/openai/v1/chat/completions', + { + model: model, + messages: [ + { + role: 'user', + content: [ + { + type: 'text', + text: prompt + }, + ...images.map(({ base64, mimeType: imageMimeType }) => ({ + type: 'image_url', + image_url: { + url: `data:${imageMimeType};base64,${base64}` + } + })) + ] + } + ], + temperature: temperature, + max_tokens: maxTokens, + // qwen/qwen3.6-27b is a reasoning model. reasoning_effort:'none' + // disables its internal pass outright -- needed because + // hidden reasoning tokens still count against max_tokens, and + // callers here use small budgets (1024) that reasoning alone + // exhausted, leaving an empty final answer. reasoning_format: + // 'hidden' is kept as a defensive second layer so no + // block can leak into the response callers use as-is (shown + // directly to users in vqaRoutes.js, JSON.parsed directly in + // detectHarvestReadinessController.js). + reasoning_effort: 'none', + reasoning_format: 'hidden' + }, + { + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${process.env.GROQ_API_KEY}` + } + } + ); + + if (response.data.choices && response.data.choices.length > 0) { + return response.data.choices[0].message.content; + } else { + throw new Error('No response from Groq API'); + } + } catch (error) { + console.error('Error calling Groq Vision API:', error.response?.data || error.message); + throw new Error(`Groq Vision API error: ${error.response?.data?.error?.message || error.message}`, { cause: error }); + } +} + +/** + * Get the current AI provider being used + * @returns {string} - 'groq' or 'none' + */ +export function getAIProvider() { + return process.env.GROQ_API_KEY ? 'groq' : 'none'; +} diff --git a/backend/utils/aiOrchestrator.js b/backend/utils/aiOrchestrator.js new file mode 100644 index 0000000000000000000000000000000000000000..53e0f84f228a0cab2e52ec865ab7865fb745cc39 --- /dev/null +++ b/backend/utils/aiOrchestrator.js @@ -0,0 +1,225 @@ +/** + * Unified AI Orchestration Pipeline + * + * Flow: User Input β†’ Schema Validation β†’ Domain Engine β†’ Structured JSON β†’ + * AI Summarization β†’ Self-Reverification β†’ Language Localization β†’ Response + * + * Rules: + * - AI must NEVER calculate business values. + * - AI must ONLY summarize structured outputs. + * - AI must NOT fabricate data. + * - AI must NOT invent government schemes. + * - AI must NOT modify numeric outputs. + */ + +import { generateAIContent } from './aiHelper.js'; + +// All 22 official Indian languages +export const LANGUAGE_MAP = { + en: 'English', hi: 'Hindi', bn: 'Bengali', mr: 'Marathi', + ta: 'Tamil', te: 'Telugu', pa: 'Punjabi', gu: 'Gujarati', + kn: 'Kannada', ml: 'Malayalam', or: 'Odia', as: 'Assamese', + ur: 'Urdu', sa: 'Sanskrit', kok: 'Konkani', mni: 'Manipuri', + brx: 'Bodo', sat: 'Santhali', mai: 'Maithili', doi: 'Dogri', + ne: 'Nepali', ks: 'Kashmiri', +}; + +/** + * Extract language from request (header, query, or body) + * @param {object} req - Express request object + * @returns {string} Language code + */ +export function extractLanguage(req) { + // Priority: query param > body > Accept-Language header > default + const lang = + req.query?.lang || + req.body?.language || + req.body?.lang || + parseAcceptLanguage(req.headers?.['accept-language']) || + 'en'; + return LANGUAGE_MAP[lang] ? lang : 'en'; +} + +/** + * Parse Accept-Language header for supported language + */ +function parseAcceptLanguage(header) { + if (!header) return null; + const codes = Object.keys(LANGUAGE_MAP); + const parts = header.split(',').map((p) => p.trim().split(';')[0].trim().toLowerCase()); + for (const part of parts) { + const short = part.split('-')[0]; + if (codes.includes(short)) return short; + } + return null; +} + +/** + * Get language name from code + */ +export function getLanguageName(code) { + return LANGUAGE_MAP[code] || 'English'; +} + +/** + * Core orchestration pipeline + * + * @param {object} opts + * @param {object} opts.structuredData - Domain engine output (numbers, data) + * @param {string} opts.domainContext - What this data is about (e.g. "crop recommendation") + * @param {string} opts.languageCode - Target language code + * @param {string} [opts.userQuery] - Original user question (optional) + * @param {object} [opts.aiOptions] - Temperature / maxTokens overrides + * @returns {Promise} { summary, structuredData, language, verified } + */ +export async function orchestrate({ + structuredData, + domainContext, + languageCode = 'en', + userQuery = '', + aiOptions = {}, +}) { + const langName = getLanguageName(languageCode); + const dataStr = JSON.stringify(structuredData, null, 2); + + // Build a strict summarization prompt + const prompt = buildSummaryPrompt({ dataStr, domainContext, langName, userQuery }); + + let summary; + let verified; + + try { + summary = await generateAIContent(prompt, { + temperature: 0.3, + maxTokens: 2048, + ...aiOptions, + }); + + // Self-reverification: check for numeric accuracy + verified = verifyNumericConsistency(structuredData, summary); + + if (!verified) { + // Retry once with stricter prompt + const retryPrompt = + prompt + + '\n\nIMPORTANT: Your previous response contained numeric inaccuracies. ' + + 'You MUST use the EXACT numbers from the JSON data. Do NOT round, estimate, or change any value.'; + + summary = await generateAIContent(retryPrompt, { + temperature: 0.1, + maxTokens: 2048, + ...aiOptions, + }); + + verified = verifyNumericConsistency(structuredData, summary); + + if (!verified) { + // Final fallback: generate a safe template-based explanation + summary = buildFallbackSummary(structuredData, domainContext, langName); + verified = true; // fallback is always correct + } + } + } catch (_err) { + // AI unavailable β€” provide structured fallback + summary = buildFallbackSummary(structuredData, domainContext, langName); + verified = true; + } + + return { + summary, + structuredData, + language: langName, + languageCode, + verified, + }; +} + +/** + * Build a summarization-only prompt (no calculation) + */ +function buildSummaryPrompt({ dataStr, domainContext, langName, userQuery }) { + return `You are an agricultural AI assistant for Indian farmers. +Your task: Summarize the following STRUCTURED DATA into a clear, simple, farmer-friendly explanation. + +DOMAIN: ${domainContext} +${userQuery ? `USER QUESTION: ${userQuery}` : ''} + +STRUCTURED DATA (source of truth β€” do NOT modify any values): +${dataStr} + +STRICT RULES: +1. Use ONLY the data provided. Do NOT invent or fabricate any information. +2. Do NOT change, round, or estimate any numeric values β€” use them EXACTLY as given. +3. Do NOT invent government schemes, subsidies, or programs not mentioned in the data. +4. Use simple, easy-to-understand language suitable for farmers with limited literacy. +5. Avoid technical jargon β€” explain terms simply. +6. Keep the summary concise and actionable. +7. Respond STRICTLY in ${langName} language. +8. If ${langName} is not English, translate ALL content including technical terms. +9. Use agricultural terminology familiar to local farmers.`; +} + +/** + * Verify that key numeric values from structuredData appear in the summary + */ +const NUMERIC_VERIFICATION_THRESHOLD = 0.5; + +function verifyNumericConsistency(structuredData, summary) { + const numbers = extractNumbers(structuredData); + if (numbers.length === 0) return true; // nothing to verify + + // Check that significant numbers appear in the summary + let matchCount = 0; + for (const num of numbers) { + const numStr = String(num); + if (summary.includes(numStr)) { + matchCount++; + } + } + + // At least NUMERIC_VERIFICATION_THRESHOLD of key numbers should appear in summary + return matchCount >= Math.ceil(numbers.length * NUMERIC_VERIFICATION_THRESHOLD); +} + +/** + * Extract numeric values from an object (recursive, top-level only for performance) + */ +function extractNumbers(obj, depth = 0) { + if (depth > 3) return []; + const nums = []; + if (obj === null || obj === undefined) return nums; + + if (typeof obj === 'number' && isFinite(obj)) { + nums.push(obj); + } else if (Array.isArray(obj)) { + for (const item of obj.slice(0, 20)) { + nums.push(...extractNumbers(item, depth + 1)); + } + } else if (typeof obj === 'object') { + for (const val of Object.values(obj).slice(0, 30)) { + nums.push(...extractNumbers(val, depth + 1)); + } + } + return nums.slice(0, 20); // limit to avoid performance issues +} + +/** + * Build a safe template-based fallback summary when AI is unavailable or fails verification + */ +function buildFallbackSummary(structuredData, domainContext, langName) { + const entries = Object.entries(structuredData).slice(0, 15); + const lines = entries.map(([key, val]) => { + const label = key.replace(/([A-Z])/g, ' $1').replace(/_/g, ' ').trim(); + const value = typeof val === 'object' ? JSON.stringify(val) : String(val); + return `β€’ ${label}: ${value}`; + }); + + return `[${domainContext}] (${langName})\n\n${lines.join('\n')}`; +} + +export default { + orchestrate, + extractLanguage, + getLanguageName, + LANGUAGE_MAP, +}; diff --git a/backend/utils/firebaseRest.js b/backend/utils/firebaseRest.js new file mode 100644 index 0000000000000000000000000000000000000000..4d3e9b519c675b77b1f3c7a443357c1222147057 --- /dev/null +++ b/backend/utils/firebaseRest.js @@ -0,0 +1,190 @@ +import { randomUUID } from "node:crypto"; +import { AsyncLocalStorage } from "node:async_hooks"; + +const FIREBASE_IDENTITY_LOOKUP_URL = "https://identitytoolkit.googleapis.com/v1/accounts:lookup"; +const FIRESTORE_API_URL = "https://firestore.googleapis.com/v1"; +const requestContext = new AsyncLocalStorage(); + +const getProjectId = () => String(process.env.FIREBASE_PROJECT_ID || "").trim(); +const getApiKey = () => String(process.env.FIREBASE_API_KEY || process.env.VITE_FIREBASE_API_KEY || "").trim(); + +const requireFirebaseConfig = () => { + const projectId = getProjectId(); + const apiKey = getApiKey(); + if (!projectId || !apiKey) { + throw new Error("Firebase REST is not configured. Set FIREBASE_PROJECT_ID and FIREBASE_API_KEY."); + } + return { projectId, apiKey }; +}; + +const readError = async (response) => { + let details; + try { + const body = await response.json(); + details = body?.error?.message || body?.error?.status || JSON.stringify(body); + } catch { + details = "The Firebase REST request failed."; + } + return `${response.status} ${response.statusText}${details ? `: ${details}` : ""}`; +}; + +const requestJson = async (url, options = {}) => { + const response = await fetch(url, { + ...options, + headers: { + Accept: "application/json", + ...(options.body ? { "Content-Type": "application/json" } : {}), + ...(options.headers || {}), + }, + }); + if (!response.ok) throw new Error(await readError(response)); + if (response.status === 204) return null; + return response.json(); +}; + +const encodePath = (value) => encodeURIComponent(String(value)); + +const toFirestoreValue = (value) => { + if (value === null) return { nullValue: null }; + if (value instanceof Date) return { timestampValue: value.toISOString() }; + if (typeof value === "boolean") return { booleanValue: value }; + if (typeof value === "number") { + return Number.isInteger(value) ? { integerValue: String(value) } : { doubleValue: value }; + } + if (typeof value === "string") return { stringValue: value }; + if (Array.isArray(value)) return { arrayValue: { values: value.map(toFirestoreValue) } }; + if (value && typeof value === "object") { + return { + mapValue: { + fields: Object.fromEntries( + Object.entries(value) + .filter(([, child]) => child !== undefined) + .map(([key, child]) => [key, toFirestoreValue(child)]), + ), + }, + }; + } + return { nullValue: null }; +}; + +const fromFirestoreValue = (value = {}) => { + if (Object.prototype.hasOwnProperty.call(value, "nullValue")) return null; + if (Object.prototype.hasOwnProperty.call(value, "stringValue")) return value.stringValue; + if (Object.prototype.hasOwnProperty.call(value, "booleanValue")) return value.booleanValue; + if (Object.prototype.hasOwnProperty.call(value, "integerValue")) return Number(value.integerValue); + if (Object.prototype.hasOwnProperty.call(value, "doubleValue")) return value.doubleValue; + if (Object.prototype.hasOwnProperty.call(value, "timestampValue")) return new Date(value.timestampValue); + if (Object.prototype.hasOwnProperty.call(value, "bytesValue")) return value.bytesValue; + if (Object.prototype.hasOwnProperty.call(value, "referenceValue")) return value.referenceValue; + if (Object.prototype.hasOwnProperty.call(value, "geoPointValue")) return value.geoPointValue; + if (value.arrayValue) return (value.arrayValue.values || []).map(fromFirestoreValue); + if (value.mapValue) return Object.fromEntries(Object.entries(value.mapValue.fields || {}).map(([key, child]) => [key, fromFirestoreValue(child)])); + return undefined; +}; + +const decodeDocument = (document) => { + if (!document) return null; + const parts = String(document.name || "").split("/"); + const id = parts.at(-1); + return { + id, + _id: id, + data: Object.fromEntries(Object.entries(document.fields || {}).map(([key, value]) => [key, fromFirestoreValue(value)])), + }; +}; + +const currentToken = () => requestContext.getStore()?.idToken || null; + +export const getFirebaseIdToken = () => currentToken(); + +export const withFirebaseToken = (idToken, callback) => requestContext.run({ idToken }, callback); + +export const lookupFirebaseIdToken = async (idToken) => { + const { apiKey } = requireFirebaseConfig(); + const data = await requestJson(`${FIREBASE_IDENTITY_LOOKUP_URL}?key=${encodeURIComponent(apiKey)}`, { + method: "POST", + body: JSON.stringify({ idToken }), + }); + const account = data?.users?.[0]; + if (!account?.localId) throw new Error("Firebase Identity Toolkit returned no user"); + const provider = account.providerUserInfo?.[0] || {}; + return { + uid: account.localId, + email: account.email || provider.email || null, + name: account.displayName || provider.displayName || null, + picture: account.photoUrl || provider.photoUrl || null, + emailVerified: Boolean(account.emailVerified), + lastLoginAt: account.lastLoginAt || null, + createdAt: account.createdAt || null, + }; +}; + +const firestoreUrl = (collectionName, documentId = null) => { + const { projectId, apiKey } = requireFirebaseConfig(); + const path = `${FIRESTORE_API_URL}/projects/${encodePath(projectId)}/databases/(default)/documents/${encodePath(collectionName)}`; + const suffix = documentId === null ? "" : `/${encodePath(documentId)}`; + return `${path}${suffix}?key=${encodeURIComponent(apiKey)}`; +}; + +const firestoreHeaders = () => { + const token = currentToken(); + return token ? { Authorization: `Bearer ${token}` } : {}; +}; + +export const listFirestoreDocuments = async (collectionName) => { + try { + const data = await requestJson(firestoreUrl(collectionName), { headers: firestoreHeaders() }); + return (data?.documents || []).map(decodeDocument); + } catch (error) { + if (/^404\b/.test(error.message)) return []; + throw error; + } +}; + +export const getFirestoreDocument = async (collectionName, documentId) => { + try { + const data = await requestJson(firestoreUrl(collectionName, documentId), { headers: firestoreHeaders() }); + return decodeDocument(data); + } catch (error) { + if (/^404\b/.test(error.message)) return null; + throw error; + } +}; + +export const setFirestoreDocument = async (collectionName, documentId, value) => { + const data = await requestJson(firestoreUrl(collectionName, documentId), { + method: "PATCH", + headers: firestoreHeaders(), + body: JSON.stringify({ fields: Object.fromEntries(Object.entries(value || {}).map(([key, child]) => [key, toFirestoreValue(child)])) }), + }); + return decodeDocument(data); +}; + +export const deleteFirestoreDocument = async (collectionName, documentId) => { + try { + await requestJson(firestoreUrl(collectionName, documentId), { method: "DELETE", headers: firestoreHeaders() }); + } catch (error) { + if (!/^404\b/.test(error.message)) throw error; + } +}; + +export const createFirestoreDocument = async (collectionName, value, documentId = randomUUID()) => + setFirestoreDocument(collectionName, documentId, value); + +export const createFirestoreCollectionProxy = (collectionName) => ({ + get: async () => { + const documents = await listFirestoreDocuments(collectionName); + return { docs: documents.map((document) => ({ id: document.id, exists: true, data: () => document.data })) }; + }, + doc: (documentId = randomUUID()) => ({ + id: documentId, + get: async () => { + const document = await getFirestoreDocument(collectionName, documentId); + return { id: documentId, exists: Boolean(document), data: () => document?.data || {} }; + }, + set: async (value) => setFirestoreDocument(collectionName, documentId, value), + delete: async () => deleteFirestoreDocument(collectionName, documentId), + }), +}); + +export { fromFirestoreValue, toFirestoreValue }; diff --git a/backend/utils/firestoreCollections.js b/backend/utils/firestoreCollections.js new file mode 100644 index 0000000000000000000000000000000000000000..4eeb1c5838b909201fd7d5d906dbe85a5a3cf5fd --- /dev/null +++ b/backend/utils/firestoreCollections.js @@ -0,0 +1,26 @@ +import { createFirestoreModel } from "./firestoreModel.js"; + +export const CRMMachine = createFirestoreModel("crmMachines"); +export const CRMBooking = createFirestoreModel("crmBookings"); +export const CRMMaintenance = createFirestoreModel("crmMaintenance"); +export const Telemetry = createFirestoreModel("telemetry"); + +export const GovernmentScheme = createFirestoreModel("governmentSchemes"); +export const UserBadge = createFirestoreModel("userBadges"); +export const PriceAlert = createFirestoreModel("priceAlerts"); +export const FarmerProfile = createFirestoreModel("farmerProfiles"); +export const Notification = createFirestoreModel("notifications"); + +export const CropicClaim = createFirestoreModel("cropicClaims"); + +export const HedgingPosition = createFirestoreModel("hedgingPositions"); +export const MarketData = createFirestoreModel("marketData"); +export const EducationModule = createFirestoreModel("educationModules"); +export const ForwardContract = createFirestoreModel("forwardContracts"); + +export const MilletListing = createFirestoreModel("milletListings"); +export const QualityCertification = createFirestoreModel("qualityCertifications"); +export const MilletType = createFirestoreModel("milletTypes"); + +export const OilPalmProfile = createFirestoreModel("oilPalmProfiles"); +export const SuccessStory = createFirestoreModel("successStories"); diff --git a/backend/utils/firestoreModel.js b/backend/utils/firestoreModel.js new file mode 100644 index 0000000000000000000000000000000000000000..0fed27b186542915232f7ad392f8ccd3b5a4a842 --- /dev/null +++ b/backend/utils/firestoreModel.js @@ -0,0 +1,329 @@ +import { + createFirestoreCollectionProxy, + getFirestoreDocument, + listFirestoreDocuments, +} from "./firebaseRest.js"; + +const isObject = (value) => value && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date); +const getPath = (value, path) => path.split(".").reduce((current, key) => current?.[key], value); + +const setPath = (target, path, value) => { + const parts = path.split("."); + let cursor = target; + for (let i = 0; i < parts.length - 1; i += 1) { + cursor[parts[i]] ||= {}; + cursor = cursor[parts[i]]; + } + cursor[parts.at(-1)] = value; +}; + +const deletePath = (target, path) => { + const parts = path.split("."); + let cursor = target; + for (let i = 0; i < parts.length - 1; i += 1) { + cursor = cursor?.[parts[i]]; + if (!cursor) return; + } + delete cursor[parts.at(-1)]; +}; + +const normalizeValue = (value) => { + if (value?.toDate instanceof Function) return value.toDate(); + if (Array.isArray(value)) return value.map(normalizeValue); + if (isObject(value)) return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, normalizeValue(child)])); + return value; +}; + +const cleanValue = (value) => { + if (value instanceof Date) return value; + if (Array.isArray(value)) return value.map(cleanValue); + if (isObject(value)) { + return Object.fromEntries( + Object.entries(value) + .filter(([, child]) => child !== undefined) + .map(([key, child]) => [key, cleanValue(child)]), + ); + } + return value; +}; + +const valuesEqual = (actual, expected) => { + if (actual instanceof Date && expected instanceof Date) return actual.getTime() === expected.getTime(); + if (Array.isArray(actual)) return actual.includes(expected) || JSON.stringify(actual) === JSON.stringify(expected); + return actual === expected; +}; + +const matches = (document, filter = {}) => { + if (!filter || Object.keys(filter).length === 0) return true; + if (filter.$or) return filter.$or.some((clause) => matches(document, clause)); + if (filter.$and) return filter.$and.every((clause) => matches(document, clause)); + return Object.entries(filter).every(([path, expected]) => { + if (path.startsWith("$")) return true; + const actual = getPath(document, path); + if (!isObject(expected)) return valuesEqual(actual, expected); + return Object.entries(expected).every(([operator, value]) => { + if (operator === "$in") return value.some((candidate) => valuesEqual(actual, candidate)); + if (operator === "$nin") return !value.some((candidate) => valuesEqual(actual, candidate)); + if (operator === "$ne") return !valuesEqual(actual, value); + if (operator === "$exists") return value ? actual !== undefined : actual === undefined; + if (operator === "$gt") return actual > value; + if (operator === "$gte") return actual >= value; + if (operator === "$lt") return actual < value; + if (operator === "$lte") return actual <= value; + return valuesEqual(actual, expected); + }); + }); +}; + +const applyProjection = (document, projection) => { + if (!projection) return document; + const fields = projection.trim().split(/\s+/).filter(Boolean); + const excluded = fields.filter((field) => field.startsWith("-")).map((field) => field.slice(1)); + const included = fields.filter((field) => !field.startsWith("-")); + if (included.length > 0) { + const result = {}; + included.forEach((field) => { + const value = getPath(document, field); + if (value !== undefined) setPath(result, field, value); + }); + if (document._id !== undefined) result._id = document._id; + return result; + } + const result = { ...document }; + excluded.forEach((field) => deletePath(result, field)); + return result; +}; + +const normalizeSort = (sort) => { + if (typeof sort === "string") { + return sort.split(/\s+/).filter(Boolean).map((field) => [field.replace(/^-/, ""), field.startsWith("-") ? -1 : 1]); + } + return Object.entries(sort || {}); +}; + +const applyUpdate = (before, update, { inserting = false } = {}) => { + const next = { ...before }; + const operators = Object.keys(update || {}).some((key) => key.startsWith("$")); + if (!operators) return { ...next, ...update }; + + for (const [path, value] of Object.entries(update.$set || {})) setPath(next, path, value); + if (inserting) { + for (const [path, value] of Object.entries(update.$setOnInsert || {})) setPath(next, path, value); + } + for (const [path, value] of Object.entries(update.$inc || {})) setPath(next, path, (getPath(next, path) || 0) + value); + for (const [path, value] of Object.entries(update.$push || {})) { + const current = Array.isArray(getPath(next, path)) ? [...getPath(next, path)] : []; + if (value?.$each) current.push(...value.$each); + else current.push(value); + setPath(next, path, current); + } + for (const [path, value] of Object.entries(update.$addToSet || {})) { + const current = Array.isArray(getPath(next, path)) ? [...getPath(next, path)] : []; + const values = value?.$each || [value]; + values.forEach((item) => { + if (!current.some((existing) => valuesEqual(existing, item))) current.push(item); + }); + setPath(next, path, current); + } + for (const [path, value] of Object.entries(update.$pull || {})) { + const current = Array.isArray(getPath(next, path)) ? [...getPath(next, path)] : []; + setPath(next, path, current.filter((item) => !matches(item, isObject(value) ? value : { value }))); + } + for (const path of Object.keys(update.$unset || {})) deletePath(next, path); + return next; +}; + +class FirestoreQuery { + constructor(model, type, filter = {}, payload = null) { + this.model = model; + this.type = type; + this.filter = filter; + this.payload = payload; + this.operations = { projection: null, sort: null, limit: null, skip: 0, populate: [] }; + } + + select(projection) { this.operations.projection = projection; return this; } + sort(sort) { this.operations.sort = sort; return this; } + limit(limit) { this.operations.limit = limit; return this; } + skip(skip) { this.operations.skip = skip; return this; } + lean() { return this; } + populate(path, select) { this.operations.populate.push({ path, select }); return this; } + async exec() { return this.model._execute(this); } + then(resolve, reject) { return this.exec().then(resolve, reject); } + catch(reject) { return this.exec().catch(reject); } + finally(handler) { return this.exec().finally(handler); } +} + +export const createFirestoreModel = (collectionName) => { + const model = { + collectionName, + collection: () => createFirestoreCollectionProxy(collectionName), + find: (filter = {}) => new FirestoreQuery(model, "find", filter), + findOne: (filter = {}) => new FirestoreQuery(model, "findOne", filter), + findById: (id) => new FirestoreQuery(model, "findById", { _id: String(id) }), + create: async (data) => model._write(null, data, { add: true }), + insertMany: async (items) => Promise.all(items.map((item) => model.create(item))), + findOneAndUpdate: (filter, update, options = {}) => new FirestoreQuery(model, "findOneAndUpdate", filter, { update, options }), + updateOne: async (filter, update) => { + const found = (await model._findDocuments(filter))[0]; + if (!found) return { acknowledged: true, matchedCount: 0, modifiedCount: 0 }; + await model._write(found._id, applyUpdate(found, update)); + return { acknowledged: true, matchedCount: 1, modifiedCount: 1 }; + }, + findByIdAndUpdate: (id, update, options = {}) => new FirestoreQuery(model, "findOneAndUpdate", { _id: String(id) }, { update, options }), + findOneAndDelete: (filter) => new FirestoreQuery(model, "findOneAndDelete", filter), + findByIdAndDelete: (id) => new FirestoreQuery(model, "findOneAndDelete", { _id: String(id) }), + deleteOne: async (filter = {}) => { + const found = (await model._findDocuments(filter))[0]; + if (!found) return { acknowledged: true, deletedCount: 0 }; + await model.collection().doc(found._id).delete(); + return { acknowledged: true, deletedCount: 1 }; + }, + deleteMany: async (filter = {}) => { + const docs = await model._findDocuments(filter); + await Promise.all(docs.map((doc) => model.collection().doc(doc._id).delete())); + return { deletedCount: docs.length }; + }, + updateMany: async (filter, update) => { + const docs = await model._findDocuments(filter); + await Promise.all(docs.map((doc) => model._write(doc._id, applyUpdate(doc, update)))); + return { modifiedCount: docs.length, matchedCount: docs.length }; + }, + countDocuments: async (filter = {}) => (await model._findDocuments(filter)).length, + exists: async (filter = {}) => Boolean((await model._findDocuments(filter)).length), + aggregate: (pipeline = []) => ({ exec: async () => model._aggregate(pipeline), then(resolve, reject) { return this.exec().then(resolve, reject); } }), + _attachDocument: (document) => { + if (!document || typeof document !== "object") return document; + Object.defineProperty(document, "save", { + enumerable: false, + value: async () => model._write(document._id, document), + }); + Object.defineProperty(document, "toObject", { + enumerable: false, + value: () => ({ ...document }), + }); + return document; + }, + _serialize: (document) => model._attachDocument({ ...normalizeValue(document.data || {}), _id: document.id, id: document.id }), + _findDocuments: async (filter = {}) => { + const documents = await listFirestoreDocuments(collectionName); + return documents.map(model._serialize).filter((document) => matches(document, filter)); + }, + _write: async (id, data, { add = false } = {}) => { + const explicitId = id || data?._id || data?.id; + const documentId = add && !explicitId ? undefined : String(explicitId); + const existing = documentId ? await getFirestoreDocument(collectionName, documentId) : null; + const now = new Date(); + const next = cleanValue({ + ...(existing?.data || {}), + ...data, + updatedAt: now, + createdAt: existing?.data?.createdAt || data.createdAt || now, + }); + const saved = documentId + ? await model.collection().doc(documentId).set(next) + : await model.collection().doc().set(next); + const savedId = saved?.id || documentId; + return model._attachDocument({ ...next, _id: savedId, id: savedId }); + }, + _populate: async (documents, operations) => { + let result = documents; + for (const { path, select } of operations) { + result = await Promise.all(result.map(async (document) => { + const referenceId = document[path]; + if (!referenceId) return document; + const userDocument = await getFirestoreDocument("users", String(referenceId)); + if (!userDocument) return document; + const user = applyProjection({ ...normalizeValue(userDocument.data), _id: userDocument.id, id: userDocument.id }, select); + return { ...document, [path]: user }; + })); + } + return result; + }, + _execute: async (query) => { + if (query.type === "findById") { + const document = await getFirestoreDocument(collectionName, String(query.filter._id)); + if (!document) return null; + let result = model._serialize(document); + result = applyProjection(result, query.operations.projection); + return (await model._populate([result], query.operations.populate))[0]; + } + + if (query.type === "findOneAndUpdate") { + const found = (await model._findDocuments(query.filter))[0]; + const update = query.payload.update; + if (!found && !query.payload.options.upsert) return null; + const result = found + ? applyUpdate(found, update) + : applyUpdate(Object.fromEntries(Object.entries(query.filter).filter(([key]) => !key.startsWith("$"))), update, { inserting: true }); + const saved = await model._write(found?._id || null, result, { add: !found }); + return query.payload.options.new === false && found ? found : saved; + } + + if (query.type === "findOneAndDelete") { + const found = (await model._findDocuments(query.filter))[0]; + if (!found) return null; + await model.collection().doc(found._id).delete(); + return found; + } + + let documents = await model._findDocuments(query.filter); + if (query.operations.sort) { + const sorts = normalizeSort(query.operations.sort); + documents.sort((left, right) => { + for (const [field, direction] of sorts) { + const a = getPath(left, field); const b = getPath(right, field); + if (a === b) continue; + return (a > b ? 1 : -1) * Number(direction); + } + return 0; + }); + } + if (query.operations.skip) documents = documents.slice(query.operations.skip); + if (query.operations.limit !== null) documents = documents.slice(0, query.operations.limit); + documents = documents.map((document) => applyProjection(document, query.operations.projection)); + documents = await model._populate(documents, query.operations.populate); + return query.type === "findOne" ? documents[0] || null : documents; + }, + _aggregate: async (pipeline) => { + let rows = await model._findDocuments({}); + for (const stage of pipeline) { + if (stage.$match) rows = rows.filter((row) => matches(row, stage.$match)); + if (stage.$unwind) { + const path = String(stage.$unwind).replace(/^\$/, ""); + rows = rows.flatMap((row) => (Array.isArray(getPath(row, path)) ? getPath(row, path).map((value) => ({ ...row, [path]: value })) : [row])); + } + if (stage.$sort) { + const sorts = normalizeSort(stage.$sort); + rows.sort((a, b) => { for (const [field, direction] of sorts) { const av = getPath(a, field); const bv = getPath(b, field); if (av !== bv) return (av > bv ? 1 : -1) * Number(direction); } return 0; }); + } + if (stage.$skip) rows = rows.slice(stage.$skip); + if (stage.$limit) rows = rows.slice(0, stage.$limit); + if (stage.$project) rows = rows.map((row) => applyProjection(row, Object.entries(stage.$project).filter(([, value]) => value === 0).map(([key]) => `-${key}`).join(" "))); + if (stage.$group) { + const groups = new Map(); + for (const row of rows) { + const keyExpression = stage.$group._id; + const key = typeof keyExpression === "string" && keyExpression.startsWith("$") ? getPath(row, keyExpression.slice(1)) : keyExpression; + if (!groups.has(JSON.stringify(key))) groups.set(JSON.stringify(key), { _id: key }); + const group = groups.get(JSON.stringify(key)); + for (const [field, operation] of Object.entries(stage.$group)) { + if (field === "_id") continue; + if (operation.$sum !== undefined) group[field] = (group[field] || 0) + (typeof operation.$sum === "number" ? operation.$sum : Number(getPath(row, String(operation.$sum).replace(/^\$/, "")) || 0)); + if (operation.$push !== undefined) (group[field] ||= []).push(typeof operation.$push === "string" ? getPath(row, operation.$push.replace(/^\$/, "")) : operation.$push); + } + } + rows = [...groups.values()]; + } + } + return rows; + }, + }; + const FirestoreModel = function FirestoreModel(data = {}) { + return model._attachDocument({ ...data, _id: data._id || data.id || undefined, id: data.id || data._id || undefined }); + }; + Object.assign(FirestoreModel, model); + return FirestoreModel; +}; + +export { applyProjection, applyUpdate, getPath, matches }; diff --git a/backend/utils/initSocket.js b/backend/utils/initSocket.js new file mode 100644 index 0000000000000000000000000000000000000000..9a068f14108fac609ea92f4e6ec17f5d509a7025 --- /dev/null +++ b/backend/utils/initSocket.js @@ -0,0 +1,27 @@ +// utils/socket.js +export default function initSocket(io) { + io.on('connection', (socket) => { + console.log(`User connected: ${socket.id}`); + + socket.on('start-call', (data) => { + const { appointmentId } = data; + socket.join(appointmentId); + io.to(appointmentId).emit('call-started', appointmentId); // Ensure event is sent to the specific room + }); + + socket.on('join-call', (data) => { + const { appointmentId } = data; + socket.join(appointmentId); + io.to(appointmentId).emit('call-joined', { appointmentId }); + }); + + socket.on('signal', (data) => { + const { appointmentId, signalData } = data; + socket.to(appointmentId).emit('signal', { signalData }); + }); + + socket.on('disconnect', () => { + console.log(`User disconnected: ${socket.id}`); + }); + }); +} diff --git a/backend/utils/roleValidator.js b/backend/utils/roleValidator.js new file mode 100644 index 0000000000000000000000000000000000000000..144faceb609cebee560b53ae3653c33af8f64ef7 --- /dev/null +++ b/backend/utils/roleValidator.js @@ -0,0 +1,9 @@ +/** + * Validates the role and returns a valid role or default to 'farmer' + * @param {string} role - The role to validate + * @returns {string} - A valid role ('farmer' or 'expert') + */ +export const validateRole = (role) => { + const validRoles = ['farmer', 'expert']; + return role && validRoles.includes(role) ? role : 'farmer'; +}; diff --git a/backend/vercel.json b/backend/vercel.json new file mode 100644 index 0000000000000000000000000000000000000000..7c160381ec8061d2cd2e4462dad7f32a3e1f3770 --- /dev/null +++ b/backend/vercel.json @@ -0,0 +1,26 @@ +{ + "installCommand": "npm install", + "version": 2, + "builds": [ + { + "src": "server.js", + "use": "@vercel/node" + }, + { + "src": "src/**/*", + "use": "@vercel/static" + } + ], + "routes": [ + { + "src": "/(.*)", + "dest": "/", + "methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"], + "headers": { + "Access-Control-Allow-Credentials": "true", + "Access-Control-Allow-Methods": "GET,OPTIONS,PATCH,DELETE,POST,PUT", + "Access-Control-Allow-Headers": "*" + } + } + ] +} \ No newline at end of file