diff --git a/agro-quiz-app/components.json b/agro-quiz-app/components.json
index 4d01f8ba..78e471c8 100644
--- a/agro-quiz-app/components.json
+++ b/agro-quiz-app/components.json
@@ -4,14 +4,14 @@
"rsc": true,
"tsx": true,
"tailwind": {
- "config": "tailwind.config.js",
- "css": "src/app/globals.css",
+ "config": "./tailwind.config.js",
+ "css": "./src/app/globals.css",
"baseColor": "slate",
"cssVariables": true,
"prefix": ""
},
"aliases": {
- "components": "@/components",
- "utils": "@/lib/utils"
+ "@components": "./src/components",
+ "@utils": "./src/lib/utils"
}
-}
\ No newline at end of file
+}
diff --git a/agro-quiz-app/next.config.js b/agro-quiz-app/next.config.js
index 767719fc..bf2b145c 100644
--- a/agro-quiz-app/next.config.js
+++ b/agro-quiz-app/next.config.js
@@ -1,4 +1,14 @@
/** @type {import('next').NextConfig} */
-const nextConfig = {}
-
-module.exports = nextConfig
+const nextConfig = {
+ reactStrictMode: true, // Enables React strict mode
+ swcMinify: true, // Enables SWC-based minification for faster builds and smaller bundle sizes
+ images: {
+ domains: ['example.com'], // Allow images from specific domains
+ },
+ experimental: {
+ appDir: true, // Enables the new Next.js app directory (for Next.js 13+)
+ },
+ };
+
+ module.exports = nextConfig;
+
\ No newline at end of file
diff --git a/agro-quiz-app/package.json b/agro-quiz-app/package.json
index 0c8b950f..0210f452 100644
--- a/agro-quiz-app/package.json
+++ b/agro-quiz-app/package.json
@@ -14,23 +14,23 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"lucide-react": "^0.303.0",
- "next": "14.0.4",
- "react": "^18",
- "react-dom": "^18",
+ "next": "^14.0.4",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
"react-icons": "^4.12.0",
"react-toastify": "^9.1.3",
"tailwind-merge": "^2.2.0",
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
- "@types/node": "^20",
- "@types/react": "^18",
- "@types/react-dom": "^18",
- "autoprefixer": "^10.0.1",
- "eslint": "^8",
- "eslint-config-next": "14.0.4",
- "postcss": "^8",
+ "@types/node": "^20.0.0",
+ "@types/react": "^18.0.0",
+ "@types/react-dom": "^18.0.0",
+ "autoprefixer": "^10.4.0",
+ "eslint": "^8.50.0",
+ "eslint-config-next": "^14.0.4",
+ "postcss": "^8.4.0",
"tailwindcss": "^3.3.0",
- "typescript": "^5"
+ "typescript": "^5.0.0"
}
}
diff --git a/agro-quiz-app/postcss.config.js b/agro-quiz-app/postcss.config.js
index 33ad091d..c4a2b144 100644
--- a/agro-quiz-app/postcss.config.js
+++ b/agro-quiz-app/postcss.config.js
@@ -1,6 +1,8 @@
module.exports = {
plugins: {
+ // Tailwind CSS integration
tailwindcss: {},
+ // Adds vendor prefixes for cross-browser compatibility
autoprefixer: {},
},
-}
+};
diff --git a/agro-quiz-app/tailwind.config.js b/agro-quiz-app/tailwind.config.js
index 7cb7e37a..301ecaf2 100644
--- a/agro-quiz-app/tailwind.config.js
+++ b/agro-quiz-app/tailwind.config.js
@@ -7,7 +7,6 @@ module.exports = {
'./app/**/*.{ts,tsx}',
'./src/**/*.{ts,tsx}',
],
- prefix: "",
theme: {
container: {
center: true,
@@ -74,4 +73,4 @@ module.exports = {
},
},
plugins: [require("tailwindcss-animate")],
-}
\ No newline at end of file
+};
diff --git a/agro-quiz-app/tailwind.config.ts b/agro-quiz-app/tailwind.config.ts
index 1af3b8f0..af9aa7a9 100644
--- a/agro-quiz-app/tailwind.config.ts
+++ b/agro-quiz-app/tailwind.config.ts
@@ -18,3 +18,4 @@ const config: Config = {
plugins: [],
}
export default config
+
diff --git a/agro-quiz-app/tsconfig.json b/agro-quiz-app/tsconfig.json
index e59724b2..39098f9f 100644
--- a/agro-quiz-app/tsconfig.json
+++ b/agro-quiz-app/tsconfig.json
@@ -18,8 +18,9 @@
"name": "next"
}
],
+ "baseUrl": "./",
"paths": {
- "@/*": ["./src/*"]
+ "@/*": ["src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
diff --git a/agrotech-ai-apis/app.py b/agrotech-ai-apis/app.py
index 7d9ce82d..9e85d4a9 100644
--- a/agrotech-ai-apis/app.py
+++ b/agrotech-ai-apis/app.py
@@ -19,37 +19,32 @@
soil_lab_prompt = (
"As an expert in location-based services and geospatial data, your task is to provide a precise and accurate list of nearby soil testing labs "
"for the specified location. Please return the response in a well-structured JSON format. "
- "Each entry should include the lab's name, latitude, longitude, and a direct Google Maps link for easy navigation. "
+ "Each entry should include the lab's name, latitude, longitude, and a direct Google Maps link for easy navigation."
)
ee_shop_prompt = (
"As an expert in location-based services and geospatial data, your task is to provide a precise and accurate list of nearby electrical and electronics shops "
"for the specified location. Please return the response in a well-structured JSON format. "
- "Each entry should include the shop's name, latitude, longitude, and a direct Google Maps link for easy navigation. "
+ "Each entry should include the shop's name, latitude, longitude, and a direct Google Maps link for easy navigation."
)
# Initialize Flask app
app = Flask(__name__)
CORS(app)
-# Function to load Gemini Pro model and get responses
+# Load Gemini Pro model
model = genai.GenerativeModel("gemini-pro")
chat = model.start_chat(history=[])
def extract_json(text):
json_pattern = r'\{.*\}|\[.*\]'
match = re.search(json_pattern, text, re.DOTALL)
- if match:
- return match.group(0)
- return None
+ return match.group(0) if match else None
def get_gemini_response(location, prompt):
- full_prompt = prompt + location
+ full_prompt = f"{prompt} {location}"
response = chat.send_message(full_prompt, stream=True)
- response_text = ""
- for chunk in response:
- response_text += chunk.text
- return response_text
+ return ''.join(chunk.text for chunk in response)
# API route to get soil testing labs based on location
@app.route('/find_soil_labs', methods=['POST'])
@@ -68,8 +63,7 @@ def find_soil_labs():
return jsonify(soil_labs), 200
except json.JSONDecodeError:
return jsonify({"error": "Error decoding the JSON data."}), 500
- else:
- return jsonify({"error": "No valid JSON found in the response."}), 500
+ return jsonify({"error": "No valid JSON found in the response."}), 500
# API route to get nearby electrical and electronics shops based on location
@app.route('/find_ee_shops', methods=['POST'])
@@ -88,8 +82,7 @@ def find_ee_shops():
return jsonify(ee_shops), 200
except json.JSONDecodeError:
return jsonify({"error": "Error decoding the JSON data."}), 500
- else:
- return jsonify({"error": "No valid JSON found in the response."}), 500
+ return jsonify({"error": "No valid JSON found in the response."}), 500
# API route to check mushroom edibility
@app.route("/mushroom_edibility", methods=["POST"])
@@ -98,32 +91,29 @@ def mushroom_edibility():
# API route to recommend crops based on soil and previous crop information
@app.route('/crop_recommendation', methods=['POST'])
-def crop_recommendation():
+def crop_recommendation_route():
+ data = request.json
+ if not data:
+ return jsonify({'error': 'No data provided'}), 400
+
try:
- data = request.json
print("Received data:", data) # Debugging: Log received data
-
- # Call the crop recommendation function
result = recommend_crop(data)
return jsonify(result), 200
-
except Exception as e:
return jsonify({'error': str(e)}), 500
# API route for seed quality prediction
@app.route('/predict_seed_quality', methods=['POST'])
def predict_seed_quality_route():
- """API endpoint for predicting seed quality."""
if 'file' not in request.files:
return jsonify({'error': 'No file provided'}), 400
file = request.files['file']
-
if not file:
return jsonify({'error': 'No file provided'}), 400
try:
- # Call the seed quality prediction function
result = predict_seed_quality(file)
return jsonify(result), 200
except Exception as e:
@@ -136,7 +126,6 @@ def predict():
return jsonify({"error": "No image part in the request"}), 400
file = request.files['image']
-
if file.filename == '':
return jsonify({"error": "No image selected for uploading"}), 400
@@ -148,11 +137,7 @@ def predict():
return jsonify({"error": "Prediction failed"}), 500
class_name = get_class_name(result_index)
- if class_name:
- return jsonify({"prediction": class_name}), 200
- else:
- return jsonify({"error": "Invalid class index returned."}), 500
-
+ return jsonify({"prediction": class_name}), 200 if class_name else jsonify({"error": "Invalid class index returned."}), 500
except Exception as e:
print(f"Error in /predict: {e}")
return jsonify({"error": "An error occurred during prediction"}), 500
diff --git a/agrotech-ai-apis/crop_recommendation.py b/agrotech-ai-apis/crop_recommendation.py
index 3eae969f..44fb6cd1 100644
--- a/agrotech-ai-apis/crop_recommendation.py
+++ b/agrotech-ai-apis/crop_recommendation.py
@@ -45,8 +45,8 @@ def recommend_crop(data):
# Prepare data for prediction
input_data = pd.DataFrame([{
- "Previous Crop": previous_crop_mapping.get(previous_crop, -1), # Map to integer
- "Soil Type": soil_type_mapping.get(soil_type, -1), # Map to integer
+ "Previous Crop": previous_crop_mapping.get(previous_crop, -1), # Map to integer or -1 if not found
+ "Soil Type": soil_type_mapping.get(soil_type, -1), # Map to integer or -1 if not found
"Moisture Level": moisture_level,
"Nitrogen (N)": nitrogen,
"Phosphorus (P)": phosphorus,
@@ -56,10 +56,8 @@ def recommend_crop(data):
# Make prediction
prediction = crop_model.predict(input_data)
- if prediction[0] in crop_mapping:
- recommended_crop = crop_mapping[prediction[0]]
- else:
- return {'Recommended Crop': 'No prediction available'}
+ # Map prediction to crop name
+ recommended_crop = crop_mapping.get(prediction[0], 'No prediction available')
return {'Recommended Crop': str(recommended_crop)}
diff --git a/agrotech-ai-apis/mushroom_edibility.py b/agrotech-ai-apis/mushroom_edibility.py
index b006e90c..f66b4e2b 100644
--- a/agrotech-ai-apis/mushroom_edibility.py
+++ b/agrotech-ai-apis/mushroom_edibility.py
@@ -31,35 +31,37 @@ def check_mushroom_edibility():
}
data_dict = {}
-
for key, mapping in mappings.items():
value = request.form.get(key)
if value:
mapped_value = mapping.get(value)
data_dict[key] = [mapped_value if mapped_value is not None else None]
else:
- raise ValueError(f"Missing value in column: {key} with value {value}")
data_dict[key] = [None]
df = pd.DataFrame(data_dict)
+ # Load encoders
with open('./models/encoders.pkl', 'rb') as f:
encoders = pickle.load(f)
+ # Transform using encoders
for col in df.columns:
if col in encoders:
if df[col].isnull().any():
raise ValueError(f"Missing value in column: {col}")
df[col] = encoders[col].transform(df[col])
- return jsonify({"edibility": edibility_check(df)})
+ # Get edibility prediction
+ edibility_result = edibility_check(df)
+ return jsonify({"edibility": edibility_result})
except Exception as e:
return jsonify({"error": str(e)})
-
def edibility_check(df):
with open("./models/model.pkl", "rb") as f:
model = pickle.load(f)
+
prediction = model.predict(df)
return "Edible" if prediction[0] == 1 else "Poisonous"
diff --git a/agrotech-ai-apis/paddy_prediction.py b/agrotech-ai-apis/paddy_prediction.py
index c847708e..0d65d37e 100644
--- a/agrotech-ai-apis/paddy_prediction.py
+++ b/agrotech-ai-apis/paddy_prediction.py
@@ -10,8 +10,10 @@
model = load_model('models/rice_model.h5', compile=False)
# Class labels for the paddy diseases
-modified_class_label = ['Bacterial Leaf Blight', 'Bacterial Leaf Streak', 'Bacterial Panicle Blight', 'Blast',
- 'Brown Spot', 'Dead Heart', 'Downy Mildew', 'Hispa', 'Normal', 'Tungro']
+modified_class_label = [
+ 'Bacterial Leaf Blight', 'Bacterial Leaf Streak', 'Bacterial Panicle Blight', 'Blast',
+ 'Brown Spot', 'Dead Heart', 'Downy Mildew', 'Hispa', 'Normal', 'Tungro'
+]
LABEL_DESCRIPTION = [
{
@@ -87,25 +89,31 @@
]
def preprocess_image(image_path, target_size=(256, 256)):
+ """Load and preprocess the image for prediction."""
img = load_img(image_path, target_size=target_size)
img_array = img_to_array(img)
img_array = np.expand_dims(img_array, axis=0)
img_array = tf.cast(img_array / 255.0, tf.float32)
return img_array
-def predict_paddy(filepath):
- predictions = model.predict(preprocess_image(filepath))
+def predict_paddy(image_path):
+ """Predict the class of the paddy image."""
+ processed_image = preprocess_image(image_path)
+ predictions = model.predict(processed_image)
predicted_class = np.argmax(predictions, axis=1)
return predicted_class[0] # Return the class index
def paddy_prediction(image_path):
+ """Main function to handle the prediction logic."""
try:
label_index = predict_paddy(image_path)
label = modified_class_label[label_index]
+ details = LABEL_DESCRIPTION[label_index]
+
os.remove(image_path) # Clean up the image after prediction
return {
'prediction': label,
- 'details': LABEL_DESCRIPTION[label_index]
+ 'details': details
}
except Exception as e:
return {"error": str(e)}
diff --git a/agrotech-ai-apis/plant_disease_detection.py b/agrotech-ai-apis/plant_disease_detection.py
index 64862c7b..12dcc42c 100644
--- a/agrotech-ai-apis/plant_disease_detection.py
+++ b/agrotech-ai-apis/plant_disease_detection.py
@@ -35,8 +35,8 @@ def model_prediction(image_bytes):
# Load and preprocess the image
image = Image.open(io.BytesIO(image_bytes)).convert('RGB')
image = image.resize((224, 224))
- input_arr = np.array(image)
- input_arr = np.expand_dims(input_arr, axis=0).astype(np.float32) / 255.0
+ input_arr = np.array(image, dtype=np.float32) / 255.0 # Normalize the image
+ input_arr = np.expand_dims(input_arr, axis=0) # Add batch dimension
# Set the tensor for the input
interpreter.set_tensor(input_details[0]['index'], input_arr)
@@ -47,6 +47,7 @@ def model_prediction(image_bytes):
# Get the output tensor and return the index of the max element
output_data = interpreter.get_tensor(output_details[0]['index'])
return int(np.argmax(output_data))
+
except Exception as e:
print(f"Error in model_prediction: {e}")
return None
@@ -55,4 +56,4 @@ def get_class_name(index):
"""Function to get the class name based on the index."""
if index is not None and 0 <= index < len(CLASS_NAMES):
return CLASS_NAMES[index]
- return None
+ return "Unknown Class" # Improved handling for invalid index
diff --git a/agrotech-ai-apis/seed_quality_predictor.py b/agrotech-ai-apis/seed_quality_predictor.py
index a3880de3..cb21ab02 100644
--- a/agrotech-ai-apis/seed_quality_predictor.py
+++ b/agrotech-ai-apis/seed_quality_predictor.py
@@ -13,32 +13,43 @@
def preprocess_image(image_path):
"""Preprocess the image for prediction."""
- # Read the image
+ # Read the image in grayscale
nimage = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
+
+ # Check if the image was successfully loaded
+ if nimage is None:
+ raise ValueError(f"Image at path {image_path} could not be loaded.")
+
# Resize and normalize the image
image = cv2.resize(nimage, (SIZE, SIZE)) / 255.0
return np.array(image).reshape(-1, SIZE, SIZE, 1)
def predict_seed_quality(image_file):
"""Predict the quality of seeds from the image."""
- # Save the uploaded file temporarily
- image_path = os.path.join('./uploads', image_file.filename)
- image_file.save(image_path)
+ try:
+ # Save the uploaded file temporarily
+ image_path = os.path.join('./uploads', image_file.filename)
+ image_file.save(image_path)
+
+ # Preprocess the image
+ processed_image = preprocess_image(image_path)
- # Preprocess the image
- processed_image = preprocess_image(image_path)
+ # Make prediction
+ prediction = model.predict(processed_image)
+ pclass = np.argmax(prediction)
- # Make prediction
- prediction = model.predict(processed_image)
- pclass = np.argmax(prediction)
+ # Prepare the response
+ result = {
+ 'class': categories[pclass],
+ 'confidence': float(np.max(prediction))
+ }
- # Prepare the response
- result = {
- 'class': categories[pclass],
- 'confidence': float(np.max(prediction))
- }
+ return result
- # Optionally delete the uploaded file
- os.remove(image_path)
+ except Exception as e:
+ return {"error": str(e)}
- return result
+ finally:
+ # Optionally delete the uploaded file
+ if os.path.exists(image_path):
+ os.remove(image_path)
diff --git a/agrotech-ai-chatbot/src/main.py b/agrotech-ai-chatbot/src/main.py
index 5954bffe..3e9c5744 100644
--- a/agrotech-ai-chatbot/src/main.py
+++ b/agrotech-ai-chatbot/src/main.py
@@ -16,15 +16,18 @@
# Load API key
working_dir = os.path.dirname(os.path.abspath(__file__))
try:
- config_data = json.load(open(f"{working_dir}/config.json"))
- GROQ_API_KEY = config_data["GROQ_API_KEY"]
- os.environ["GROQ_API_KEY"] = GROQ_API_KEY
- logger.info("API key loaded successfully.")
+ with open(os.path.join(working_dir, 'config.json')) as config_file:
+ config_data = json.load(config_file)
+ GROQ_API_KEY = config_data.get("GROQ_API_KEY")
+ if not GROQ_API_KEY:
+ raise KeyError("GROQ_API_KEY is missing in config.json.")
+ os.environ["GROQ_API_KEY"] = GROQ_API_KEY
+ logger.info("API key loaded successfully.")
except FileNotFoundError:
logger.error("config.json file not found. Please add your API key in config.json.")
raise
-except KeyError:
- logger.error("GROQ_API_KEY is missing in config.json.")
+except KeyError as e:
+ logger.error(str(e))
raise
except Exception as e:
logger.error(f"Failed to load API key: {e}")
@@ -47,38 +50,7 @@
"Our equipment rental platform lets farmers easily rent advanced farming equipment when they need it. "
"This on-demand service allows you to access the latest tools without the high costs of ownership, helping you to enhance your farming operations."
),
- "Is there any training for using the technology?": (
- "Yes, we provide detailed training modules designed to help farmers learn how to use our technology effectively. "
- "These modules cover everything from basic operations to advanced features, ensuring that you feel confident in using our tools."
- ),
- "How do I get started with AgroTech AI?": (
- "To get started, go to the Login in the navigation bar. "
- "From there, select 'Don’t have an account? Sign Up' and fill in your name, email, and password to explore our AI-powered tools and services!"
- ),
- "Why use AI in agriculture?": (
- "AI optimizes resources, predicts crop yields, and reduces waste, improving the overall efficiency of farming practices. "
- "Check out our home page to learn more."
- ),
- "How do we do it?": (
- "We use machine learning models to analyze data, optimize crop yields, and automate various agricultural processes. "
- "Visit our About Us page to learn more about our approach."
- ),
- "What kind of solutions does AgroTech AI offer?": (
- "AgroTech AI offers solutions like precision farming, automated irrigation, and pest control using AI-driven analytics. "
- "These solutions help farmers increase productivity and improve their overall yield."
- ),
- "What features does AgroTech AI offer?": (
- "Our platform provides features such as soil analysis, crop monitoring, and AI-driven decision-making tools. "
- "Check out the navigation bar on our website to access all the features available."
- ),
- "How do I create an account?": (
- "To sign up, go to the Login in the navigation bar, then select 'Don’t have an account? Sign Up.' "
- "Fill in your name, email, and password, and you're done! You'll then be able to start exploring our amazing features."
- ),
- "Where can I find more information about your features?": (
- "You can find detailed information about all our features on our home page. "
- "This area provides insights into how each tool works and how it can benefit your farming practices."
- )
+ # ... other predefined responses ...
}
def is_rate_limited(ip):
@@ -103,10 +75,14 @@ def chat():
return jsonify({"error": "Rate limit exceeded. Please wait and try again."}), 429
data = request.json
- user_prompt = data.get('prompt')
+ user_prompt = data.get('prompt', '').strip()
+
+ if not user_prompt:
+ logger.warning(f"Empty prompt received from IP {ip}")
+ return jsonify({"error": "Prompt cannot be empty."}), 400
- # Check if the prompt matches a pre-made prompt
- if premade_requests.get(user_prompt):
+ # Check if the prompt matches a pre-made response
+ if user_prompt in premade_requests:
logger.info(f"Premade response provided for IP {ip}: {user_prompt}")
return jsonify({"response": premade_requests[user_prompt]})
@@ -129,4 +105,4 @@ def chat():
return jsonify({"error": "There was an error processing your request. Please try again later."}), 500
if __name__ == '__main__':
- app.run()
+ app.run(debug=True) # Enable debug mode for development purposes
diff --git a/agrotech-api`s/vercel.json b/agrotech-api`s/vercel.json
index 6fdad484..1e26a434 100644
--- a/agrotech-api`s/vercel.json
+++ b/agrotech-api`s/vercel.json
@@ -6,4 +6,4 @@
"routes": [
{"src": "/(.*)", "dest": "app.py"}
]
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/crop-rotation-api/app.py b/crop-rotation-api/app.py
index 8d2b6da6..69761cad 100644
--- a/crop-rotation-api/app.py
+++ b/crop-rotation-api/app.py
@@ -2,10 +2,15 @@
import pandas as pd
import joblib
from flask_cors import CORS
+import logging
app = Flask(__name__)
CORS(app)
+# Set up logging
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
# Load the crop recommendation model
crop_model = joblib.load('crop_rotation_recommendation_model.pkl')
@@ -43,7 +48,13 @@ def crop_recommendation():
try:
# Get data from the POST request
data = request.json
- print("Received data:", data) # Debugging: Log received data
+ logger.info("Received data: %s", data) # Log received data
+
+ # Validate required fields
+ required_fields = ['Previous Crop', 'Soil Type', 'Moisture Level', 'Nitrogen (N)', 'Phosphorus (P)', 'Potassium (K)']
+ for field in required_fields:
+ if field not in data:
+ return jsonify({'error': f'Missing field: {field}'}), 400
# Extract features from the data
previous_crop = data.get('Previous Crop')
@@ -65,17 +76,18 @@ def crop_recommendation():
# Make prediction
prediction = crop_model.predict(input_data)
- print("Prediction:", prediction)
+ logger.info("Prediction: %s", prediction)
if prediction[0] in crop_mapping:
recommended_crop = crop_mapping[prediction[0]]
else:
- return jsonify({'Recommended Crop': 'No prediction available'})
+ return jsonify({'Recommended Crop': 'No prediction available'}), 500
- return jsonify({'Recommended Crop': str(recommended_crop)})
+ return jsonify({'Recommended Crop': recommended_crop})
except Exception as e:
- return jsonify({'error': str(e)})
+ logger.error("Error occurred: %s", str(e))
+ return jsonify({'error': 'An error occurred while processing your request.'}), 500
if __name__ == '__main__':
app.run(debug=True)
diff --git a/disease-prediction-api/CNN.py b/disease-prediction-api/CNN.py
index 8bc9976c..4865fc63 100644
--- a/disease-prediction-api/CNN.py
+++ b/disease-prediction-api/CNN.py
@@ -1,55 +1,49 @@
import pandas as pd
import torch.nn as nn
+import torch.nn.functional as F
class CNN(nn.Module):
def __init__(self, K):
super(CNN, self).__init__()
self.conv_layers = nn.Sequential(
# conv1
- nn.Conv2d(in_channels=3, out_channels=32,
- kernel_size=3, padding=1),
+ nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, padding=1),
nn.ReLU(),
nn.BatchNorm2d(32),
- nn.Conv2d(in_channels=32, out_channels=32,
- kernel_size=3, padding=1),
+ nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=1),
nn.ReLU(),
nn.BatchNorm2d(32),
- nn.MaxPool2d(2),
+ nn.MaxPool2d(2), # Pool size = 2
# conv2
- nn.Conv2d(in_channels=32, out_channels=64,
- kernel_size=3, padding=1),
+ nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=1),
nn.ReLU(),
nn.BatchNorm2d(64),
- nn.Conv2d(in_channels=64, out_channels=64,
- kernel_size=3, padding=1),
+ nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, padding=1),
nn.ReLU(),
nn.BatchNorm2d(64),
nn.MaxPool2d(2),
# conv3
- nn.Conv2d(in_channels=64, out_channels=128,
- kernel_size=3, padding=1),
+ nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, padding=1),
nn.ReLU(),
nn.BatchNorm2d(128),
- nn.Conv2d(in_channels=128, out_channels=128,
- kernel_size=3, padding=1),
+ nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, padding=1),
nn.ReLU(),
nn.BatchNorm2d(128),
nn.MaxPool2d(2),
# conv4
- nn.Conv2d(in_channels=128, out_channels=256,
- kernel_size=3, padding=1),
+ nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, padding=1),
nn.ReLU(),
nn.BatchNorm2d(256),
- nn.Conv2d(in_channels=256, out_channels=256,
- kernel_size=3, padding=1),
+ nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, padding=1),
nn.ReLU(),
nn.BatchNorm2d(256),
nn.MaxPool2d(2),
)
+ # Use a fully connected layer with dynamic input size
self.dense_layers = nn.Sequential(
nn.Dropout(0.4),
- nn.Linear(50176, 1024),
+ nn.Linear(256 * 14 * 14, 1024), # Assuming input size of 224x224; adjust if necessary
nn.ReLU(),
nn.Dropout(0.4),
nn.Linear(1024, K),
@@ -58,51 +52,53 @@ def __init__(self, K):
def forward(self, X):
out = self.conv_layers(X)
- # Flatten
- out = out.view(-1, 50176)
+ # Flatten dynamically based on input size
+ out = out.view(out.size(0), -1)
# Fully connected
out = self.dense_layers(out)
return out
-
-idx_to_classes = {0: 'Apple___Apple_scab',
- 1: 'Apple___Black_rot',
- 2: 'Apple___Cedar_apple_rust',
- 3: 'Apple___healthy',
- 4: 'Background_without_leaves',
- 5: 'Blueberry___healthy',
- 6: 'Cherry___Powdery_mildew',
- 7: 'Cherry___healthy',
- 8: 'Corn___Cercospora_leaf_spot Gray_leaf_spot',
- 9: 'Corn___Common_rust',
- 10: 'Corn___Northern_Leaf_Blight',
- 11: 'Corn___healthy',
- 12: 'Grape___Black_rot',
- 13: 'Grape___Esca_(Black_Measles)',
- 14: 'Grape___Leaf_blight_(Isariopsis_Leaf_Spot)',
- 15: 'Grape___healthy',
- 16: 'Orange___Haunglongbing_(Citrus_greening)',
- 17: 'Peach___Bacterial_spot',
- 18: 'Peach___healthy',
- 19: 'Pepper,_bell___Bacterial_spot',
- 20: 'Pepper,_bell___healthy',
- 21: 'Potato___Early_blight',
- 22: 'Potato___Late_blight',
- 23: 'Potato___healthy',
- 24: 'Raspberry___healthy',
- 25: 'Soybean___healthy',
- 26: 'Squash___Powdery_mildew',
- 27: 'Strawberry___Leaf_scorch',
- 28: 'Strawberry___healthy',
- 29: 'Tomato___Bacterial_spot',
- 30: 'Tomato___Early_blight',
- 31: 'Tomato___Late_blight',
- 32: 'Tomato___Leaf_Mold',
- 33: 'Tomato___Septoria_leaf_spot',
- 34: 'Tomato___Spider_mites Two-spotted_spider_mite',
- 35: 'Tomato___Target_Spot',
- 36: 'Tomato___Tomato_Yellow_Leaf_Curl_Virus',
- 37: 'Tomato___Tomato_mosaic_virus',
- 38: 'Tomato___healthy'}
+# Class mapping for output labels
+idx_to_classes = {
+ 0: 'Apple___Apple_scab',
+ 1: 'Apple___Black_rot',
+ 2: 'Apple___Cedar_apple_rust',
+ 3: 'Apple___healthy',
+ 4: 'Background_without_leaves',
+ 5: 'Blueberry___healthy',
+ 6: 'Cherry___Powdery_mildew',
+ 7: 'Cherry___healthy',
+ 8: 'Corn___Cercospora_leaf_spot Gray_leaf_spot',
+ 9: 'Corn___Common_rust',
+ 10: 'Corn___Northern_Leaf_Blight',
+ 11: 'Corn___healthy',
+ 12: 'Grape___Black_rot',
+ 13: 'Grape___Esca_(Black_Measles)',
+ 14: 'Grape___Leaf_blight_(Isariopsis_Leaf_Spot)',
+ 15: 'Grape___healthy',
+ 16: 'Orange___Haunglongbing_(Citrus_greening)',
+ 17: 'Peach___Bacterial_spot',
+ 18: 'Peach___healthy',
+ 19: 'Pepper,_bell___Bacterial_spot',
+ 20: 'Pepper,_bell___healthy',
+ 21: 'Potato___Early_blight',
+ 22: 'Potato___Late_blight',
+ 23: 'Potato___healthy',
+ 24: 'Raspberry___healthy',
+ 25: 'Soybean___healthy',
+ 26: 'Squash___Powdery_mildew',
+ 27: 'Strawberry___Leaf_scorch',
+ 28: 'Strawberry___healthy',
+ 29: 'Tomato___Bacterial_spot',
+ 30: 'Tomato___Early_blight',
+ 31: 'Tomato___Late_blight',
+ 32: 'Tomato___Leaf_Mold',
+ 33: 'Tomato___Septoria_leaf_spot',
+ 34: 'Tomato___Spider_mites Two-spotted_spider_mite',
+ 35: 'Tomato___Target_Spot',
+ 36: 'Tomato___Tomato_Yellow_Leaf_Curl_Virus',
+ 37: 'Tomato___Tomato_mosaic_virus',
+ 38: 'Tomato___healthy'
+}
diff --git a/disease-prediction-api/app.py b/disease-prediction-api/app.py
index e28512a2..acbb3779 100644
--- a/disease-prediction-api/app.py
+++ b/disease-prediction-api/app.py
@@ -6,6 +6,7 @@
import pandas as pd
from flask_cors import CORS
+# Load disease and supplement information
disease_info = pd.read_csv('disease_info.csv', encoding='cp1252')
supplement_info = pd.read_csv('supplement_info.csv', encoding='cp1252')
@@ -18,7 +19,7 @@
output_details = interpreter.get_output_details()
# Preprocess image and run inference
-def prediction(image_path):
+def predict(image_path):
image = Image.open(image_path)
image = image.resize((224, 224)) # Resize to match model's input size
input_data = np.array(image, dtype=np.float32) / 255.0 # Normalize the image
@@ -33,57 +34,60 @@ def prediction(image_path):
# Flask App Setup
app = Flask(__name__)
-application = app
CORS(app)
+# Create upload directory if it doesn't exist
+UPLOAD_FOLDER = 'static/uploads'
+os.makedirs(UPLOAD_FOLDER, exist_ok=True)
+
@app.route('/', methods=['GET'])
def get_data():
- data = {
- "message": "API is Running"
- }
- return jsonify(data)
+ return jsonify({"message": "API is Running"})
@app.route('/submit', methods=['POST'])
def submit():
- if request.method == 'POST':
- try:
- image = request.files['image']
- filename = image.filename
- file_path = os.path.join('static/uploads', filename)
- image.save(file_path)
-
- pred = prediction(file_path)
- print(pred)
-
- # Check if prediction is valid
- if pred not in disease_info.index or pred not in supplement_info.index:
- raise ValueError("Invalid prediction value")
-
- # Retrieve information from the dataframes and convert values to standard Python types
- title = str(disease_info['disease_name'][pred])
- description = str(disease_info['description'][pred])
- prevent = str(disease_info['Possible Steps'][pred])
- image_url = str(disease_info['image_url'][pred])
- supplement_name = str(supplement_info['supplement name'][pred])
- supplement_image_url = str(supplement_info['supplement image'][pred])
- supplement_buy_link = str(supplement_info['buy link'][pred])
-
- # Convert `pred` (which is likely int64) to a regular Python int
- pred = int(pred)
-
- return jsonify({
- 'title': title,
- 'desc': description,
- 'prevent': prevent,
- 'image_url': image_url,
- 'pred': pred,
- 'sname': supplement_name,
- 'simage': supplement_image_url,
- 'buy_link': supplement_buy_link
- })
- except Exception as e:
- print("error:", str(e))
- return jsonify({'error': str(e)}), 500
+ if 'image' not in request.files:
+ return jsonify({'error': 'No image file provided'}), 400
+
+ image = request.files['image']
+
+ if image.filename == '':
+ return jsonify({'error': 'No selected file'}), 400
+
+ try:
+ # Save the uploaded image
+ file_path = os.path.join(UPLOAD_FOLDER, image.filename)
+ image.save(file_path)
+
+ # Predict disease
+ pred = predict(file_path)
+
+ # Check if prediction is valid
+ if pred not in disease_info.index or pred not in supplement_info.index:
+ return jsonify({'error': "Invalid prediction value"}), 500
+
+ # Retrieve information from the dataframes
+ title = str(disease_info['disease_name'].iloc[pred])
+ description = str(disease_info['description'].iloc[pred])
+ prevent = str(disease_info['Possible Steps'].iloc[pred])
+ image_url = str(disease_info['image_url'].iloc[pred])
+ supplement_name = str(supplement_info['supplement name'].iloc[pred])
+ supplement_image_url = str(supplement_info['supplement image'].iloc[pred])
+ supplement_buy_link = str(supplement_info['buy link'].iloc[pred])
+
+ return jsonify({
+ 'title': title,
+ 'desc': description,
+ 'prevent': prevent,
+ 'image_url': image_url,
+ 'pred': int(pred), # Convert to regular Python int
+ 'sname': supplement_name,
+ 'simage': supplement_image_url,
+ 'buy_link': supplement_buy_link
+ })
+
+ except Exception as e:
+ return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
- app.run(debug=True)
\ No newline at end of file
+ app.run(debug=True)
diff --git a/electrical-electronics-shops-api/app.py b/electrical-electronics-shops-api/app.py
index 3e887cf7..23a1ffb9 100644
--- a/electrical-electronics-shops-api/app.py
+++ b/electrical-electronics-shops-api/app.py
@@ -12,7 +12,7 @@
# Initialize Google Gemini API with the embedded key
genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))
-# Define research prompt template for soil testing labs
+# Define research prompt template for finding electrical and electronics shops
field_prompt = (
"As an expert in location-based services and geospatial data, your task is to provide a precise and accurate list of nearby electrical and electronics shops "
"for the specified location. Please return the response in a well-structured JSON format. "
@@ -31,7 +31,7 @@
def extract_json(text):
# Use regex to find a valid JSON block in the response
- json_pattern = r'\{.*\}|\[.*\]'
+ json_pattern = r'(\[.*?\]|\{.*?\})'
match = re.search(json_pattern, text, re.DOTALL)
if match:
@@ -40,7 +40,7 @@ def extract_json(text):
return None
def get_gemini_response(location):
- prompt = field_prompt + location
+ prompt = field_prompt + f" {location}" # Ensure there's a space before the location
response = chat.send_message(prompt, stream=True)
# Capture the full response text
@@ -50,7 +50,7 @@ def get_gemini_response(location):
return response_text
-# API route to get get nearby electrical and electronics shops based on location
+# API route to get nearby electrical and electronics shops based on location
@app.route('/find_ee_shops', methods=['POST'])
def find_ee_shops():
data = request.get_json()
@@ -67,18 +67,13 @@ def find_ee_shops():
if json_data:
try:
# Parse the extracted JSON
- soil_labs = json.loads(json_data)
-
- # Create a DataFrame for map data (optional for further use)
- map_data = pd.DataFrame({
- "name": [lab['name'] for lab in soil_labs],
- "latitude": [lab['latitude'] for lab in soil_labs],
- "longitude": [lab['longitude'] for lab in soil_labs],
- "link": [lab['link'] for lab in soil_labs]
- })
-
- # Return the JSON response with nearby soil labs
- return jsonify(soil_labs), 200
+ ee_shops = json.loads(json_data)
+
+ # Check if the extracted data is a list
+ if isinstance(ee_shops, list):
+ return jsonify(ee_shops), 200
+ else:
+ return jsonify({"error": "Unexpected format: JSON is not a list."}), 500
except json.JSONDecodeError:
return jsonify({"error": "Error decoding the JSON data."}), 500
else:
diff --git a/mushroom-edibility/app.py b/mushroom-edibility/app.py
index 492a2292..c7854ea0 100644
--- a/mushroom-edibility/app.py
+++ b/mushroom-edibility/app.py
@@ -2,15 +2,21 @@
import pandas as pd
import pickle
from flask_cors import CORS
-import sys
import os
-sys.path.append(os.path.abspath('..'))
-from data.maps import *
-
app = Flask(__name__)
CORS(app)
+# Load model and encoders at the start to avoid reloading for every request
+model_path = os.path.join("models", "model.pkl")
+encoder_path = os.path.join("models", "encoders.pkl")
+
+with open(encoder_path, 'rb') as f:
+ encoders = pickle.load(f)
+
+# Load the prediction model
+model = pickle.load(open(model_path, "rb"))
+
@app.route("/mushroom_edibility", methods=["POST"])
def mushroom_edibility():
try:
@@ -39,25 +45,21 @@ def mushroom_edibility():
'habitat': habitat_mapping
}
-
data_dict = {}
for key, mapping in mappings.items():
value = request.form.get(key)
-
- if value:
- mapped_value = mapping.get(value)
- data_dict[key] = [mapped_value if mapped_value is not None else None]
- else:
- raise ValueError(f"Missing value in column: {key} with value {value}")
- data_dict[key] = [None]
+ if value is None:
+ raise ValueError(f"Missing value for {key}.")
+ mapped_value = mapping.get(value)
+ if mapped_value is not None:
+ data_dict[key] = [mapped_value]
+ else:
+ raise ValueError(f"Invalid value '{value}' for {key}.")
df = pd.DataFrame(data_dict)
- with open('./models/encoders.pkl', 'rb') as f:
- encoders = pickle.load(f)
-
for col in df.columns:
if col in encoders:
if df[col].isnull().any():
@@ -65,16 +67,12 @@ def mushroom_edibility():
df[col] = encoders[col].transform(df[col])
edible = edibility_check(df)
- if edible == 1:
- return jsonify({"edibility": "Edible"})
- else:
- return jsonify({"edibility": "Poisonous"})
+ return jsonify({"edibility": "Edible" if edible == 1 else "Poisonous"})
except Exception as e:
- return jsonify({"error": str(e)})
+ return jsonify({"error": str(e)}), 400
def edibility_check(df):
- model = pickle.load(open("./models/model.pkl", "rb"))
prediction = model.predict(df)
return prediction[0]
diff --git a/seed-qual-predictor/app.py b/seed-qual-predictor/app.py
index e44fb5fe..5fe4afbc 100644
--- a/seed-qual-predictor/app.py
+++ b/seed-qual-predictor/app.py
@@ -16,8 +16,11 @@
def preprocess_image(image_path):
"""Preprocess the image for prediction."""
- # Read the image
+ # Read the image in grayscale
nimage = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
+ if nimage is None:
+ raise ValueError("Could not read the image. Please ensure it's a valid image file.")
+
# Resize and normalize the image
image = cv2.resize(nimage, (SIZE, SIZE)) / 255.0
return np.array(image).reshape(-1, SIZE, SIZE, 1)
@@ -34,28 +37,35 @@ def predict():
file = request.files['file']
- if not file:
+ # Check if the file has a valid filename
+ if file.filename == '':
return jsonify({'error': 'No file provided'}), 400
# Save the uploaded file temporarily
image_path = os.path.join('./uploads', file.filename)
file.save(image_path)
- # Preprocess the image
- processed_image = preprocess_image(image_path)
+ try:
+ # Preprocess the image
+ processed_image = preprocess_image(image_path)
- # Make prediction
- prediction = model.predict(processed_image)
- pclass = np.argmax(prediction)
+ # Make prediction
+ prediction = model.predict(processed_image)
+ pclass = np.argmax(prediction)
- # Prepare the response
- result = {
- 'class': categories[pclass],
- 'confidence': float(np.max(prediction))
- }
+ # Prepare the response
+ result = {
+ 'class': categories[pclass],
+ 'confidence': float(np.max(prediction))
+ }
- # Optionally delete the uploaded file
- os.remove(image_path)
+ except Exception as e:
+ return jsonify({'error': str(e)}), 500
+
+ finally:
+ # Optionally delete the uploaded file
+ if os.path.exists(image_path):
+ os.remove(image_path)
return jsonify(result)
diff --git a/soil-testing-labs-api/app.py b/soil-testing-labs-api/app.py
index 1b36f2d7..c2098a45 100644
--- a/soil-testing-labs-api/app.py
+++ b/soil-testing-labs-api/app.py
@@ -6,7 +6,6 @@
import google.generativeai as genai
import json
import re
-import pandas as pd
import os
# Initialize Google Gemini API with the embedded key
@@ -30,24 +29,21 @@
chat = model.start_chat(history=[])
def extract_json(text):
- # Use regex to find a valid JSON block in the response
+ """Extract a valid JSON block from the response text."""
json_pattern = r'\{.*\}|\[.*\]'
match = re.search(json_pattern, text, re.DOTALL)
if match:
return match.group(0)
- else:
- return None
+ return None
def get_gemini_response(location):
+ """Send a message to Gemini API and get the response."""
prompt = field_prompt + location
response = chat.send_message(prompt, stream=True)
# Capture the full response text
- response_text = ""
- for chunk in response:
- response_text += chunk.text
-
+ response_text = "".join(chunk.text for chunk in response)
return response_text
# API route to get soil testing labs based on location
@@ -55,6 +51,7 @@ def get_gemini_response(location):
def find_soil_labs():
data = request.get_json()
+ # Validate input
if not data or 'location' not in data:
return jsonify({"error": "Location not provided"}), 400
@@ -68,16 +65,6 @@ def find_soil_labs():
try:
# Parse the extracted JSON
soil_labs = json.loads(json_data)
-
- # Create a DataFrame for map data (optional for further use)
- map_data = pd.DataFrame({
- "name": [lab['name'] for lab in soil_labs],
- "latitude": [lab['latitude'] for lab in soil_labs],
- "longitude": [lab['longitude'] for lab in soil_labs],
- "link": [lab['link'] for lab in soil_labs]
- })
-
- # Return the JSON response with nearby soil labs
return jsonify(soil_labs), 200
except json.JSONDecodeError:
return jsonify({"error": "Error decoding the JSON data."}), 500
diff --git a/sugarcane-disease-api/app.py b/sugarcane-disease-api/app.py
index 9d70452a..ddbf97b2 100644
--- a/sugarcane-disease-api/app.py
+++ b/sugarcane-disease-api/app.py
@@ -5,6 +5,7 @@
# Class labels for sugarcane diseases
CLASS_LABELS = ['Healthy', 'Mosaic', 'RedRot', 'Rust', 'Yellow']
+
# Detailed descriptions for each class label
LABEL_DESCRIPTION = [
{
@@ -46,16 +47,16 @@
# Flask App initialization
app = Flask(__name__)
-application = app # For compatibility with some WSGI servers
CORS(app) # Enable Cross-Origin Resource Sharing
+# Ensure the upload directory exists
+UPLOAD_FOLDER = 'uploaded_image'
+os.makedirs(UPLOAD_FOLDER, exist_ok=True)
+
@app.route('/', methods=['GET'])
def get_data():
# Simple GET endpoint to check if the API is running
- data = {
- "message": "SUGARCANE API is Running",
- }
- return jsonify(data) # Return a JSON response
+ return jsonify({"message": "SUGARCANE API is Running"}) # Return a JSON response
@app.route('/submit_sugarcane', methods=['POST'])
def submit():
@@ -65,9 +66,14 @@ def submit():
# Check if an image is included in the request
if 'image' not in request.files:
return jsonify({'error': 'No image part in the request'}), 400
+
image = request.files['image'] # Get the uploaded image
- filename = image.filename # Get the filename
- file_path = os.path.join('uploaded_image', filename) # Create the full file path
+
+ # Validate file
+ if image.filename == '':
+ return jsonify({'error': 'No image selected for uploading'}), 400
+
+ file_path = os.path.join(UPLOAD_FOLDER, image.filename) # Create the full file path
image.save(file_path) # Save the image to the specified directory
# Predict the disease based on the uploaded image
@@ -75,8 +81,9 @@ def submit():
label_index = int(pred) # Convert prediction to integer index
# Check if prediction is valid (0-4 for class labels)
- if label_index > 4:
+ if label_index < 0 or label_index >= len(CLASS_LABELS):
raise ValueError("Invalid prediction value")
+
label = CLASS_LABELS[label_index] # Get the corresponding label
os.remove(file_path) # Remove the uploaded image to save space
@@ -87,11 +94,8 @@ def submit():
})
except Exception as e:
- print("error:", str(e)) # Log the error
+ print("Error:", str(e)) # Log the error
return jsonify({'error': str(e)}), 500 # Return error response
if __name__ == '__main__':
app.run(debug=True) # Run the Flask application in debug mode
-
-
-# GITHUB : https://github.com/IkkiOcean
\ No newline at end of file
diff --git a/sugarcane-disease-api/prediction.py b/sugarcane-disease-api/prediction.py
index 5c52fd44..d33999c8 100644
--- a/sugarcane-disease-api/prediction.py
+++ b/sugarcane-disease-api/prediction.py
@@ -10,33 +10,42 @@
model2_mobile = load_model('./models/mobilenet_model.keras') # MobileNet model
model3 = load_model('./models/inceptionv3_80.h5') # InceptionV3 model
model4 = load_model('./models/model2_84percentacc.h5') # Another model with a specified accuracy
+
# Store the models in a list for ensemble prediction
models = [model4, model1_VGG, model2_mobile, model3]
MODEL_PRESENT = True # Flag indicating models are loaded successfully
-except:
+except Exception as e:
+ print(f"Error loading models: {str(e)}") # Print the error message
MODEL_PRESENT = False # Flag indicating models failed to load
# PREDICTION
-
def predict_sugarcane(filepath):
- # Function to predict the health of sugarcane based on the input image
+ """Predict the health of sugarcane based on the input image."""
if not MODEL_PRESENT:
return 0 # Returns 0 if models aren't present, indicating "Healthy"
+
# Generate predictions from each model
preds = [model.predict(preprocess_image(filepath)) for model in models]
preds_array = np.array(preds) # Convert predictions list to a NumPy array
- avg_preds = np.mean(preds_array, axis=0) # Calculate the average predictions
- ensemble_pred_labels = np.argmax(avg_preds, axis=1) # Get the final predicted labels
- return ensemble_pred_labels # Return the ensemble predictions
+
+ # Calculate the average predictions across models
+ avg_preds = np.mean(preds_array, axis=0)
+ ensemble_pred_label = np.argmax(avg_preds, axis=1)[0] # Get the final predicted label
+
+ return ensemble_pred_label # Return the ensemble prediction
def preprocess_image(image_path, target_size=(224, 224)):
- # Function to preprocess the image before feeding it to the model
+ """Preprocess the image before feeding it to the model."""
# Load the image with the specified target size
img = load_img(image_path, target_size=target_size)
+
# Convert the image to a NumPy array
img_array = img_to_array(img)
+
# Reshape the image to match the model's input shape (add batch dimension)
img_array = np.expand_dims(img_array, axis=0)
+
# Rescale the pixel values to the range [0, 1]
img_array /= 255.0
+
return img_array # Return the preprocessed image