diff --git a/README.md b/README.md index 1ef914b1..dc82fe74 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,7 @@ Note: Backend and frontend must be running simultaneously for proper functionali ## 🌟 Core Features - 🌾 Crop Recommendation +- 🌿 Fertilizer Recommendation - 📉 Yield Prediction - 🔬 Disease Detection - � **AI Chatbot** - Platform guidance & agriculture support @@ -226,6 +227,7 @@ AGRITECH/ │ ├── 📁 css/ # Stylesheets │ └── 📁 js/ # Client-side scripts ├── 📁 Crop Recommendation/ # 🌾 Crop recommendation module +├── 📁 Fertiliser Recommendation System/ # 🌿 Fertilizer recommendation ML module ├── 📁 Disease Prediction/ # 🔬 Disease detection module ├── 📁 Crop Yield Prediction/ # 📊 Yield forecasting module ├── 📁 Community/ # 💬 community/forum backend diff --git a/disease.js b/disease.js index 309a2012..8d37f97c 100644 --- a/disease.js +++ b/disease.js @@ -255,6 +255,8 @@ const loading = document.getElementById("loading"); const resultsDiv = document.getElementById("results"); let selectedFile = null; +let uploadInProgress = false; +let fileSelectionToken = 0; // File upload handling uploadArea.addEventListener("click", () => fileInput.click()); @@ -308,7 +310,7 @@ fileInput.addEventListener("change", (e) => { // Analysis function analyzeBtn.addEventListener("click", async () => { - if (!selectedFile) return; + if (uploadInProgress || !selectedFile) return; loading.style.display = "block"; resultsDiv.innerHTML = ""; @@ -470,40 +472,59 @@ function validateImage(file) { return true; } +function readPreviewDataUrl(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.onload = (event) => resolve(event.target.result); + reader.onerror = () => reject(new Error("Error loading image preview.")); + reader.readAsDataURL(file); + }); +} + // Enhanced file handling with validation -function handleFileSelect(file) { +async function handleFileSelect(file) { + const currentSelectionToken = ++fileSelectionToken; + try { validateImage(file); - selectedFile = file; + uploadInProgress = true; + selectedFile = null; + analyzeBtn.disabled = true; previewContainer.innerHTML = '
'; - const reader = new FileReader(); - reader.onload = (e) => { - previewContainer.innerHTML = `Plant preview`; - analyzeBtn.disabled = false; - resultsDiv.innerHTML = ""; - document.getElementById("downloadPdfBtn").style.display = "none"; + const previewDataUrl = await readPreviewDataUrl(file); - document.getElementById("modelStatus").innerHTML = - "🔍 Image loaded - Ready for analysis"; - document.getElementById("modelStatus").className = - "status-indicator status-warning"; - }; + if (currentSelectionToken !== fileSelectionToken) { + return; + } + + selectedFile = file; + previewContainer.innerHTML = `Plant preview`; + resultsDiv.innerHTML = ""; + document.getElementById("downloadPdfBtn").style.display = "none"; - reader.onerror = () => { - previewContainer.innerHTML = - '
❌ Error loading image
'; - selectedFile = null; - }; + document.getElementById("modelStatus").innerHTML = + "🔍 Image loaded - Ready for analysis"; + document.getElementById("modelStatus").className = + "status-indicator status-warning"; - reader.readAsDataURL(file); + analyzeBtn.disabled = false; } catch (error) { + if (currentSelectionToken !== fileSelectionToken) { + return; + } + alert(error.message); previewContainer.innerHTML = '
📷 Upload an image to get started
'; selectedFile = null; analyzeBtn.disabled = true; + } finally { + if (currentSelectionToken === fileSelectionToken) { + uploadInProgress = false; + } } } diff --git a/domain/README.md b/domain/README.md index 3f06e4d9..e5545645 100644 --- a/domain/README.md +++ b/domain/README.md @@ -9,6 +9,8 @@ This directory defines shared domain contracts used across AgriTech. ## Current Schemas - Crop +- FertilizerRecommendationInput +- FertilizerRecommendation - GrowthStage - SoilData - PredictionResult diff --git a/domain/fertilizer.schema.js b/domain/fertilizer.schema.js new file mode 100644 index 00000000..577660f7 --- /dev/null +++ b/domain/fertilizer.schema.js @@ -0,0 +1,79 @@ +/** + * Fertilizer recommendation schema + */ + +export const FertilizerRecommendationInputSchema = { + $id: "FertilizerRecommendationInput", + type: "object", + required: [ + "temperature", + "humidity", + "moisture", + "soilType", + "cropType", + "nitrogen", + "phosphorous", + "potassium" + ], + additionalProperties: false, + properties: { + temperature: { + type: "number", + description: "Ambient temperature in degrees Celsius" + }, + humidity: { + type: "number", + description: "Relative humidity percentage" + }, + moisture: { + type: "number", + description: "Soil moisture percentage" + }, + soilType: { + type: "string", + description: "Categorical soil type" + }, + cropType: { + type: "string", + description: "Categorical crop type" + }, + nitrogen: { + type: "number", + description: "Nitrogen content" + }, + phosphorous: { + type: "number", + description: "Phosphorous content" + }, + potassium: { + type: "number", + description: "Potassium content" + } + } +}; + +export const FertilizerRecommendationSchema = { + $id: "FertilizerRecommendation", + type: "object", + required: ["fertilizerName", "confidence", "inputs"], + additionalProperties: false, + properties: { + fertilizerName: { + type: "string", + description: "Recommended fertilizer label" + }, + confidence: { + type: "number", + description: "Prediction confidence score (0-1)" + }, + inputs: FertilizerRecommendationInputSchema, + modelVersion: { + type: "string", + description: "Version of the fertilizer recommendation model" + }, + createdAt: { + type: "string", + description: "ISO timestamp when the recommendation was generated" + } + } +}; \ No newline at end of file diff --git a/domain/index.js b/domain/index.js index 12eae6bd..e3a696ae 100644 --- a/domain/index.js +++ b/domain/index.js @@ -1,10 +1,13 @@ import { CropSchema } from "./crop.schema.js"; +import { FertilizerRecommendationInputSchema, FertilizerRecommendationSchema } from "./fertilizer.schema.js"; import { GrowthStageSchema } from "./growthStage.schema.js"; import { PredictionResultSchema } from "./prediction.schema.js"; import { SoilDataSchema } from "./soil.schema.js"; export { CropSchema, + FertilizerRecommendationInputSchema, + FertilizerRecommendationSchema, GrowthStageSchema, PredictionResultSchema, SoilDataSchema @@ -12,6 +15,8 @@ export { export const DomainSchemas = { Crop: CropSchema, + FertilizerRecommendationInput: FertilizerRecommendationInputSchema, + FertilizerRecommendation: FertilizerRecommendationSchema, GrowthStage: GrowthStageSchema, PredictionResult: PredictionResultSchema, SoilData: SoilDataSchema diff --git a/domain/validate.js b/domain/validate.js index 2e9e394e..110e47d6 100644 --- a/domain/validate.js +++ b/domain/validate.js @@ -1,5 +1,7 @@ import { CropSchema, + FertilizerRecommendationInputSchema, + FertilizerRecommendationSchema, GrowthStageSchema, PredictionResultSchema, SoilDataSchema @@ -7,6 +9,8 @@ import { const schemaMap = { Crop: CropSchema, + FertilizerRecommendationInput: FertilizerRecommendationInputSchema, + FertilizerRecommendation: FertilizerRecommendationSchema, GrowthStage: GrowthStageSchema, PredictionResult: PredictionResultSchema, SoilData: SoilDataSchema