Emmanuel Frimpong Asante
commited on
Commit
·
87eefcd
1
Parent(s):
5c3c9e5
update space
Browse files- .env +1 -0
- .idea/Generative_AI_with_poultry_disease_detection_system_v2.iml +0 -3
- app.py +8 -3
- requirements.txt +11 -8
- routes/disease_detection.py +46 -0
- services/convert_model.py +12 -0
- services/disease_detection_service.py +35 -0
- services/image_preprocessing.py +22 -0
.env
CHANGED
@@ -3,3 +3,4 @@
|
|
3 |
MONGO_URI="your_mongo_db_uri"
|
4 |
EMAIL_USER="your_email_username"
|
5 |
EMAIL_PASS="your_email_password"
|
|
|
|
3 |
MONGO_URI="your_mongo_db_uri"
|
4 |
EMAIL_USER="your_email_username"
|
5 |
EMAIL_PASS="your_email_password"
|
6 |
+
TF_ENABLE_ONEDNN_OPTS=0
|
.idea/Generative_AI_with_poultry_disease_detection_system_v2.iml
CHANGED
@@ -8,7 +8,4 @@
|
|
8 |
<orderEntry type="sourceFolder" forTests="false" />
|
9 |
<orderEntry type="library" name="jquery-3.6.0" level="application" />
|
10 |
</component>
|
11 |
-
<component name="PackageRequirementsSettings">
|
12 |
-
<option name="removeUnused" value="true" />
|
13 |
-
</component>
|
14 |
</module>
|
|
|
8 |
<orderEntry type="sourceFolder" forTests="false" />
|
9 |
<orderEntry type="library" name="jquery-3.6.0" level="application" />
|
10 |
</component>
|
|
|
|
|
|
|
11 |
</module>
|
app.py
CHANGED
@@ -5,21 +5,26 @@ from fastapi.templating import Jinja2Templates
|
|
5 |
from fastapi.responses import HTMLResponse
|
6 |
from fastapi.staticfiles import StaticFiles
|
7 |
from routes.authentication import auth_router
|
|
|
8 |
import os
|
|
|
|
|
|
|
|
|
9 |
|
10 |
-
# Initialize FastAPI app and template directory
|
11 |
app = FastAPI()
|
12 |
templates = Jinja2Templates(directory="templates")
|
13 |
|
14 |
-
# Mount static files if
|
15 |
static_dir = "static"
|
16 |
if os.path.isdir(static_dir):
|
17 |
app.mount("/static", StaticFiles(directory=static_dir), name="static")
|
18 |
else:
|
19 |
raise HTTPException(status_code=500, detail="Static directory not found.")
|
20 |
|
21 |
-
# Include
|
22 |
app.include_router(auth_router, prefix="/auth", tags=["Authentication"])
|
|
|
23 |
|
24 |
@app.get("/", response_class=HTMLResponse)
|
25 |
async def landing_page(request: Request):
|
|
|
5 |
from fastapi.responses import HTMLResponse
|
6 |
from fastapi.staticfiles import StaticFiles
|
7 |
from routes.authentication import auth_router
|
8 |
+
from routes.disease_detection import disease_router # Import the new router
|
9 |
import os
|
10 |
+
import tensorflow as tf
|
11 |
+
|
12 |
+
|
13 |
+
print("Num GPUs Available: ", len(tf.config.list_physical_devices('GPU')))
|
14 |
|
|
|
15 |
app = FastAPI()
|
16 |
templates = Jinja2Templates(directory="templates")
|
17 |
|
18 |
+
# Mount static files if directory exists
|
19 |
static_dir = "static"
|
20 |
if os.path.isdir(static_dir):
|
21 |
app.mount("/static", StaticFiles(directory=static_dir), name="static")
|
22 |
else:
|
23 |
raise HTTPException(status_code=500, detail="Static directory not found.")
|
24 |
|
25 |
+
# Include routers
|
26 |
app.include_router(auth_router, prefix="/auth", tags=["Authentication"])
|
27 |
+
app.include_router(disease_router, prefix="/disease", tags=["Disease Detection"]) # New route
|
28 |
|
29 |
@app.get("/", response_class=HTMLResponse)
|
30 |
async def landing_page(request: Request):
|
requirements.txt
CHANGED
@@ -1,10 +1,13 @@
|
|
1 |
-
fastapi
|
2 |
-
passlib[bcrypt]
|
3 |
-
pydantic[email]
|
4 |
-
pymongo
|
5 |
-
python-dotenv
|
6 |
-
python-jose[cryptography]
|
7 |
-
starlette
|
8 |
uvicorn
|
9 |
jinja2
|
10 |
-
python-multipart
|
|
|
|
|
|
|
|
1 |
+
fastapi
|
2 |
+
passlib[bcrypt]
|
3 |
+
pydantic[email]
|
4 |
+
pymongo
|
5 |
+
python-dotenv
|
6 |
+
python-jose[cryptography]
|
7 |
+
starlette
|
8 |
uvicorn
|
9 |
jinja2
|
10 |
+
python-multipart
|
11 |
+
numpy
|
12 |
+
pillow
|
13 |
+
tensorflow[and-cuda]~=2.9
|
routes/disease_detection.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# routes/disease_detection.py
|
2 |
+
|
3 |
+
from fastapi import APIRouter, UploadFile, File, HTTPException
|
4 |
+
from fastapi.responses import JSONResponse
|
5 |
+
from PIL import Image
|
6 |
+
import io
|
7 |
+
import numpy as np
|
8 |
+
from services.image_preprocessing import preprocess_image
|
9 |
+
from services.disease_detection_service import load_disease_model
|
10 |
+
|
11 |
+
disease_router = APIRouter()
|
12 |
+
model = load_disease_model()
|
13 |
+
|
14 |
+
|
15 |
+
@disease_router.post("/detect_disease", response_class=JSONResponse)
|
16 |
+
async def detect_disease(file: UploadFile = File(...)):
|
17 |
+
"""
|
18 |
+
Detect disease from uploaded poultry fecal image.
|
19 |
+
|
20 |
+
Parameters:
|
21 |
+
file (UploadFile): Uploaded image file to analyze.
|
22 |
+
|
23 |
+
Returns:
|
24 |
+
JSONResponse: Prediction result indicating disease probability or classification.
|
25 |
+
"""
|
26 |
+
if file.content_type not in ["image/jpeg", "image/png"]:
|
27 |
+
raise HTTPException(status_code=400, detail="Invalid file type. Please upload a JPEG or PNG image.")
|
28 |
+
|
29 |
+
# Load image and preprocess
|
30 |
+
image_data = await file.read()
|
31 |
+
image = Image.open(io.BytesIO(image_data))
|
32 |
+
processed_image = preprocess_image(image)
|
33 |
+
|
34 |
+
# Predict using the loaded model
|
35 |
+
prediction = model.predict(processed_image)
|
36 |
+
predicted_class = np.argmax(prediction, axis=1).item()
|
37 |
+
confidence = prediction[0][predicted_class] * 100
|
38 |
+
|
39 |
+
# Interpret results (assume labels for example: 0='Healthy', 1='Infected')
|
40 |
+
label_map = {0: "Healthy", 1: "Infected"}
|
41 |
+
result = {
|
42 |
+
"prediction": label_map.get(predicted_class, "Unknown"),
|
43 |
+
"confidence": f"{confidence:.2f}%"
|
44 |
+
}
|
45 |
+
|
46 |
+
return JSONResponse(content=result)
|
services/convert_model.py
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# convert_model.py
|
2 |
+
|
3 |
+
import tensorflow as tf
|
4 |
+
|
5 |
+
MODEL_PATH = "models/Final_Chicken_disease_model.h5"
|
6 |
+
NEW_MODEL_PATH = "models/Final_Chicken_disease_model"
|
7 |
+
|
8 |
+
# Load the .h5 model
|
9 |
+
model = tf.keras.models.load_model(MODEL_PATH)
|
10 |
+
|
11 |
+
# Save it in the SavedModel format
|
12 |
+
model.save(NEW_MODEL_PATH)
|
services/disease_detection_service.py
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# services/disease_detection_service.py
|
2 |
+
|
3 |
+
import tensorflow as tf
|
4 |
+
from tensorflow.keras.models import load_model
|
5 |
+
import numpy as np
|
6 |
+
from PIL import Image
|
7 |
+
import os
|
8 |
+
|
9 |
+
# Enable memory growth for GPUs
|
10 |
+
gpus = tf.config.list_physical_devices('GPU')
|
11 |
+
if gpus:
|
12 |
+
try:
|
13 |
+
for gpu in gpus:
|
14 |
+
tf.config.experimental.set_memory_growth(gpu, True)
|
15 |
+
print("Memory growth enabled for GPU.")
|
16 |
+
except RuntimeError as e:
|
17 |
+
print(f"Error setting memory growth: {e}")
|
18 |
+
|
19 |
+
|
20 |
+
MODEL_PATH = "models/Final_Chicken_disease_model.h5"
|
21 |
+
model = None
|
22 |
+
|
23 |
+
def load_disease_model():
|
24 |
+
"""Load the trained disease detection model with GPU support if available."""
|
25 |
+
global model
|
26 |
+
if model is None:
|
27 |
+
# Use GPU if available
|
28 |
+
if tf.config.list_physical_devices('GPU'):
|
29 |
+
print("GPU is available. Using GPU for model inference.")
|
30 |
+
with tf.device('/GPU:0'):
|
31 |
+
model = load_model(MODEL_PATH, custom_objects={'BatchNormalization': tf.keras.layers.BatchNormalization})
|
32 |
+
else:
|
33 |
+
print("GPU not available. Using CPU for model inference.")
|
34 |
+
model = load_model(MODEL_PATH, custom_objects={'BatchNormalization': tf.keras.layers.BatchNormalization})
|
35 |
+
return model
|
services/image_preprocessing.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# services/image_preprocessing.py
|
2 |
+
|
3 |
+
from PIL import Image
|
4 |
+
import numpy as np
|
5 |
+
|
6 |
+
|
7 |
+
def preprocess_image(image: Image.Image, target_size=(224, 224)):
|
8 |
+
"""
|
9 |
+
Preprocesses the uploaded image for disease detection.
|
10 |
+
|
11 |
+
Parameters:
|
12 |
+
image (PIL.Image.Image): Input image to preprocess.
|
13 |
+
target_size (tuple): Target size for resizing the image.
|
14 |
+
|
15 |
+
Returns:
|
16 |
+
np.ndarray: Preprocessed image ready for model input.
|
17 |
+
"""
|
18 |
+
image = image.convert("RGB") # Ensure 3 color channels
|
19 |
+
image = image.resize(target_size) # Resize image
|
20 |
+
image_array = np.array(image) / 255.0 # Normalize to [0, 1]
|
21 |
+
image_array = np.expand_dims(image_array, axis=0) # Add batch dimension
|
22 |
+
return image_array
|