├── README.md ├── server ├── requirements.txt ├── static │ ├── download.jpg │ ├── images.jpeg │ ├── images (1).jpeg │ ├── images (2).jpeg │ ├── images (3).jpeg │ ├── images (5).jpeg │ ├── images (6).jpeg │ ├── images (7).jpeg │ ├── alternaria (24).jpeg │ ├── Alternaria Leaf resized.jpg │ ├── XkvoUQ5ffAU8j5Fq8DK3Vf.jpg │ ├── bacterial_spot_tomato.jpg │ ├── Mycosphaerella_fragariae_2.jpg │ ├── Common_Leaf_Spot_of_Strawberry.jpg │ ├── bacterial-spot-of-pepper-pepper-1560240277.jpg │ ├── 360_F_113671201_gYvMp03B480EMamMDFVQLcwVGJeXa0i7.jpg │ ├── 360_F_731867902_FVJfWSSYmA89ZPJZHDUpYqoduH9YsweU.jpg │ ├── ff8b36d5-feaf-4d2d-8126-18670a312657___RS_HL 0229.JPG │ ├── fe28e4c7-0c35-4f52-984e-0e60f33a2c6e___GH_HL Leaf 198.JPG │ ├── 0a0dbf1f-1131-496f-b337-169ec6693e6f___NREC_B.Spot 9241.JPG │ ├── 0a8a68ee-f587-4dea-beec-79d02e7d3fa4___RS_Early.B 8461.JPG │ ├── 0b13b997-9957-4029-b2a4-ef4a046eb088___UF.GRC_BS_Lab Leaf 0595.JPG │ └── Early-blight-diseases-infected-potato-leaf-Introduction-Early-blight-of-potato-is-caused.png ├── __pycache__ │ ├── utils.cpython-311.pyc │ └── openai_api.cpython-311.pyc ├── utils.py ├── templates │ ├── index.html │ └── result.html ├── openai.py ├── class_indices.json └── app.py ├── jsconfig.json ├── next.config.mjs ├── postcss.config.mjs ├── public ├── vercel.svg ├── window.svg ├── file.svg ├── placeholder.svg ├── globe.svg └── next.svg ├── src ├── lib │ └── utils.js ├── app │ ├── page.js │ ├── layout.js │ ├── components │ │ ├── AboutUs.jsx │ │ ├── HowItWorks.jsx │ │ ├── Prediction.jsx │ │ ├── Hero.jsx │ │ └── UserInput.jsx │ └── globals.css └── components │ └── ui │ ├── input.jsx │ ├── badge.jsx │ ├── accordion.jsx │ ├── button.jsx │ ├── card.jsx │ ├── select.jsx │ ├── sheet.jsx │ └── navigation-menu.jsx ├── eslint.config.mjs ├── .gitignore ├── components.json ├── SECURITY.md ├── package.json └── tailwind.config.js /README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /server/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | tensorflow 3 | openai 4 | pillow 5 | -------------------------------------------------------------------------------- /server/static/download.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/download.jpg -------------------------------------------------------------------------------- /server/static/images.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/images.jpeg -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: ["@tailwindcss/postcss"], 3 | }; 4 | 5 | export default config; 6 | -------------------------------------------------------------------------------- /server/static/images (1).jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/images (1).jpeg -------------------------------------------------------------------------------- /server/static/images (2).jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/images (2).jpeg -------------------------------------------------------------------------------- /server/static/images (3).jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/images (3).jpeg -------------------------------------------------------------------------------- /server/static/images (5).jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/images (5).jpeg -------------------------------------------------------------------------------- /server/static/images (6).jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/images (6).jpeg -------------------------------------------------------------------------------- /server/static/images (7).jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/images (7).jpeg -------------------------------------------------------------------------------- /server/static/alternaria (24).jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/alternaria (24).jpeg -------------------------------------------------------------------------------- /server/__pycache__/utils.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/__pycache__/utils.cpython-311.pyc -------------------------------------------------------------------------------- /server/static/Alternaria Leaf resized.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/Alternaria Leaf resized.jpg -------------------------------------------------------------------------------- /server/static/XkvoUQ5ffAU8j5Fq8DK3Vf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/XkvoUQ5ffAU8j5Fq8DK3Vf.jpg -------------------------------------------------------------------------------- /server/static/bacterial_spot_tomato.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/bacterial_spot_tomato.jpg -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/__pycache__/openai_api.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/__pycache__/openai_api.cpython-311.pyc -------------------------------------------------------------------------------- /server/static/Mycosphaerella_fragariae_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/Mycosphaerella_fragariae_2.jpg -------------------------------------------------------------------------------- /server/static/Common_Leaf_Spot_of_Strawberry.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/Common_Leaf_Spot_of_Strawberry.jpg -------------------------------------------------------------------------------- /src/lib/utils.js: -------------------------------------------------------------------------------- 1 | import { clsx } from "clsx"; 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /server/static/bacterial-spot-of-pepper-pepper-1560240277.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/bacterial-spot-of-pepper-pepper-1560240277.jpg -------------------------------------------------------------------------------- /server/static/360_F_113671201_gYvMp03B480EMamMDFVQLcwVGJeXa0i7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/360_F_113671201_gYvMp03B480EMamMDFVQLcwVGJeXa0i7.jpg -------------------------------------------------------------------------------- /server/static/360_F_731867902_FVJfWSSYmA89ZPJZHDUpYqoduH9YsweU.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/360_F_731867902_FVJfWSSYmA89ZPJZHDUpYqoduH9YsweU.jpg -------------------------------------------------------------------------------- /server/static/ff8b36d5-feaf-4d2d-8126-18670a312657___RS_HL 0229.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/ff8b36d5-feaf-4d2d-8126-18670a312657___RS_HL 0229.JPG -------------------------------------------------------------------------------- /server/static/fe28e4c7-0c35-4f52-984e-0e60f33a2c6e___GH_HL Leaf 198.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/fe28e4c7-0c35-4f52-984e-0e60f33a2c6e___GH_HL Leaf 198.JPG -------------------------------------------------------------------------------- /server/static/0a0dbf1f-1131-496f-b337-169ec6693e6f___NREC_B.Spot 9241.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/0a0dbf1f-1131-496f-b337-169ec6693e6f___NREC_B.Spot 9241.JPG -------------------------------------------------------------------------------- /server/static/0a8a68ee-f587-4dea-beec-79d02e7d3fa4___RS_Early.B 8461.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/0a8a68ee-f587-4dea-beec-79d02e7d3fa4___RS_Early.B 8461.JPG -------------------------------------------------------------------------------- /server/static/0b13b997-9957-4029-b2a4-ef4a046eb088___UF.GRC_BS_Lab Leaf 0595.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/0b13b997-9957-4029-b2a4-ef4a046eb088___UF.GRC_BS_Lab Leaf 0595.JPG -------------------------------------------------------------------------------- /server/static/Early-blight-diseases-infected-potato-leaf-Introduction-Early-blight-of-potato-is-caused.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Harshkotkar/plant-disease/HEAD/server/static/Early-blight-diseases-infected-potato-leaf-Introduction-Early-blight-of-potato-is-caused.png -------------------------------------------------------------------------------- /server/utils.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | import numpy as np 3 | 4 | def load_and_preprocess_image(image, target_size=(256, 256)): 5 | img = Image.open(image) 6 | img = img.resize(target_size) 7 | img_array = np.array(img) / 255.0 8 | img_array = np.expand_dims(img_array, axis=0) 9 | return img_array 10 | -------------------------------------------------------------------------------- /src/app/page.js: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | // import Navbar from "./components/Navbar"; 3 | import Hero from "./components/Hero"; 4 | import HowItWorks from "./components/HowItWorks"; 5 | 6 | export default function Home() { 7 | return ( 8 | <> 9 | {/* */} 10 | 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Plant Disease Classifier 5 | 6 | 7 |

Plant Disease Classifier 🌿

8 |
9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /server/templates/result.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Prediction Result 5 | 6 | 7 |

Prediction Result 🌱

8 | Uploaded Image 9 |

Predicted Class: {{ prediction }}

10 |

Confidence: {{ confidence }}%

11 | Back to Home 12 | 13 | 14 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path"; 2 | import { fileURLToPath } from "url"; 3 | import { FlatCompat } from "@eslint/eslintrc"; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = dirname(__filename); 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }); 11 | 12 | const eslintConfig = [...compat.extends("next/core-web-vitals")]; 13 | 14 | export default eslintConfig; 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /node_modules 3 | /.pnp 4 | .pnp.* 5 | .yarn/* 6 | !.yarn/patches 7 | !.yarn/plugins 8 | !.yarn/releases 9 | !.yarn/versions 10 | 11 | /coverage 12 | 13 | /.next/ 14 | /out/ 15 | /build 16 | 17 | 18 | .DS_Store 19 | *.pem 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | .pnpm-debug.log* 25 | 26 | .env* 27 | 28 | *.tsbuildinfo 29 | next-env.d.ts 30 | C:\Users\HP\Desktop\plant-disease\server\env 31 | server\model 32 | "C:\Users\HP\Desktop\plant-disease\server\openai_api.py" -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": false, 6 | "tailwind": { 7 | "config": "", 8 | "css": "src/app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | }, 20 | "iconLibrary": "lucide" 21 | } -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /server/openai.py: -------------------------------------------------------------------------------- 1 | import openai 2 | import os 3 | from dotenv import load_dotenv 4 | 5 | 6 | load_dotenv() 7 | openai.api_key = os.getenv("OPENAI_API_KEY") 8 | 9 | # Initialize the OpenAI client 10 | client = openai.Client() 11 | 12 | def generate_advice(disease_name): 13 | prompt = f""" 14 | Provide details about the following plant disease: 15 | Disease: {disease_name} 16 | 17 | Include: 18 | - Causes 19 | - Precautionary Measures 20 | - Recommended Pesticides 21 | """ 22 | 23 | # Updated API format for chat completion 24 | response = client.chat.completions.create( 25 | model="gpt-3.5-turbo", 26 | messages=[{"role": "user", "content": prompt}], 27 | max_tokens=200 28 | ) 29 | 30 | return response.choices[0].message.content.strip() 31 | -------------------------------------------------------------------------------- /public/placeholder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/app/layout.js: -------------------------------------------------------------------------------- 1 | import { Geist, Geist_Mono } from "next/font/google"; 2 | import "./globals.css"; 3 | import AboutUs from "./components/AboutUs"; 4 | import React from "react"; 5 | const geistSans = Geist({ 6 | variable: "--font-geist-sans", 7 | subsets: ["latin"], 8 | }); 9 | 10 | const geistMono = Geist_Mono({ 11 | variable: "--font-geist-mono", 12 | subsets: ["latin"], 13 | }); 14 | 15 | export const metadata = { 16 | title: "Bio-Bytes", 17 | description: "Generated by create next app", 18 | }; 19 | 20 | export default function RootLayout({ children }) { 21 | return ( 22 | 23 | 26 | 27 | {children} 28 | 29 | 30 | 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "plant_disease", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev --turbopack", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@radix-ui/react-accordion": "^1.2.3", 13 | "@radix-ui/react-dialog": "^1.1.6", 14 | "@radix-ui/react-navigation-menu": "^1.2.5", 15 | "@radix-ui/react-select": "^2.1.6", 16 | "@radix-ui/react-slot": "^1.1.2", 17 | "class-variance-authority": "^0.7.1", 18 | "clsx": "^2.1.1", 19 | "lucide-react": "^0.482.0", 20 | "next": "15.2.2", 21 | "react": "^19.0.0", 22 | "react-dom": "^19.0.0", 23 | "tailwind-merge": "^3.0.2", 24 | "tailwindcss-animate": "^1.0.7" 25 | }, 26 | "devDependencies": { 27 | "@eslint/eslintrc": "^3", 28 | "@tailwindcss/postcss": "^4", 29 | "eslint": "^9", 30 | "eslint-config-next": "15.2.2", 31 | "tailwindcss": "^4" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ui/input.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | function Input({ 6 | className, 7 | type, 8 | ...props 9 | }) { 10 | return ( 11 | 21 | ); 22 | } 23 | 24 | export { Input } 25 | -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/class_indices.json: -------------------------------------------------------------------------------- 1 | { 2 | "0": "Apple___Apple_scab", 3 | "1": "Apple___Black_rot", 4 | "2": "Apple___Cedar_apple_rust", 5 | "3": "Apple___healthy", 6 | "4": "Blueberry___healthy", 7 | "5": "Cherry_(including_sour)___Powdery_mildew", 8 | "6": "Cherry_(including_sour)___healthy", 9 | "7": "Corn_(maize)___Cercospora_leaf_spot Gray_leaf_spot", 10 | "8": "Corn_(maize)___Common_rust_", 11 | "9": "Corn_(maize)___Northern_Leaf_Blight", 12 | "10": "Corn_(maize)___healthy", 13 | "11": "Grape___Black_rot", 14 | "12": "Grape___Esca_(Black_Measles)", 15 | "13": "Grape___Leaf_blight_(Isariopsis_Leaf_Spot)", 16 | "14": "Grape___healthy", 17 | "15": "Orange___Haunglongbing_(Citrus_greening)", 18 | "16": "Peach___Bacterial_spot", 19 | "17": "Peach___healthy", 20 | "18": "Pepper,_bell___Bacterial_spot", 21 | "19": "Pepper,_bell___healthy", 22 | "20": "Potato___Early_blight", 23 | "21": "Potato___Late_blight", 24 | "22": "Potato___healthy", 25 | "23": "Raspberry___healthy", 26 | "24": "Soybean___healthy", 27 | "25": "Squash___Powdery_mildew", 28 | "26": "Strawberry___Leaf_scorch", 29 | "27": "Strawberry___healthy", 30 | "28": "Tomato___Bacterial_spot", 31 | "29": "Tomato___Early_blight", 32 | "30": "Tomato___Late_blight", 33 | "31": "Tomato___Leaf_Mold", 34 | "32": "Tomato___Septoria_leaf_spot", 35 | "33": "Tomato___Spider_mites Two-spotted_spider_mite", 36 | "34": "Tomato___Target_Spot", 37 | "35": "Tomato___Tomato_Yellow_Leaf_Curl_Virus", 38 | "36": "Tomato___Tomato_mosaic_virus", 39 | "37": "Tomato___healthy" 40 | } -------------------------------------------------------------------------------- /src/components/ui/badge.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { Slot } from "@radix-ui/react-slot" 3 | import { cva } from "class-variance-authority"; 4 | 5 | import { cn } from "@/lib/utils" 6 | 7 | const badgeVariants = cva( 8 | "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", 9 | { 10 | variants: { 11 | variant: { 12 | default: 13 | "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", 14 | secondary: 15 | "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", 16 | destructive: 17 | "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/70", 18 | outline: 19 | "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", 20 | }, 21 | }, 22 | defaultVariants: { 23 | variant: "default", 24 | }, 25 | } 26 | ) 27 | 28 | function Badge({ 29 | className, 30 | variant, 31 | asChild = false, 32 | ...props 33 | }) { 34 | const Comp = asChild ? Slot : "span" 35 | 36 | return ( 37 | 41 | ); 42 | } 43 | 44 | export { Badge, badgeVariants } 45 | -------------------------------------------------------------------------------- /src/components/ui/accordion.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as AccordionPrimitive from "@radix-ui/react-accordion" 5 | import { ChevronDownIcon } from "lucide-react" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | function Accordion({ 10 | ...props 11 | }) { 12 | return ; 13 | } 14 | 15 | function AccordionItem({ 16 | className, 17 | ...props 18 | }) { 19 | return ( 20 | 24 | ); 25 | } 26 | 27 | function AccordionTrigger({ 28 | className, 29 | children, 30 | ...props 31 | }) { 32 | return ( 33 | 34 | svg]:rotate-180", 38 | className 39 | )} 40 | {...props}> 41 | {children} 42 | 44 | 45 | 46 | ); 47 | } 48 | 49 | function AccordionContent({ 50 | className, 51 | children, 52 | ...props 53 | }) { 54 | return ( 55 | 59 |
{children}
60 |
61 | ); 62 | } 63 | 64 | export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } 65 | -------------------------------------------------------------------------------- /src/components/ui/button.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { Slot } from "@radix-ui/react-slot" 3 | import { cva } from "class-variance-authority"; 4 | 5 | import { cn } from "@/lib/utils" 6 | 7 | const buttonVariants = cva( 8 | "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", 9 | { 10 | variants: { 11 | variant: { 12 | default: 13 | "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", 14 | destructive: 15 | "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", 16 | outline: 17 | "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", 18 | secondary: 19 | "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", 20 | ghost: 21 | "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", 22 | link: "text-primary underline-offset-4 hover:underline", 23 | }, 24 | size: { 25 | default: "h-9 px-4 py-2 has-[>svg]:px-3", 26 | sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", 27 | lg: "h-10 rounded-md px-6 has-[>svg]:px-4", 28 | icon: "size-9", 29 | }, 30 | }, 31 | defaultVariants: { 32 | variant: "default", 33 | size: "default", 34 | }, 35 | } 36 | ) 37 | 38 | function Button({ 39 | className, 40 | variant, 41 | size, 42 | asChild = false, 43 | ...props 44 | }) { 45 | const Comp = asChild ? Slot : "button" 46 | 47 | return ( 48 | 52 | ); 53 | } 54 | 55 | export { Button, buttonVariants } 56 | -------------------------------------------------------------------------------- /src/components/ui/card.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | function Card({ 6 | className, 7 | ...props 8 | }) { 9 | return ( 10 |
17 | ); 18 | } 19 | 20 | function CardHeader({ 21 | className, 22 | ...props 23 | }) { 24 | return ( 25 |
32 | ); 33 | } 34 | 35 | function CardTitle({ 36 | className, 37 | ...props 38 | }) { 39 | return ( 40 |
44 | ); 45 | } 46 | 47 | function CardDescription({ 48 | className, 49 | ...props 50 | }) { 51 | return ( 52 |
56 | ); 57 | } 58 | 59 | function CardAction({ 60 | className, 61 | ...props 62 | }) { 63 | return ( 64 |
71 | ); 72 | } 73 | 74 | function CardContent({ 75 | className, 76 | ...props 77 | }) { 78 | return (
); 79 | } 80 | 81 | function CardFooter({ 82 | className, 83 | ...props 84 | }) { 85 | return ( 86 |
90 | ); 91 | } 92 | 93 | export { 94 | Card, 95 | CardHeader, 96 | CardFooter, 97 | CardTitle, 98 | CardAction, 99 | CardDescription, 100 | CardContent, 101 | } 102 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | darkMode: ["class"], 4 | content: [ 5 | "./pages/**/*.{js,jsx}", 6 | "./components/**/*.{js,jsx}", 7 | "./app/**/*.{js,jsx}", 8 | "./src/**/*.{js,jsx}", 9 | "*.{js,jsx,mdx}", 10 | "*.{js,ts,jsx,tsx,mdx}", 11 | ], 12 | prefix: "", 13 | theme: { 14 | container: { 15 | center: true, 16 | padding: "2rem", 17 | screens: { 18 | "2xl": "1400px", 19 | }, 20 | }, 21 | extend: { 22 | colors: { 23 | border: "hsl(var(--border))", 24 | input: "hsl(var(--input))", 25 | ring: "hsl(var(--ring))", 26 | background: "hsl(var(--background))", 27 | foreground: "hsl(var(--foreground))", 28 | primary: { 29 | DEFAULT: "hsl(var(--primary))", 30 | foreground: "hsl(var(--primary-foreground))", 31 | }, 32 | secondary: { 33 | DEFAULT: "hsl(var(--secondary))", 34 | foreground: "hsl(var(--secondary-foreground))", 35 | }, 36 | destructive: { 37 | DEFAULT: "hsl(var(--destructive))", 38 | foreground: "hsl(var(--destructive-foreground))", 39 | }, 40 | muted: { 41 | DEFAULT: "hsl(var(--muted))", 42 | foreground: "hsl(var(--muted-foreground))", 43 | }, 44 | accent: { 45 | DEFAULT: "hsl(var(--accent))", 46 | foreground: "hsl(var(--accent-foreground))", 47 | }, 48 | popover: { 49 | DEFAULT: "hsl(var(--popover))", 50 | foreground: "hsl(var(--popover-foreground))", 51 | }, 52 | card: { 53 | DEFAULT: "hsl(var(--card))", 54 | foreground: "hsl(var(--card-foreground))", 55 | }, 56 | green: { 57 | 50: "#f0faf5", 58 | 100: "#d1f0e0", 59 | 200: "#a3e0c5", 60 | 400: "#4aba81", 61 | 500: "#2ca366", 62 | 600: "#1e8a52", 63 | 700: "#1a7847", 64 | 800: "#166239", 65 | }, 66 | }, 67 | borderRadius: { 68 | lg: "var(--radius)", 69 | md: "calc(var(--radius) - 2px)", 70 | sm: "calc(var(--radius) - 4px)", 71 | }, 72 | keyframes: { 73 | "accordion-down": { 74 | from: { height: "0" }, 75 | to: { height: "var(--radix-accordion-content-height)" }, 76 | }, 77 | "accordion-up": { 78 | from: { height: "var(--radix-accordion-content-height)" }, 79 | to: { height: "0" }, 80 | }, 81 | }, 82 | animation: { 83 | "accordion-down": "accordion-down 0.2s ease-out", 84 | "accordion-up": "accordion-up 0.2s ease-out", 85 | }, 86 | }, 87 | }, 88 | plugins: [require("tailwindcss-animate")], 89 | } 90 | 91 | -------------------------------------------------------------------------------- /src/app/components/AboutUs.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const AboutUs = () => { 4 | return ( 5 |
6 | {/* Main container */} 7 |
8 | {/* Heading */} 9 |

10 | About Us 11 |

12 | 13 | {/* Description text */} 14 |

15 | Our plant disease diagnosis platform combines advanced artificial intelligence with botanical expertise to 16 | provide accurate and timely plant health assessments. We're dedicated to helping gardeners, farmers, and 17 | plant enthusiasts maintain healthy plants and sustainable growing practices. 18 |

19 | 20 | {/* Features grid */} 21 |
22 | {/* AI-Powered Analysis */} 23 |
24 |
25 | 26 | 27 | 28 |
29 |

AI-Powered Analysis

30 |

31 | Our machine learning algorithms are trained on millions of plant disease images to provide accurate 32 | diagnoses within seconds. 33 |

34 |
35 | 36 | {/* Research & Innovation */} 37 |
38 |
39 | 40 | 41 | 42 |
43 |

Research & Innovation

44 |

45 | We continuously collaborate with agricultural research institutions and stay at the forefront of 46 | plant pathology advancements to provide cutting-edge solutions. 47 |

48 |
49 | 50 | {/* Sustainable Solutions */} 51 |
52 |
53 | 54 | 55 | 56 |
57 |

Sustainable Solutions

58 |

59 | We prioritize user friendly solutions and integrated pest management techniques in our 60 | recommendations. 61 |

62 |
63 |
64 |
65 |
66 | ) 67 | } 68 | 69 | export default AboutUs -------------------------------------------------------------------------------- /src/components/ui/select.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as SelectPrimitive from "@radix-ui/react-select" 5 | import { Check, ChevronDown } from "lucide-react" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const Select = SelectPrimitive.Root 10 | 11 | const SelectGroup = SelectPrimitive.Group 12 | 13 | const SelectValue = SelectPrimitive.Value 14 | 15 | const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => ( 16 | 23 | {children} 24 | 25 | 26 | 27 | 28 | )) 29 | SelectTrigger.displayName = SelectPrimitive.Trigger.displayName 30 | 31 | const SelectContent = React.forwardRef(({ className, children, position = "popper", ...props }, ref) => ( 32 | 33 | 43 | 49 | {children} 50 | 51 | 52 | 53 | )) 54 | SelectContent.displayName = SelectPrimitive.Content.displayName 55 | 56 | const SelectLabel = React.forwardRef(({ className, ...props }, ref) => ( 57 | 61 | )) 62 | SelectLabel.displayName = SelectPrimitive.Label.displayName 63 | 64 | const SelectItem = React.forwardRef(({ className, children, ...props }, ref) => ( 65 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | {children} 79 | 80 | )) 81 | SelectItem.displayName = SelectPrimitive.Item.displayName 82 | 83 | const SelectSeparator = React.forwardRef(({ className, ...props }, ref) => ( 84 | 88 | )) 89 | SelectSeparator.displayName = SelectPrimitive.Separator.displayName 90 | 91 | export { 92 | Select, 93 | SelectGroup, 94 | SelectValue, 95 | SelectTrigger, 96 | SelectContent, 97 | SelectLabel, 98 | SelectItem, 99 | SelectSeparator, 100 | } -------------------------------------------------------------------------------- /src/app/components/HowItWorks.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const HowItWorks = () => { 4 | return ( 5 |
6 |

How It Works

7 | 8 |
9 | {/* Step 1 */} 10 |
11 |
12 | 13 | 14 | 15 |
16 |

1. Upload Image

17 |

Take a clear photo of your plant showing the affected areas and upload it to our system.

18 |
19 | 20 | {/* Step 2 */} 21 |
22 |
23 | 24 | 25 | 26 | 27 |
28 |

2. Provide Location

29 |

Enter your location to help us provide region-specific recommendations for treatment.

30 |
31 | 32 | {/* Step 3 - New Language Selection Step */} 33 |
34 |
35 | 36 | 37 | 38 |
39 |

3. Select Language

40 |

Choose your preferred language to receive the analysis and recommendations in your local language.

41 |
42 | 43 | {/* Step 4 */} 44 |
45 |
46 | 47 | 48 | 49 |
50 |

4. Get Analysis

51 |

Receive detailed insights about the disease, its causes, prevention methods, and treatment options.

52 |
53 |
54 |
55 | ) 56 | } 57 | 58 | export default HowItWorks -------------------------------------------------------------------------------- /src/components/ui/sheet.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as SheetPrimitive from "@radix-ui/react-dialog" 5 | import { XIcon } from "lucide-react" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | function Sheet({ 10 | ...props 11 | }) { 12 | return ; 13 | } 14 | 15 | function SheetTrigger({ 16 | ...props 17 | }) { 18 | return ; 19 | } 20 | 21 | function SheetClose({ 22 | ...props 23 | }) { 24 | return ; 25 | } 26 | 27 | function SheetPortal({ 28 | ...props 29 | }) { 30 | return ; 31 | } 32 | 33 | function SheetOverlay({ 34 | className, 35 | ...props 36 | }) { 37 | return ( 38 | 45 | ); 46 | } 47 | 48 | function SheetContent({ 49 | className, 50 | children, 51 | side = "right", 52 | ...props 53 | }) { 54 | return ( 55 | 56 | 57 | 72 | {children} 73 | 75 | 76 | Close 77 | 78 | 79 | 80 | ); 81 | } 82 | 83 | function SheetHeader({ 84 | className, 85 | ...props 86 | }) { 87 | return ( 88 |
92 | ); 93 | } 94 | 95 | function SheetFooter({ 96 | className, 97 | ...props 98 | }) { 99 | return ( 100 |
104 | ); 105 | } 106 | 107 | function SheetTitle({ 108 | className, 109 | ...props 110 | }) { 111 | return ( 112 | 116 | ); 117 | } 118 | 119 | function SheetDescription({ 120 | className, 121 | ...props 122 | }) { 123 | return ( 124 | 128 | ); 129 | } 130 | 131 | export { 132 | Sheet, 133 | SheetTrigger, 134 | SheetClose, 135 | SheetContent, 136 | SheetHeader, 137 | SheetFooter, 138 | SheetTitle, 139 | SheetDescription, 140 | } 141 | -------------------------------------------------------------------------------- /server/app.py: -------------------------------------------------------------------------------- 1 | # from flask import Flask, request, render_template 2 | # import numpy as np 3 | # from tensorflow.keras.models import load_model 4 | # from PIL import Image 5 | # import json 6 | # import os 7 | 8 | # app = Flask(__name__) 9 | 10 | # # Load the trained model 11 | # model = load_model(r'C:\Users\HP\Desktop\project02\model\model.h5') 12 | # # Load class indices from JSON file 13 | # with open('class_indices.json', 'r') as f: 14 | # class_indices = json.load(f) 15 | 16 | # # Reverse the dictionary for index-to-class mapping (ensure keys are integers) 17 | # class_indices = {int(k): v for k, v in class_indices.items()} 18 | 19 | # # Function to Load and Preprocess Image 20 | # def load_and_preprocess_image(image_path, target_size=(256, 256)): 21 | # img = Image.open(image_path) 22 | # img = img.resize(target_size) 23 | # img_array = np.array(img) / 255.0 24 | # img_array = np.expand_dims(img_array, axis=0) # Add batch dimension 25 | # return img_array 26 | 27 | # # Home Route 28 | # @app.route("/", methods=['GET', 'POST']) 29 | # def home(): 30 | # if request.method == 'POST': 31 | # file = request.files['file'] 32 | # if file: 33 | # # Save the uploaded file 34 | # image_path = os.path.join('static', file.filename) 35 | # file.save(image_path) 36 | 37 | # # Prediction 38 | # img_array = load_and_preprocess_image(image_path) 39 | # prediction = model.predict(img_array) 40 | 41 | # # Handle unknown classes safely 42 | # predicted_index = np.argmax(prediction) 43 | # predicted_class = class_indices.get(predicted_index, "Unknown Class") 44 | 45 | # # Confidence Score 46 | # confidence_score = np.max(prediction) * 100 47 | 48 | # return render_template('result.html', 49 | # image_path=image_path, 50 | # prediction=predicted_class, 51 | # confidence=round(confidence_score, 2)) 52 | # return render_template('index.html') 53 | 54 | # # Run the app 55 | # if __name__ == "__main__": 56 | # app.run(debug=True) 57 | 58 | from flask import Flask, request, jsonify 59 | import numpy as np 60 | from tensorflow.keras.models import load_model 61 | from PIL import Image 62 | import json 63 | import os 64 | 65 | app = Flask(__name__) 66 | 67 | # Load the trained model 68 | model = load_model(r'C:\Users\HP\Desktop\project02\model\model.h5') 69 | 70 | # Load class indices from JSON file 71 | with open('class_indices.json', 'r') as f: 72 | class_indices = json.load(f) 73 | 74 | # Reverse the dictionary for index-to-class mapping (ensure keys are integers) 75 | class_indices = {int(k): v for k, v in class_indices.items()} 76 | 77 | # Function to Load and Preprocess Image 78 | def load_and_preprocess_image(image_path, target_size=(256, 256)): 79 | img = Image.open(image_path) 80 | img = img.resize(target_size) 81 | img_array = np.array(img) / 255.0 82 | img_array = np.expand_dims(img_array, axis=0) # Add batch dimension 83 | return img_array 84 | 85 | # Prediction Route 86 | @app.route("/predict", methods=['POST']) 87 | def predict(): 88 | if 'file' not in request.files: 89 | return jsonify({"error": "No file uploaded."}), 400 90 | 91 | file = request.files['file'] 92 | if file: 93 | # Save the uploaded file 94 | image_path = os.path.join('static', file.filename) 95 | file.save(image_path) 96 | 97 | # Prediction 98 | img_array = load_and_preprocess_image(image_path) 99 | prediction = model.predict(img_array) 100 | 101 | # Handle unknown classes safely 102 | predicted_index = int(np.argmax(prediction)) # Ensure integer type 103 | predicted_class = class_indices.get(predicted_index, "Unknown Class") 104 | 105 | # Confidence Score 106 | confidence_score = float(np.max(prediction) * 100) # Ensure float type 107 | 108 | return jsonify({ 109 | "image_path": image_path, 110 | "prediction": predicted_class, 111 | "confidence": round(confidence_score, 2) 112 | }) 113 | 114 | return jsonify({"error": "Invalid file."}), 400 115 | 116 | # Run the app 117 | if __name__ == "__main__": 118 | app.run(debug=True) 119 | -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | 3 | @plugin "tailwindcss-animate"; 4 | 5 | @custom-variant dark (&:is(.dark *)); 6 | 7 | @theme inline { 8 | --color-background: var(--background); 9 | --color-foreground: var(--foreground); 10 | --font-sans: var(--font-geist-sans); 11 | --font-mono: var(--font-geist-mono); 12 | --color-sidebar-ring: var(--sidebar-ring); 13 | --color-sidebar-border: var(--sidebar-border); 14 | --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); 15 | --color-sidebar-accent: var(--sidebar-accent); 16 | --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); 17 | --color-sidebar-primary: var(--sidebar-primary); 18 | --color-sidebar-foreground: var(--sidebar-foreground); 19 | --color-sidebar: var(--sidebar); 20 | --color-chart-5: var(--chart-5); 21 | --color-chart-4: var(--chart-4); 22 | --color-chart-3: var(--chart-3); 23 | --color-chart-2: var(--chart-2); 24 | --color-chart-1: var(--chart-1); 25 | --color-ring: var(--ring); 26 | --color-input: var(--input); 27 | --color-border: var(--border); 28 | --color-destructive: var(--destructive); 29 | --color-accent-foreground: var(--accent-foreground); 30 | --color-accent: var(--accent); 31 | --color-muted-foreground: var(--muted-foreground); 32 | --color-muted: var(--muted); 33 | --color-secondary-foreground: var(--secondary-foreground); 34 | --color-secondary: var(--secondary); 35 | --color-primary-foreground: var(--primary-foreground); 36 | --color-primary: var(--primary); 37 | --color-popover-foreground: var(--popover-foreground); 38 | --color-popover: var(--popover); 39 | --color-card-foreground: var(--card-foreground); 40 | --color-card: var(--card); 41 | --radius-sm: calc(var(--radius) - 4px); 42 | --radius-md: calc(var(--radius) - 2px); 43 | --radius-lg: var(--radius); 44 | --radius-xl: calc(var(--radius) + 4px); 45 | } 46 | 47 | :root { 48 | --radius: 0.625rem; 49 | --background: oklch(1 0 0); 50 | --foreground: oklch(0.145 0 0); 51 | --card: oklch(1 0 0); 52 | --card-foreground: oklch(0.145 0 0); 53 | --popover: oklch(1 0 0); 54 | --popover-foreground: oklch(0.145 0 0); 55 | --primary: oklch(0.205 0 0); 56 | --primary-foreground: oklch(0.985 0 0); 57 | --secondary: oklch(0.97 0 0); 58 | --secondary-foreground: oklch(0.205 0 0); 59 | --muted: oklch(0.97 0 0); 60 | --muted-foreground: oklch(0.556 0 0); 61 | --accent: oklch(0.97 0 0); 62 | --accent-foreground: oklch(0.205 0 0); 63 | --destructive: oklch(0.577 0.245 27.325); 64 | --border: oklch(0.922 0 0); 65 | --input: oklch(0.922 0 0); 66 | --ring: oklch(0.708 0 0); 67 | --chart-1: oklch(0.646 0.222 41.116); 68 | --chart-2: oklch(0.6 0.118 184.704); 69 | --chart-3: oklch(0.398 0.07 227.392); 70 | --chart-4: oklch(0.828 0.189 84.429); 71 | --chart-5: oklch(0.769 0.188 70.08); 72 | --sidebar: oklch(0.985 0 0); 73 | --sidebar-foreground: oklch(0.145 0 0); 74 | --sidebar-primary: oklch(0.205 0 0); 75 | --sidebar-primary-foreground: oklch(0.985 0 0); 76 | --sidebar-accent: oklch(0.97 0 0); 77 | --sidebar-accent-foreground: oklch(0.205 0 0); 78 | --sidebar-border: oklch(0.922 0 0); 79 | --sidebar-ring: oklch(0.708 0 0); 80 | } 81 | 82 | .dark { 83 | --background: oklch(0.145 0 0); 84 | --foreground: oklch(0.985 0 0); 85 | --card: oklch(0.205 0 0); 86 | --card-foreground: oklch(0.985 0 0); 87 | --popover: oklch(0.205 0 0); 88 | --popover-foreground: oklch(0.985 0 0); 89 | --primary: oklch(0.922 0 0); 90 | --primary-foreground: oklch(0.205 0 0); 91 | --secondary: oklch(0.269 0 0); 92 | --secondary-foreground: oklch(0.985 0 0); 93 | --muted: oklch(0.269 0 0); 94 | --muted-foreground: oklch(0.708 0 0); 95 | --accent: oklch(0.269 0 0); 96 | --accent-foreground: oklch(0.985 0 0); 97 | --destructive: oklch(0.704 0.191 22.216); 98 | --border: oklch(1 0 0 / 10%); 99 | --input: oklch(1 0 0 / 15%); 100 | --ring: oklch(0.556 0 0); 101 | --chart-1: oklch(0.488 0.243 264.376); 102 | --chart-2: oklch(0.696 0.17 162.48); 103 | --chart-3: oklch(0.769 0.188 70.08); 104 | --chart-4: oklch(0.627 0.265 303.9); 105 | --chart-5: oklch(0.645 0.246 16.439); 106 | --sidebar: oklch(0.205 0 0); 107 | --sidebar-foreground: oklch(0.985 0 0); 108 | --sidebar-primary: oklch(0.488 0.243 264.376); 109 | --sidebar-primary-foreground: oklch(0.985 0 0); 110 | --sidebar-accent: oklch(0.269 0 0); 111 | --sidebar-accent-foreground: oklch(0.985 0 0); 112 | --sidebar-border: oklch(1 0 0 / 10%); 113 | --sidebar-ring: oklch(0.556 0 0); 114 | } 115 | 116 | @layer base { 117 | * { 118 | @apply border-border outline-ring/50; 119 | } 120 | body { 121 | @apply bg-background text-foreground; 122 | } 123 | } 124 | 125 | /* Custom scrollbar for the accordion */ 126 | .custom-scrollbar::-webkit-scrollbar { 127 | width: 8px; 128 | } 129 | 130 | .custom-scrollbar::-webkit-scrollbar-track { 131 | background: #f0fdf4; /* light green background */ 132 | border-radius: 10px; 133 | } 134 | 135 | .custom-scrollbar::-webkit-scrollbar-thumb { 136 | background-color: #4ade80; /* green thumb */ 137 | border-radius: 10px; 138 | border: 2px solid #f0fdf4; 139 | } 140 | 141 | /* Optional: for Firefox */ 142 | .custom-scrollbar { 143 | scrollbar-width: thin; 144 | scrollbar-color: #4ade80 #f0fdf4; 145 | } 146 | 147 | -------------------------------------------------------------------------------- /src/app/components/Prediction.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { Card, CardContent } from "@/components/ui/card"; 3 | import { Button } from "@/components/ui/button"; 4 | import { 5 | Accordion, 6 | AccordionContent, 7 | AccordionItem, 8 | AccordionTrigger, 9 | } from "@/components/ui/accordion"; 10 | import { Badge } from "@/components/ui/badge"; 11 | import { Printer, Share2, Download } from "lucide-react"; 12 | import { 13 | Select, 14 | SelectContent, 15 | SelectItem, 16 | SelectTrigger, 17 | SelectValue, 18 | } from "@/components/ui/select"; 19 | import { useState, useEffect } from "react"; 20 | 21 | export default function Prediction({ userData, file, onLanguageChange }) { 22 | const [selectedLanguage, setSelectedLanguage] = useState("en"); 23 | 24 | useEffect(() => { 25 | // When language changes, trigger a new analysis 26 | if (userData && Object.keys(userData).length > 0) { 27 | onLanguageChange(selectedLanguage); 28 | } 29 | }, [selectedLanguage]); 30 | 31 | const handleLanguageChange = (value) => { 32 | setSelectedLanguage(value); 33 | }; 34 | 35 | // Sample data - in a real app, this would come from an API or props 36 | const result = { 37 | diseaseName: userData.diseaseName || "", 38 | location: userData.location || "", 39 | uploadDate: new Date().toLocaleDateString(), 40 | severity: "Severe", 41 | type: "Fungal", 42 | imageUrl: userData.diseaseName 43 | ? URL.createObjectURL(file) 44 | : "/placeholder.svg", 45 | cause: 46 | userData.cause || "", 47 | prevention: 48 | userData.prevention || "", 49 | treatment: 50 | userData.treatment || "", 51 | }; 52 | 53 | return ( 54 |
55 | 56 | 57 |
58 |

59 | Analysis Results 60 |

61 | 75 |
76 | 77 | {/* Disease info section */} 78 |
79 |
80 | Plant with disease 85 |
86 | 87 |
88 |

{result.diseaseName}

89 |

Location: {result.location}

90 |

91 | Uploaded: {result.uploadDate} 92 |

93 | 94 | {/*
95 | 99 | {result.severity} 100 | 101 | 105 | {result.type} 106 | 107 |
*/} 108 |
109 |
110 | 111 | {/* Accordion sections */} 112 | 117 | 121 | 122 | Cause 123 | 124 | 125 | {result.cause} 126 | 127 | 128 | 129 | 133 | 134 | Prevention 135 | 136 | 137 | {result.prevention} 138 | 139 | 140 | 141 | 145 | 146 | Treatment & Pesticides 147 | 148 | 149 | {result.treatment} 150 | 151 | 152 | 153 |
154 |
155 |
156 | ); 157 | } 158 | -------------------------------------------------------------------------------- /src/components/ui/navigation-menu.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu" 3 | import { cva } from "class-variance-authority" 4 | import { ChevronDownIcon } from "lucide-react" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | function NavigationMenu({ 9 | className, 10 | children, 11 | viewport = true, 12 | ...props 13 | }) { 14 | return ( 15 | 23 | {children} 24 | {viewport && } 25 | 26 | ); 27 | } 28 | 29 | function NavigationMenuList({ 30 | className, 31 | ...props 32 | }) { 33 | return ( 34 | 38 | ); 39 | } 40 | 41 | function NavigationMenuItem({ 42 | className, 43 | ...props 44 | }) { 45 | return ( 46 | 50 | ); 51 | } 52 | 53 | const navigationMenuTriggerStyle = cva( 54 | "group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 ring-ring/10 dark:ring-ring/20 dark:outline-ring/40 outline-ring/50 transition-[color,box-shadow] focus-visible:ring-4 focus-visible:outline-1" 55 | ) 56 | 57 | function NavigationMenuTrigger({ 58 | className, 59 | children, 60 | ...props 61 | }) { 62 | return ( 63 | 67 | {children}{" "} 68 | 72 | ); 73 | } 74 | 75 | function NavigationMenuContent({ 76 | className, 77 | ...props 78 | }) { 79 | return ( 80 | 88 | ); 89 | } 90 | 91 | function NavigationMenuViewport({ 92 | className, 93 | ...props 94 | }) { 95 | return ( 96 |
98 | 105 |
106 | ); 107 | } 108 | 109 | function NavigationMenuLink({ 110 | className, 111 | ...props 112 | }) { 113 | return ( 114 | 121 | ); 122 | } 123 | 124 | function NavigationMenuIndicator({ 125 | className, 126 | ...props 127 | }) { 128 | return ( 129 | 136 |
138 | 139 | ); 140 | } 141 | 142 | export { 143 | NavigationMenu, 144 | NavigationMenuList, 145 | NavigationMenuItem, 146 | NavigationMenuContent, 147 | NavigationMenuTrigger, 148 | NavigationMenuLink, 149 | NavigationMenuIndicator, 150 | NavigationMenuViewport, 151 | navigationMenuTriggerStyle, 152 | } 153 | -------------------------------------------------------------------------------- /src/app/components/Hero.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import React, { useState } from 'react' 4 | import UserInput from './UserInput' 5 | import Prediction from './Prediction' 6 | 7 | const Hero = () => { 8 | const [userData, setUserData] = useState({}); 9 | const [file, setFile] = useState(null); 10 | const [selectedLanguage, setSelectedLanguage] = useState("en"); 11 | const [placeLocation, setPlaceLocation] = useState(""); 12 | const [diseaseName, setDiseaseName] = useState(""); 13 | 14 | const handleLanguageChange = (language) => { 15 | setSelectedLanguage(language); 16 | // If we have existing data, trigger a new analysis with the new language 17 | if (userData && Object.keys(userData).length > 0) { 18 | // Reuse the existing data to trigger a new analysis 19 | const formData = new FormData(); 20 | formData.append("file", file); 21 | 22 | // Step 1: Plant Analysis (reuse existing prediction) 23 | fetch("http://127.0.0.1:5000/predict", { 24 | method: "POST", 25 | body: formData 26 | }) 27 | .then(response => response.json()) 28 | .then(data => { 29 | setDiseaseName(data.prediction); 30 | return fetch(`https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(placeLocation)}&format=json`); 31 | }) 32 | .then(response => response.json()) 33 | .then(locationData => { 34 | if (!locationData || locationData.length === 0) { 35 | throw new Error("Location not found"); 36 | } 37 | 38 | const { lat, lon } = locationData[0]; 39 | 40 | // Step 3: Fetch Weather Data 41 | const currentDate = new Date().toISOString().split('T')[0]; 42 | const pastDate = new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]; 43 | 44 | return fetch(`https://api.worldweatheronline.com/premium/v1/past-weather.ashx?key=d2af227ed68348f99de201856251603&q=${lat},${lon}&date=${pastDate}&enddate=${currentDate}&format=json`); 45 | }) 46 | .then(response => response.json()) 47 | .then(weatherData => { 48 | if (!weatherData?.data?.weather) { 49 | throw new Error("Weather data not found for the given coordinates."); 50 | } 51 | 52 | // Step 4: Calculate Average Values 53 | const avgData = weatherData.data.weather.reduce((acc, day) => { 54 | acc.tempMax += parseFloat(day.maxtempC); 55 | acc.tempMin += parseFloat(day.mintempC); 56 | acc.humidity += parseFloat(day.hourly.reduce((sum, hour) => sum + parseFloat(hour.humidity), 0) / day.hourly.length); 57 | acc.windSpeed += parseFloat(day.hourly.reduce((sum, hour) => sum + parseFloat(hour.windspeedKmph), 0) / day.hourly.length); 58 | return acc; 59 | }, { tempMax: 0, tempMin: 0, humidity: 0, windSpeed: 0 }); 60 | 61 | const totalDays = weatherData.data.weather.length; 62 | const averagedData = { 63 | avgTempMax: (avgData.tempMax / totalDays).toFixed(2), 64 | avgTempMin: (avgData.tempMin / totalDays).toFixed(2), 65 | avgHumidity: (avgData.humidity / totalDays).toFixed(2), 66 | avgWindSpeed: (avgData.windSpeed / totalDays).toFixed(2) 67 | }; 68 | 69 | // Step 5: Call Gemini API with new language 70 | return analyzePlantDisease( 71 | placeLocation, 72 | averagedData.avgHumidity, 73 | averagedData.avgTempMax, 74 | averagedData.avgTempMin, 75 | diseaseName, 76 | language 77 | ); 78 | }) 79 | .then(analysisResult => { 80 | setUserData(analysisResult); 81 | }) 82 | .catch(error => console.error("Error in the process:", error)); 83 | } 84 | }; 85 | 86 | const analyzePlantDisease = async (placeLocation, avgHumidity, avgTempMax, avgTempMin, diseaseName, language) => { 87 | const apiKey = "AIzaSyBWEhilw2TATGtVaBxVEDA5HlObyyJKtmQ"; 88 | const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`; 89 | 90 | const prompt = ` 91 | Analyze the given environmental data and plant disease information to provide insights on the disease's cause, prevention methods, and treatment options. 92 | Please provide the response in ${language} language. 93 | 94 | Input Details: 95 | - Location Name: ${placeLocation} 96 | - Average Humidity: ${avgHumidity}% 97 | - Average Maximum Temperature: ${avgTempMax}°C 98 | - Average Minimum Temperature: ${avgTempMin}°C 99 | - Plant Disease Name: ${diseaseName} 100 | 101 | **Output Format (in JSON, without markdown formatting):** 102 | { 103 | "diseaseName": "", 104 | "cause": "", 105 | "prevention": "", 106 | "treatment": "", 107 | "location": "" 108 | } 109 | 110 | Ensure the JSON is valid and does not include markdown code block markers like \`\`\`. 111 | `; 112 | 113 | const requestBody = { 114 | contents: [ 115 | { 116 | parts: [{ text: prompt }] 117 | } 118 | ] 119 | }; 120 | 121 | try { 122 | const response = await fetch(apiUrl, { 123 | method: "POST", 124 | headers: { 125 | "Content-Type": "application/json" 126 | }, 127 | body: JSON.stringify(requestBody) 128 | }); 129 | 130 | const data = await response.json(); 131 | const jsonString = data.candidates?.[0]?.content?.parts?.[0]?.text?.trim(); 132 | const cleanJsonString = jsonString 133 | .replace(/```json/g, '') 134 | .replace(/```/g, '') 135 | .trim(); 136 | 137 | return JSON.parse(cleanJsonString); 138 | } catch (error) { 139 | console.error("Error in fetching data:", error); 140 | return null; 141 | } 142 | }; 143 | 144 | return ( 145 |
146 |
147 |
148 | 157 |
158 |
159 | 164 |
165 |
166 |
167 | ) 168 | } 169 | 170 | export default Hero -------------------------------------------------------------------------------- /src/app/components/UserInput.jsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useEffect, useState } from "react" 4 | import { Upload, MapPin } from "lucide-react" 5 | import { Card, CardContent } from "@/components/ui/card" 6 | import { Button } from "@/components/ui/button" 7 | import { Input } from "@/components/ui/input" 8 | 9 | export default function UserInput({ setUserData, setFile, file, selectedLanguage, setPlaceLocation, setDiseaseName, placeLocation }) { 10 | 11 | const [preview, setPreview] = useState(null) 12 | 13 | const handleFileChange = (e) => { 14 | const selectedFile = e.target.files?.[0] || null 15 | setFile(selectedFile) 16 | 17 | if (selectedFile) { 18 | const reader = new FileReader() 19 | reader.onload = (e) => { 20 | setPreview(e.target?.result) 21 | } 22 | reader.readAsDataURL(selectedFile) 23 | } else { 24 | setPreview(null) 25 | } 26 | } 27 | 28 | const handleDrop = (e) => { 29 | e.preventDefault() 30 | const droppedFile = e.dataTransfer.files[0] 31 | setFile(droppedFile) 32 | 33 | if (droppedFile) { 34 | const reader = new FileReader() 35 | reader.onload = (e) => { 36 | setPreview(e.target?.result) 37 | } 38 | reader.readAsDataURL(droppedFile) 39 | } 40 | } 41 | 42 | const handleDragOver = (e) => { 43 | e.preventDefault() 44 | } 45 | 46 | const handleAnalyze = () => { 47 | const formData = new FormData(); 48 | formData.append("file", file); 49 | 50 | let predictedDisease = null; // Store the prediction value 51 | 52 | // Step 1: Plant Analysis 53 | fetch("http://127.0.0.1:5000/predict", { 54 | method: "POST", 55 | body: formData 56 | }) 57 | .then(response => response.json()) 58 | .then(data => { 59 | console.log("Plant Analysis Data:", data); 60 | predictedDisease = data.prediction; // Store the prediction 61 | setDiseaseName(predictedDisease); 62 | console.log("Detected Disease:", predictedDisease); 63 | 64 | // Step 2: Get Coordinates for the Location 65 | return fetch(`https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(placeLocation)}&format=json`); 66 | }) 67 | .then(response => response.json()) 68 | .then(locationData => { 69 | if (!locationData || locationData.length === 0) { 70 | throw new Error("Location not found"); 71 | } 72 | 73 | const { lat, lon } = locationData[0]; 74 | console.log(`Coordinates for ${placeLocation}:`, { lat, lon }); 75 | 76 | // Step 3: Fetch Weather Data (Using Coordinates) 77 | const currentDate = new Date().toISOString().split('T')[0]; 78 | const pastDate = new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]; 79 | 80 | return fetch(`https://api.worldweatheronline.com/premium/v1/past-weather.ashx?key=d2af227ed68348f99de201856251603&q=${lat},${lon}&date=${pastDate}&enddate=${currentDate}&format=json`); 81 | }) 82 | .then(response => response.json()) 83 | .then(weatherData => { 84 | if (!weatherData?.data?.weather) { 85 | throw new Error("Weather data not found for the given coordinates."); 86 | } 87 | 88 | console.log("Weather Data for the Past 10 Days:", weatherData); 89 | 90 | // Step 4: Calculate Average Values for the Past 10 Days 91 | const avgData = weatherData.data.weather.reduce((acc, day) => { 92 | acc.tempMax += parseFloat(day.maxtempC); 93 | acc.tempMin += parseFloat(day.mintempC); 94 | acc.humidity += parseFloat(day.hourly.reduce((sum, hour) => sum + parseFloat(hour.humidity), 0) / day.hourly.length); 95 | acc.windSpeed += parseFloat(day.hourly.reduce((sum, hour) => sum + parseFloat(hour.windspeedKmph), 0) / day.hourly.length); 96 | return acc; 97 | }, { tempMax: 0, tempMin: 0, humidity: 0, windSpeed: 0 }); 98 | 99 | const totalDays = weatherData.data.weather.length; 100 | const averagedData = { 101 | avgTempMax: (avgData.tempMax / totalDays).toFixed(2), 102 | avgTempMin: (avgData.tempMin / totalDays).toFixed(2), 103 | avgHumidity: (avgData.humidity / totalDays).toFixed(2), 104 | avgWindSpeed: (avgData.windSpeed / totalDays).toFixed(2) 105 | }; 106 | 107 | console.log("Averaged Weather Data:", averagedData); 108 | // Step 5: Call Gemini API for Plant Disease Analysis 109 | return analyzePlantDisease( 110 | placeLocation, 111 | averagedData.avgHumidity, 112 | averagedData.avgTempMax, 113 | averagedData.avgTempMin, 114 | predictedDisease, // Use the stored prediction value 115 | selectedLanguage 116 | ); 117 | }) 118 | .then(analysisResult => { 119 | console.log("Gemini Analysis Result:", analysisResult); 120 | setUserData(analysisResult); 121 | }) 122 | .catch(error => console.error("Error in the process:", error)); 123 | }; 124 | 125 | const analyzePlantDisease = async (placeLocation, avgHumidity, avgTempMax, avgTempMin, diseaseName, language) => { 126 | console.log("Analyzing plant disease for location:", placeLocation); 127 | const apiKey = "AIzaSyBWEhilw2TATGtVaBxVEDA5HlObyyJKtmQ"; 128 | const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`; 129 | 130 | const prompt = ` 131 | Analyze the given environmental data and plant disease information to provide insights on the disease's cause, prevention methods, and treatment options. 132 | Please provide the response in ${language} language. 133 | 134 | Input Details: 135 | - Location Name: ${placeLocation} 136 | - Average Humidity: ${avgHumidity}% 137 | - Average Maximum Temperature: ${avgTempMax}°C 138 | - Average Minimum Temperature: ${avgTempMin}°C 139 | - Plant Disease Name: ${diseaseName} 140 | 141 | **Output Format (in JSON, without markdown formatting):** 142 | { 143 | "diseaseName": "", 144 | "cause": "", 145 | "prevention": "", 146 | "treatment": "", 147 | "location": "" 148 | } 149 | 150 | Ensure the JSON is valid and does not include markdown code block markers like \`\`\`. 151 | `; 152 | 153 | const requestBody = { 154 | contents: [ 155 | { 156 | parts: [{ text: prompt }] 157 | } 158 | ] 159 | }; 160 | 161 | try { 162 | const response = await fetch(apiUrl, { 163 | method: "POST", 164 | headers: { 165 | "Content-Type": "application/json" 166 | }, 167 | body: JSON.stringify(requestBody) 168 | }); 169 | 170 | const data = await response.json(); 171 | 172 | // Extract text response and clean unnecessary characters 173 | const jsonString = data.candidates?.[0]?.content?.parts?.[0]?.text?.trim(); 174 | 175 | // Remove potential backticks and code block markers 176 | const cleanJsonString = jsonString 177 | .replace(/```json/g, '') // Removes ```json 178 | .replace(/```/g, '') // Removes remaining ``` 179 | .trim(); 180 | 181 | const parsedData = JSON.parse(cleanJsonString); 182 | 183 | console.log("Parsed JSON Data:", parsedData); 184 | return parsedData; 185 | } catch (error) { 186 | console.error("Error in fetching data:", error); 187 | } 188 | }; 189 | 190 | return ( 191 |
192 |
193 |
194 |

Plant Disease Diagnosis

195 |

196 | Get instant diagnosis for your plant's health issues. Upload an image of your diseased plant, provide your 197 | location, and receive professional recommendations for treatment. 198 |

199 |
200 | 201 | 202 | 203 |
204 |
205 |

Upload Plant Image

206 |
document.getElementById("file-upload")?.click()} 212 | > 213 | {preview ? ( 214 |
215 | Plant preview 220 |

Click to change image

221 |
222 | ) : ( 223 |
224 |
225 | 226 |
227 |

Drag and drop your image here or click to browse

228 |
229 | )} 230 | 231 |
232 |
233 | 234 |
235 |

Your Location

236 |
237 | 238 | setPlaceLocation(e.target.value)} 243 | /> 244 |
245 |
246 | 247 | 254 |
255 |
256 |
257 |
258 |
259 | ) 260 | } --------------------------------------------------------------------------------