Skip to content

Dev-Salem/plant_app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

51 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Planty - Plant Disease Diagnosis App

๐Ÿ“Œ Overview

Planty is a mobile application that leverages Artificial Intelligence (AI) and Computer Vision to help farmers and agricultural specialists diagnose plant diseases instantly. By simply taking a picture of a plant leaf, users receive an instant diagnosis and the ability to purchase agricultural products directly through the app.

Screenshots:

Screenshot 1 Screenshot 2

๐Ÿš€ Features

1๏ธโƒฃ Instant AI Diagnosis

  • Take a picture or upload an image of a plant.
  • AI detects plant diseases, pests, or nutrient deficiencies.
  • Provides instant results with treatment recommendations.

3๏ธโƒฃ Marketplace for Agricultural Products

  • Buy recommended pesticides, fertilizers, and treatments.
  • Admin dashboard for managing products & orders

4๏ธโƒฃ Diagnosis History & Tracking

  • View past scans and AI-generated reports.
  • Track disease trends over time.

๐ŸŽฏ Target Users

  • Farmers & Growers looking for fast disease diagnosis.
  • Agricultural Specialists needing AI-powered insights.
  • Agriculture Companies selling pesticides and fertilizers.

Architecture

The application follows Riverpod/Reference Architecture:

  • Presentation Layer: Widgets, Screens, Controllers (Notifiers & Providers) for managing the state
  • Data Layer: Repositories and Data sources
  • Domain Layer: Models and business entities

Project Structure

|- assets  <- images & app icon
|
|- lib
   |
   |_ ๐Ÿ“src
       |
       |__ ๐Ÿ“core  <- (constants, theme, shared widgets, utils)
       |
       |__ ๐Ÿ“auth  
       |    |
       |    |__ ๐Ÿ“data  <- (auth repository: sign in, sign out, getAccount, verifyOTP, etc.)
       |    |
       |    |__ ๐Ÿ“presentation  <- (controllers for managing state with Riverpod 2.0 & Screens/Widgets)
       |
       |__ ๐Ÿ“scan  
       |    |
       |    |__ ๐Ÿ“data  <- (scan repository: save scan, get scan, get scans, save & delete access tokens)
       |    |
       |    |__ ๐Ÿ“domain  <- (entities: PlantScanResponse, ScanResult, InputData, PlantStatus, Disease, etc.)
       |    |
       |    |__ ๐Ÿ“presentation  <- (controllers for managing state with Riverpod 2.0 & Screens/Widgets)
       |
       |__ ๐Ÿ“onboarding  
       |    |
       |    |__ ๐Ÿ“domain  <- (Onboarding Content)
       |    |
       |    |__ ๐Ÿ“presentation  <- (Onboarding & Welcome Screens)
       |
       |__ ๐Ÿ“market  
       |    |
       |    |__ ๐Ÿ“data  <- (AppwriteMarketRepository & IMarketplaceService: manage products, carts, and orders)
       |    |
       |    |__ ๐Ÿ“domain  <- (entities: Product, CartItem, Order, OrderItem)
       |    |
       |    |__ ๐Ÿ“presentation  <- (controllers for managing state with Riverpod 2.0 & Screens/Widgets)
       |
       |__ ๐Ÿ“admin  
       |    |
       |    |__ ๐Ÿ“data  <- (IAdminService & AppwriteAdminRepository: manage products & orders, edit, add, or delete them)
       |    |
       |    |__ ๐Ÿ“presentation  <- (controllers for managing state with Riverpod 2.0 & Screens/Widgets)

โšก Installation & Setup

1๏ธโƒฃ Clone the Repository

git clone https://github.com/Dev-Salem/plant_app

2๏ธโƒฃ Install Dependencies & configure secrets using envied

flutter pub get

Create .env at the root director with these values:

ENDPOINT=https://cloud.appwrite.io/v1
PROJECT_ID=project-id-from-appwrite-console

3๏ธโƒฃ Run the App

flutter run

4๏ธโƒฃ Backend Setup (Using Appwrite)

  • Sign in for Appwrite
  • Create project & follow the instruction
  • Create collections using Python SDK with this script:
Python script for creating collections
import logging
import sys

from appwrite.client import Client
from appwrite.services.databases import Databases

# Set up logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    handlers=[
        logging.FileHandler("appwrite_setup.log"),
        logging.StreamHandler(sys.stdout),
    ],
)
logger = logging.getLogger("AppwriteSetup")

# Initialize Appwrite client
client = Client()
client.set_endpoint("https://cloud.appwrite.io/v1")
client.set_project("")
client.set_key(
    ""
)
# Connect to database service
databases = Databases(client)
DATABASE_ID = "planty-db-id"


def create_products_collection():
    logger.info("๐Ÿ”„ Creating products collection...")
    try:
        # Check if collection exists
        try:
            collection = databases.get_collection(DATABASE_ID, "products")
            logger.info("  โœ“ Products collection already exists")
        except:
            # Create the collection
            collection = databases.create_collection(
                database_id=DATABASE_ID, collection_id="products", name="Products"
            )
            logger.info("  โœ“ Products collection created")

            # Create attributes based on the Product entity
            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="products",
                key="name",
                size=255,
                required=True,
            )

            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="products",
                key="description",
                size=10000,
                required=True,
            )

            databases.create_float_attribute(
                database_id=DATABASE_ID,
                collection_id="products",
                key="price",
                required=True,
            )

            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="products",
                key="imageUrl",
                size=2048,
                required=True,
            )

            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="products",
                key="category",
                size=100,
                required=True,
                default="Other",
            )

            databases.create_boolean_attribute(
                database_id=DATABASE_ID,
                collection_id="products",
                key="isAvailable",
                required=True,
                default=True,
            )

            # Create indexes
            databases.create_index(
                database_id=DATABASE_ID,
                collection_id="products",
                key="name_index",
                type="fulltext",
                attributes=["name"],
            )

            databases.create_index(
                database_id=DATABASE_ID,
                collection_id="products",
                key="category_index",
                type="key",
                attributes=["category"],
            )

        logger.info("โœ… Products collection setup complete")
        return True
    except Exception as e:
        logger.error(f"โŒ Error creating products collection: {str(e)}")
        return False


def create_cart_items_collection():
    logger.info("๐Ÿ”„ Creating cart_items collection...")
    try:
        # Check if collection exists
        try:
            collection = databases.get_collection(DATABASE_ID, "cart_items")
            logger.info("  โœ“ Cart items collection already exists")
        except:
            # Create the collection
            collection = databases.create_collection(
                database_id=DATABASE_ID, collection_id="cart_items", name="Cart Items"
            )
            logger.info("  โœ“ Cart items collection created")

            # Create attributes based on the CartItem entity
            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="cart_items",
                key="userId",
                size=100,
                required=True,
            )

            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="cart_items",
                key="productId",
                size=100,
                required=True,
            )

            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="cart_items",
                key="productName",
                size=255,
                required=True,
            )

            databases.create_float_attribute(
                database_id=DATABASE_ID,
                collection_id="cart_items",
                key="price",
                required=True,
            )

            databases.create_integer_attribute(
                database_id=DATABASE_ID,
                collection_id="cart_items",
                key="quantity",
                required=True,
                min=1,
            )

            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="cart_items",
                key="imageUrl",
                size=2048,
                required=True,
            )

            # Create indexes
            databases.create_index(
                database_id=DATABASE_ID,
                collection_id="cart_items",
                key="userId_index",
                type="key",
                attributes=["userId"],
            )

            databases.create_index(
                database_id=DATABASE_ID,
                collection_id="cart_items",
                key="user_product_index",
                type="key",
                attributes=["userId", "productId"],
            )

        logger.info("โœ… Cart items collection setup complete")
        return True
    except Exception as e:
        logger.error(f"โŒ Error creating cart items collection: {str(e)}")
        return False


def create_orders_collection():
    logger.info("๐Ÿ”„ Creating orders collection...")
    try:
        # Check if collection exists
        try:
            collection = databases.get_collection(DATABASE_ID, "orders")
            logger.info("  โœ“ Orders collection already exists")
        except:
            # Create the collection
            collection = databases.create_collection(
                database_id=DATABASE_ID, collection_id="orders", name="Orders"
            )
            logger.info("  โœ“ Orders collection created")

            # Create attributes based on the Order entity
            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="orders",
                key="userId",
                size=100,
                required=True,
            )

            databases.create_float_attribute(
                database_id=DATABASE_ID,
                collection_id="orders",
                key="totalAmount",
                required=True,
            )

            databases.create_datetime_attribute(
                database_id=DATABASE_ID,
                collection_id="orders",
                key="dateTime",
                required=True,
            )

            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="orders",
                key="status",
                size=50,
                required=True,
            )

            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="orders",
                key="address",
                size=1000,
                required=False,
            )

            # Create indexes
            databases.create_index(
                database_id=DATABASE_ID,
                collection_id="orders",
                key="userId_index",
                type="key",
                attributes=["userId"],
            )

            databases.create_index(
                database_id=DATABASE_ID,
                collection_id="orders",
                key="status_index",
                type="key",
                attributes=["status"],
            )

            databases.create_index(
                database_id=DATABASE_ID,
                collection_id="orders",
                key="dateTime_index",
                type="key",
                attributes=["dateTime"],
            )

        logger.info("โœ… Orders collection setup complete")
        return True
    except Exception as e:
        logger.error(f"โŒ Error creating orders collection: {str(e)}")
        return False


def create_order_items_collection():
    logger.info("๐Ÿ”„ Creating order_items collection...")
    try:
        # Check if collection exists
        try:
            collection = databases.get_collection(DATABASE_ID, "order_items")
            logger.info("  โœ“ Order items collection already exists")
        except:
            # Create the collection
            collection = databases.create_collection(
                database_id=DATABASE_ID, collection_id="order_items", name="Order Items"
            )
            logger.info("  โœ“ Order items collection created")

            # Create attributes based on the OrderItem entity
            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="order_items",
                key="orderId",
                size=100,
                required=True,
            )

            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="order_items",
                key="productId",
                size=100,
                required=True,
            )

            databases.create_string_attribute(
                database_id=DATABASE_ID,
                collection_id="order_items",
                key="productName",
                size=255,
                required=True,
            )

            databases.create_float_attribute(
                database_id=DATABASE_ID,
                collection_id="order_items",
                key="price",
                required=True,
            )

            databases.create_integer_attribute(
                database_id=DATABASE_ID,
                collection_id="order_items",
                key="quantity",
                required=True,
                min=1,
            )

            # Create indexes
            databases.create_index(
                database_id=DATABASE_ID,
                collection_id="order_items",
                key="orderId_index",
                type="key",
                attributes=["orderId"],
            )

        logger.info("โœ… Order items collection setup complete")
        return True
    except Exception as e:
        logger.error(f"โŒ Error creating order items collection: {str(e)}")
        return False


if __name__ == "__main__":
    logger.info("๐Ÿš€ Starting Appwrite Plant App setup script...")

    # Create all collections
    products_result = create_products_collection()
    cart_items_result = create_cart_items_collection()
    orders_result = create_orders_collection()
    order_items_result = create_order_items_collection()

    # Print summary
    logger.info("\n๐Ÿ“Š SETUP SUMMARY:")
    logger.info(
        f"Products collection: {'โœ… SUCCESS' if products_result else 'โŒ FAILED'}"
    )
    logger.info(
        f"Cart items collection: {'โœ… SUCCESS' if cart_items_result else 'โŒ FAILED'}"
    )
    logger.info(f"Orders collection: {'โœ… SUCCESS' if orders_result else 'โŒ FAILED'}")
    logger.info(
        f"Order items collection: {'โœ… SUCCESS' if order_items_result else 'โŒ FAILED'}"
    )

    if all([products_result, cart_items_result, orders_result, order_items_result]):
        logger.info("\n๐ŸŽ‰ All collections created successfully!")
    else:
        logger.warning("\nโš ๏ธ Some collections have issues. Check the logs for details.")

๐Ÿ“œ Business Model & Monetization

  • Freemium Model: Free basic scans with premium features (e.g., detailed analysis).
  • Marketplace Commission: Earn from product sales via partnerships with suppliers.
  • Subscription Plans: Offer advanced AI-based insights for professional farmers.

๐Ÿ”ฎ Future Enhancements

  • โœ”๏ธ Offline Mode โ€“ Enable diagnosis without internet.
  • โœ”๏ธ Community Forum โ€“ Allow farmers to discuss issues.
  • โœ”๏ธ Multi-language Support โ€“ Expand to other languages.

Known Issues:

  • The demo is deployed on github pages and is not meant for web usage
  • images might not render because CORS issues with Crop API
  • There might be issues with other browsers other than Chrome
  • Payment for the mini market place isn't configured
  • Legal documents (like Privacy & Policy, Terms Of Use) are not presented

About

An app to diagnose plant diseases with AI

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages