SaiStack commited on
Commit
fc10439
Β·
0 Parent(s):

Added entire project to hf

Browse files
.fttignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ .git
2
+ fast-ai
.gitattributes ADDED
@@ -0,0 +1 @@
 
 
1
+ model/ filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ fast-ai/
2
+ *__pycache__
3
+ # *.keras
app/api/predict.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, UploadFile, File, HTTPException
2
+ from fastapi import FastAPI, File, UploadFile, Form
3
+ from pydantic import BaseModel
4
+ from typing import Optional
5
+ from app.schemas.predict import PredictRequest, PredictResponse
6
+ from app.core.model import predict as kpredict
7
+
8
+ router = APIRouter()
9
+
10
+ @router.post("/predict", response_model=PredictResponse)
11
+ async def predict(
12
+ model_name: str = Form(...),
13
+ # text: Optional[str] = Form(None),
14
+ file: UploadFile = File(...)
15
+ ):
16
+ try:
17
+ req = PredictRequest(model_name=model_name)
18
+ return await kpredict(req, file)
19
+ except Exception as e:
20
+ raise HTTPException(status_code=500, detail=str(e))
app/config.py ADDED
File without changes
app/core/model.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gc
2
+ # from app.pipelines.sentiment_pipeline import load_model as load_sentiment, predict_sentiment
3
+ from app.pipelines.main_pipeline import load_model as load_maize, predict_image
4
+
5
+ _cache = {}
6
+
7
+ async def predict(req, file):
8
+ name = req.model_name
9
+ # choose loader/predictor
10
+ # if name == "sentiment":
11
+ # loader, predictor, data = load_sentiment, predict_sentiment, req.text
12
+ if name.startswith("xception_"):
13
+ loader, predictor, data = load_maize, predict_image, await file.read()
14
+ else:
15
+ raise ValueError("Unknown model")
16
+
17
+ # load-on-demand
18
+ if name not in _cache:
19
+ _cache[name] = loader(name)
20
+ model = _cache[name]
21
+
22
+ # label, conf, disease_data = "Disease", 0.564, {"leaf beetle": {
23
+ # "description": "Beetles that skeletonize maize leaves, reducing growth.",
24
+ # "symptoms": ["Holes and transparent patches on leaves"],
25
+ # "treatment": "Use insecticidal soap or approved beetle pesticides.",
26
+ # "prevention": "Practice crop rotation and destroy old crop debris.",
27
+ # "message": "Leaf beetles may be feeding on your maize. Spray with safe insecticides and clean up leftover plant waste after harvest."
28
+ # }}
29
+ label, conf, disease_data = predictor(data, model, name)
30
+ return {"model": name, "label": label, "confidence": conf, "recommendation": disease_data}
31
+
app/pipelines/main_pipeline.py ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from tensorflow.keras.models import load_model as keras_load_model
2
+ from tensorflow.keras.applications.xception import preprocess_input
3
+ from PIL import Image
4
+ import numpy as np
5
+ from io import BytesIO
6
+ import os
7
+ from pathlib import Path
8
+
9
+ # Base directory: two levels up from this file
10
+ BASE_DIR = Path(__file__).resolve().parent.parent.parent
11
+
12
+ # Map model names to class labels
13
+ CLASS_NAMES = {
14
+ "xception_maize": ['fall armyworm', 'grasshoper', 'healthy', 'leaf beetle', 'leaf blight', 'leaf spot', 'streak virus'],
15
+ "xception_cassava": ["bacterial blight", "brown spot", "green mite", "healthy", "mosaic"],
16
+ "xception_cashew": ["anthracnose", "gumosis", "healthy", "leaf miner", "red rust"],
17
+ "xception_tomato": ["healthy", "leaf blight", "leaf curl", "septoria leaf spot", "verticulium wilt"]
18
+ }
19
+
20
+ DISEASE_DATA = {
21
+ "xception_maize": {
22
+ "fall armyworm": {
23
+ "description": "A destructive caterpillar that feeds on maize leaves and cobs.",
24
+ "symptoms": ["Holes in leaves", "Frass (insect poop) near whorls", "Stunted growth"],
25
+ "treatment": "Apply pesticides such as Spinosad or Bacillus thuringiensis. Early detection helps.",
26
+ "prevention": "Plant early, use pest-resistant varieties, rotate crops.",
27
+ "message": "Your maize might be under attack by fall armyworms. It's best to spray a safe pesticide like Spinosad and monitor regularly. Early action saves your yield!"
28
+ },
29
+ "grasshoper": {
30
+ "description": "Insects that chew on maize leaves, reducing photosynthesis.",
31
+ "symptoms": ["Jagged leaf edges", "Visible insects on leaves"],
32
+ "treatment": "Use neem-based sprays or mechanical control.",
33
+ "prevention": "Encourage natural predators like birds; avoid overuse of fertilizers.",
34
+ "message": "Looks like grasshoppers are chewing on your maize. Spray neem oil and try attracting birds to your farmβ€”they’re great helpers!"
35
+ },
36
+ "healthy": {
37
+ "description": "Your crop shows no signs of disease or pest infestation.",
38
+ "symptoms": [],
39
+ "treatment": "No treatment needed.",
40
+ "prevention": "Keep monitoring and maintain good farming practices.",
41
+ "message": "Great job! Your maize is looking healthy. Keep up the good work and keep checking regularly."
42
+ },
43
+ "leaf beetle": {
44
+ "description": "Beetles that skeletonize maize leaves, reducing growth.",
45
+ "symptoms": ["Holes and transparent patches on leaves"],
46
+ "treatment": "Use insecticidal soap or approved beetle pesticides.",
47
+ "prevention": "Practice crop rotation and destroy old crop debris.",
48
+ "message": "Leaf beetles may be feeding on your maize. Spray with safe insecticides and clean up leftover plant waste after harvest."
49
+ },
50
+ "leaf blight": {
51
+ "description": "Fungal disease that causes dead streaks on leaves.",
52
+ "symptoms": ["Long, greyish lesions", "Yellowing and dying leaves"],
53
+ "treatment": "Apply fungicides like Mancozeb. Ensure good air circulation.",
54
+ "prevention": "Avoid overhead watering; plant in well-spaced rows.",
55
+ "message": "Maize leaf blight detected. Spray fungicide and avoid wetting leaves during irrigation."
56
+ },
57
+ "leaf spot": {
58
+ "description": "Spots caused by fungus or bacteria, reducing photosynthesis.",
59
+ "symptoms": ["Brown or black spots with yellow halos"],
60
+ "treatment": "Spray with copper-based fungicide.",
61
+ "prevention": "Use disease-free seeds and rotate maize with legumes.",
62
+ "message": "Spots on your maize leaves suggest leaf spot. A copper fungicide should do the trick. Rotate crops to prevent re-infection."
63
+ },
64
+ "streak virus": {
65
+ "description": "A viral disease transmitted by leafhoppers.",
66
+ "symptoms": ["Yellow streaks", "Stunted plants", "Chlorotic leaves"],
67
+ "treatment": "No cure, but remove and burn infected plants.",
68
+ "prevention": "Control leafhoppers; use virus-free seeds.",
69
+ "message": "Your maize may have streak virus. Uproot and burn infected plants quickly, and spray to control leafhoppers."
70
+ }
71
+ },
72
+
73
+ "xception_cassava": {
74
+ "bacterial blight": {
75
+ "description": "A bacterial infection causing leaf wilting and stem dieback.",
76
+ "symptoms": ["Angular leaf spots", "Wilted leaves", "Stem rot"],
77
+ "treatment": "No direct cure, but pruning infected areas helps.",
78
+ "prevention": "Use disease-free cuttings; plant early.",
79
+ "message": "Cassava bacterial blight found. Cut off infected stems and plant clean cuttings next time."
80
+ },
81
+ "brown spot": {
82
+ "description": "Fungal disease causing brown lesions on leaves.",
83
+ "symptoms": ["Brown dry patches", "Defoliation in severe cases"],
84
+ "treatment": "Apply Mancozeb or other fungicides.",
85
+ "prevention": "Avoid overhead watering and weed regularly.",
86
+ "message": "Your cassava shows brown spot symptoms. Apply fungicide and keep the field well-weeded."
87
+ },
88
+ "green mite": {
89
+ "description": "Microscopic pests that feed on cassava leaves.",
90
+ "symptoms": ["Leaf curling", "Yellowing", "Stunted growth"],
91
+ "treatment": "Use neem oil or biological controls like predatory mites.",
92
+ "prevention": "Use tolerant varieties and natural predators.",
93
+ "message": "Green mites might be on your cassava. Spray neem oil and look into mite-resistant varieties."
94
+ },
95
+ "healthy": {
96
+ "description": "Your cassava is in excellent condition.",
97
+ "symptoms": [],
98
+ "treatment": "None required.",
99
+ "prevention": "Keep monitoring and weed regularly.",
100
+ "message": "Well done! Your cassava looks healthy. Just maintain regular care and check for early signs of trouble."
101
+ },
102
+ "mosaic": {
103
+ "description": "A viral disease causing leaf distortion.",
104
+ "symptoms": ["Mottled leaves", "Distorted growth"],
105
+ "treatment": "Remove and destroy infected plants.",
106
+ "prevention": "Use resistant varieties and clean planting materials.",
107
+ "message": "Cassava mosaic virus detected. Uproot affected plants and use resistant varieties for next season."
108
+ }
109
+ },
110
+
111
+ "xception_cashew": {
112
+ "anthracnose": {
113
+ "description": "Fungal disease that attacks young shoots and fruits.",
114
+ "symptoms": ["Black lesions", "Fruit drop", "Leaf spots"],
115
+ "treatment": "Use copper-based fungicides like Copper Oxychloride.",
116
+ "prevention": "Prune to increase airflow and avoid overhead irrigation.",
117
+ "message": "Your cashew trees may have anthracnose. Apply copper fungicide and prune crowded branches."
118
+ },
119
+ "gumosis": {
120
+ "description": "A physiological disorder where gum oozes from the bark.",
121
+ "symptoms": ["Gum exudation", "Cracked bark", "Yellowing leaves"],
122
+ "treatment": "Apply Bordeaux paste to the wounds.",
123
+ "prevention": "Avoid waterlogging and mechanical injuries.",
124
+ "message": "Gumosis spotted. Apply Bordeaux paste and ensure the soil drains well."
125
+ },
126
+ "healthy": {
127
+ "description": "No signs of disease or pest issues on your cashew.",
128
+ "symptoms": [],
129
+ "treatment": "None needed.",
130
+ "prevention": "Maintain clean pruning and proper watering.",
131
+ "message": "Your cashew looks healthy! Keep following good care practices and you'll be rewarded with a good harvest."
132
+ },
133
+ "leaf miner": {
134
+ "description": "Insects that burrow inside cashew leaves.",
135
+ "symptoms": ["Winding trails on leaves", "Leaf curling"],
136
+ "treatment": "Spray with Imidacloprid or neem-based pesticide.",
137
+ "prevention": "Remove affected leaves; plant resistant varieties.",
138
+ "message": "Leaf miners are feeding inside your cashew leaves. Spray with neem oil and remove damaged leaves."
139
+ },
140
+ "red rust": {
141
+ "description": "Algae-caused disease that forms reddish growth on leaves.",
142
+ "symptoms": ["Reddish-orange spots", "Reduced vigor"],
143
+ "treatment": "Spray copper fungicide or lime-sulfur solution.",
144
+ "prevention": "Avoid overcrowding and increase air circulation.",
145
+ "message": "Red rust detected on your cashew. Treat with copper fungicide and give your plants some breathing room."
146
+ }
147
+ },
148
+
149
+ "xception_tomato": {
150
+ "healthy": {
151
+ "description": "Tomatoes are growing well without any visible issues.",
152
+ "symptoms": [],
153
+ "treatment": "None needed.",
154
+ "prevention": "Maintain good practices like mulching and spacing.",
155
+ "message": "Your tomatoes are doing great! Keep watering regularly and monitor for any signs of pests or disease."
156
+ },
157
+ "leaf blight": {
158
+ "description": "Fungal disease causing rapid leaf death.",
159
+ "symptoms": ["Brown lesions", "Leaf drop", "Stem cankers"],
160
+ "treatment": "Apply chlorothalonil or copper-based fungicide.",
161
+ "prevention": "Avoid overhead watering and plant spacing.",
162
+ "message": "Leaf blight may be affecting your tomatoes. Spray fungicide and avoid splashing water on leaves."
163
+ },
164
+ "leaf curl": {
165
+ "description": "Viral disease spread by whiteflies.",
166
+ "symptoms": ["Upward curling leaves", "Stunted growth"],
167
+ "treatment": "Remove infected plants and control whiteflies.",
168
+ "prevention": "Use yellow sticky traps and virus-resistant varieties.",
169
+ "message": "Tomato leaf curl detected. Remove infected plants and trap whiteflies with yellow sticky traps."
170
+ },
171
+ "septoria leaf spot": {
172
+ "description": "Fungal disease causing circular spots on tomato leaves.",
173
+ "symptoms": ["Small brown circular spots", "Yellowing lower leaves"],
174
+ "treatment": "Use Mancozeb or chlorothalonil spray.",
175
+ "prevention": "Avoid wetting leaves; improve air circulation.",
176
+ "message": "Spots on tomato leaves? That’s septoria. Spray fungicide and ensure your plants aren’t too crowded."
177
+ },
178
+ "verticulium wilt": {
179
+ "description": "Soil-borne fungus that blocks water flow in tomatoes.",
180
+ "symptoms": ["Wilting leaves", "Yellowing", "Reduced fruit size"],
181
+ "treatment": "Remove affected plants and solarize soil.",
182
+ "prevention": "Rotate crops and avoid planting tomatoes in the same spot every year.",
183
+ "message": "Tomato wilt detected. Uproot infected plants and rotate your crops next season."
184
+ }
185
+ }
186
+ }
187
+
188
+
189
+ # Base path to models
190
+ MODEL_DIR = BASE_DIR / 'model'
191
+
192
+ # Load the model from disk
193
+ def load_model(name):
194
+ model_path = os.path.join(MODEL_DIR, f"{name}.keras")
195
+ return keras_load_model(model_path)
196
+
197
+ # Unified prediction logic
198
+ def predict_image(file_bytes, model, model_name):
199
+ img = Image.open(BytesIO(file_bytes)).convert("RGB")
200
+ img = img.resize((299, 299)) # Xception size
201
+
202
+ arr = np.array(img, dtype=np.float32)
203
+ arr = preprocess_input(arr)
204
+ arr = np.expand_dims(arr, axis=0)
205
+
206
+ preds = model.predict(arr)
207
+ idx = int(np.argmax(preds))
208
+ label = CLASS_NAMES[model_name][idx]
209
+ conf = float(np.max(preds))
210
+ return label, conf, DISEASE_DATA[model_name][label]
app/schemas/predict.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+ from typing import List, Optional
3
+
4
+
5
+ class Recommendation(BaseModel):
6
+ description: str
7
+ symptoms: List[str]
8
+ treatment: str
9
+ prevention: str
10
+ message: str
11
+
12
+ class PredictRequest(BaseModel):
13
+ model_name: str
14
+ # text: str = None # for text pipelines
15
+ class PredictResponse(BaseModel):
16
+ model: str
17
+ label: str
18
+ confidence: float
19
+ recommendation: Recommendation
20
+
app/scripts/dummy_model.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sklearn.pipeline import make_pipeline
2
+ from sklearn.feature_extraction.text import TfidfVectorizer
3
+ from sklearn.linear_model import LogisticRegression
4
+ import joblib
5
+
6
+ X = ["i love this", "i hate this", "amazing", "terrible", "good", "bad"]
7
+ y = ["positive", "negative", "positive", "negative", "positive", "negative"]
8
+
9
+ model = make_pipeline(TfidfVectorizer(), LogisticRegression())
10
+ model.fit(X, y)
11
+
12
+ joblib.dump(model, "model/classifier.pkl")
13
+ print("Dummy model saved.")
app/scripts/tens_test.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ import tensorflow as tf
2
+ print(tf.__version__)
huggingface.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ sdk: "python"
2
+ app_file: "main.py"
3
+ python_version: "3.12.8" # or another if needed
main.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from app.api.predict import router as predict_router
4
+
5
+ app = FastAPI()
6
+ app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
7
+ app.include_router(predict_router)
model/classifier.pkl ADDED
Binary file (1.81 kB). View file
 
readme.md ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Crop Disease Detection API Server
2
+
3
+ A **FastAPI** server hosting multiple Xception‑based deep learning models for detecting diseases in maize, cassava, cashew, and tomato leaves. Send images via HTTP and receive back the predicted disease, confidence score, and recommended treatment.
4
+
5
+ ---
6
+
7
+ ## πŸ“‹ Features
8
+
9
+ - **On‑demand model loading**: Each model is loaded the first time it’s requested and then cached.
10
+ - **Unified image pipeline**: Shared resizing, normalization, and inference logic.
11
+ - **Interactive docs**: Built‑in Swagger UI at `/docs`.
12
+ - **CORS enabled**: Accepts requests from any origin (customize as needed).
13
+
14
+ ---
15
+
16
+ ## πŸš€ Quick Start
17
+
18
+ ### 1. Clone & Prepare
19
+
20
+ ```bash
21
+ git clone https://github.com/Bawah-Joy/Ghana-Hack-AI.git
22
+ cd Ghana-Hack-AI/crop-guard-backend
23
+ python -m venv venv
24
+ source venv/bin/activate # macOS/Linux
25
+ venv\Scripts\activate # Windows
26
+ pip install --upgrade pip
27
+ pip install -r requirements.txt
28
+ ```
29
+
30
+ ### 2. Download & Place Models
31
+
32
+ Create a `model/` directory in the project root and download the pre-trained `.keras` files (examples below) into it:
33
+
34
+ ```
35
+ model/
36
+ β”œβ”€ xception_maize.keras
37
+ β”œβ”€ xception_cassava.keras
38
+ β”œβ”€ xception_cashew.keras
39
+ └─ xception_tomato.keras
40
+ ```
41
+
42
+ **Download links** (example Google Drive):
43
+
44
+ - [Maize Model](https://drive.google.com/file/d/1TLtyN5uzFUwMVL6TjTN3ejKZtZBXi2hw/view)
45
+ - [Cassava Model](https://drive.google.com/file/d/11mvp4TuIQ5NATksrRki-z2gWjJyU-j85/view)
46
+ - [Cashew Model](https://drive.google.com/file/d/1lxlHR6lWyOJJwZb9n6JST8yEd8VtcZK/view)
47
+ - [Tomato Model](https://drive.google.com/file/d/1A9a-t3kspjdxqmqz11OoK62D9JPortw3/view)
48
+
49
+ ### 3. Run Locally
50
+
51
+ #### Start the API
52
+
53
+ ```bash
54
+ uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
55
+ ```
56
+
57
+ #### (Optional) Ngrok Tunneling
58
+
59
+ ```bash
60
+ ngrok http 8000
61
+ ```
62
+
63
+ Copy the HTTPS URL (e.g. `https://abcd1234.ngrok.io`) and use it in your frontend or API clients.
64
+
65
+ ---
66
+
67
+ ## βš™οΈ Configuration
68
+
69
+ - No secrets required by default.
70
+ - CORS is enabled for all origins in `app/main.py` via:
71
+
72
+ ```python
73
+ app.add_middleware(
74
+ CORSMiddleware,
75
+ allow_origins=["*"],
76
+ allow_methods=["*"],
77
+ allow_headers=["*"],
78
+ )
79
+ ```
80
+
81
+ ---
82
+
83
+ ## πŸ“ API Reference
84
+
85
+ ### Interactive Docs
86
+
87
+ Browse and test all endpoints at:
88
+
89
+ ```
90
+ http://localhost:8000/docs
91
+ ```
92
+
93
+ ### `/predict`
94
+
95
+ - **Method:** `POST`
96
+ - **Content-Type:** `multipart/form-data`
97
+ - **Fields:**
98
+
99
+ - `file` (binary image file, e.g. JPEG/PNG)
100
+ - `model_name` (string; one of `xception_maize`, `xception_cassava`, `xception_cashew`, `xception_tomato`)
101
+
102
+ #### Example `curl`
103
+
104
+ ```bash
105
+ curl -X POST "https://<YOUR_NGROK>.ngrok.io/predict" \
106
+ -F "file=@/path/to/leaf.jpg;type=image/jpeg" \
107
+ -F "model_name=xception_maize"
108
+ ```
109
+
110
+ #### Sample Response
111
+
112
+ ```json
113
+ {
114
+ "label": "leaf blight",
115
+ "confidence": 0.87,
116
+ "details": {
117
+ "description": "Fungal disease that causes dead streaks on leaves.",
118
+ "symptoms": ["Long, greyish lesions", "Yellowing and dying leaves"],
119
+ "treatment": "Apply fungicides like Mancozeb. Ensure good air circulation.",
120
+ "prevention": "Avoid overhead watering; plant in well-spaced rows.",
121
+ "message": "Maize leaf blight detected. Spray fungicide and avoid wetting leaves during irrigation."
122
+ }
123
+ }
124
+ ```
125
+
126
+ ---
127
+
128
+ ## πŸ”„ Model Loading & Inference Flow
129
+
130
+ _All contained in `app/api/predict.py`:_
131
+
132
+ 1. **Load model on first request**
133
+
134
+ ```python
135
+ def load_model(name):
136
+ path = MODEL_DIR / f"{name}.keras"
137
+ return keras_load_model(path)
138
+ ```
139
+
140
+ 2. **Preprocess & predict**
141
+
142
+ ```python
143
+ def predict_image(file_bytes, model, model_name):
144
+ img = Image.open(BytesIO(file_bytes)).convert("RGB")
145
+ img = img.resize((299, 299))
146
+ arr = preprocess_input(np.expand_dims(np.array(img), 0))
147
+ preds = model.predict(arr)
148
+ idx = int(np.argmax(preds))
149
+ label = CLASS_NAMES[model_name][idx]
150
+ conf = float(np.max(preds))
151
+ return label, conf, DISEASE_DATA[model_name][label]
152
+ ```
153
+
154
+ 3. **Return JSON** with `label`, `confidence`, and rich `details`.
155
+
156
+ ---
157
+
158
+ ## ☁️ Deployment on Render
159
+
160
+ 1. Ensure `render.yml` is present in the project root.
161
+ 2. Push to GitHub and connect the repo in Render.
162
+ 3. Render will:
163
+
164
+ - Install dependencies: `pip install -r requirements.txt`
165
+ - Launch the app using:
166
+
167
+ ```bash
168
+ uvicorn app.main:app --host 0.0.0.0 --port $PORT
169
+ ```
170
+
171
+ ---
172
+
173
+ ## πŸ—‚οΈ Project Structure
174
+
175
+ ```
176
+ crop-guard-backend/
177
+ β”œβ”€ app/
178
+ β”‚ β”œβ”€ api/
179
+ β”‚ β”‚ └─ predict.py # Routes & inference logic
180
+ β”‚ β”œβ”€ core/
181
+ β”‚ β”‚ └─ model.py # Model manager & loader
182
+ β”‚ β”œβ”€ pipelines/
183
+ β”‚ β”‚ └─ main_pipeline.py # Shared preprocessing flow
184
+ β”‚ β”œβ”€ schemas/
185
+ β”‚ β”‚ └─ predict.py # Request/response Pydantic models
186
+ β”‚ └─ main.py # FastAPI app setup + CORS
187
+ β”œβ”€ model/ # Place downloaded .keras files here
188
+ β”œβ”€ requirements.txt # Python dependencies
189
+ β”œβ”€ render.yml # Render deployment config
190
+ └─ README.md # This file
191
+ ```
192
+
193
+ ---
render.yml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ services:
2
+ - type: web
3
+ name: crop-guard-api
4
+ runtime: python
5
+ buildCommand: pip install -r requirements.txt
6
+ startCommand: uvicorn app.main:app --host=0.0.0.0 --port=10000
7
+ envVars:
8
+ - key: PYTHON_VERSION
9
+ value: "3.10"
requirements.txt ADDED
Binary file (2.49 kB). View file
 
test.html ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>Predict</title>
6
+ </head>
7
+ <body>
8
+ <h1>Upload an Image for Prediction</h1>
9
+ <form id="predictForm">
10
+ <label for="model_name">Model Name:</label>
11
+ <input
12
+ type="text"
13
+ id="model_name"
14
+ name="model_name"
15
+ value="xception_maize"
16
+ required
17
+ />
18
+ <br /><br />
19
+ <label for="file">Choose image:</label>
20
+ <input type="file" id="file" name="file" accept="image/*" required />
21
+ <br /><br />
22
+ <button type="submit">Predict</button>
23
+ </form>
24
+
25
+ <pre id="output"></pre>
26
+
27
+ <script>
28
+ const form = document.getElementById("predictForm");
29
+ const output = document.getElementById("output");
30
+
31
+ form.addEventListener("submit", async (e) => {
32
+ e.preventDefault();
33
+
34
+ const formData = new FormData(form);
35
+
36
+ try {
37
+ const res = await fetch("http://localhost:8000/predict", {
38
+ method: "POST",
39
+ body: formData,
40
+ });
41
+
42
+ if (!res.ok) {
43
+ throw new Error("Server returned error: " + res.status);
44
+ }
45
+
46
+ const data = await res.json();
47
+ output.textContent = JSON.stringify(data, null, 2);
48
+ } catch (err) {
49
+ output.textContent = "Error: " + err.message;
50
+ }
51
+ });
52
+ </script>
53
+ </body>
54
+ </html>