Upload 7 files
Browse files- .gitattributes +0 -0
- .gitmodules +0 -0
- Poultry.h5 +3 -0
- app.py +179 -0
- index.html +125 -0
- requirements.txt +55 -0
- styles.css +64 -0
.gitattributes
CHANGED
Binary files a/.gitattributes and b/.gitattributes differ
|
|
.gitmodules
ADDED
Binary file (208 Bytes). View file
|
|
Poultry.h5
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:0390b132a918b165c89f813ec54d1481364bef0c3ae6f12c1dae60eb224499db
|
3 |
+
size 569291088
|
app.py
ADDED
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from flask import Flask, render_template, request, jsonify
|
2 |
+
from PIL import Image
|
3 |
+
import numpy as np
|
4 |
+
import os
|
5 |
+
import tensorflow as tf
|
6 |
+
from tensorflow.keras.models import load_model
|
7 |
+
from tensorflow.keras.preprocessing import image
|
8 |
+
from tensorflow.keras.layers import (
|
9 |
+
Input,
|
10 |
+
Conv2D,
|
11 |
+
MaxPooling2D,
|
12 |
+
Flatten,
|
13 |
+
Dense,
|
14 |
+
BatchNormalization,
|
15 |
+
Activation,
|
16 |
+
Add,
|
17 |
+
Concatenate,
|
18 |
+
)
|
19 |
+
from tensorflow.keras.optimizers import Adam
|
20 |
+
from vit_keras import vit
|
21 |
+
|
22 |
+
app = Flask(__name__)
|
23 |
+
|
24 |
+
# Define the upload directory
|
25 |
+
UPLOAD_FOLDER = 'uploads'
|
26 |
+
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
|
27 |
+
|
28 |
+
# Define transitional block function
|
29 |
+
def transitional_block(x, filters):
|
30 |
+
x = Conv2D(filters, kernel_size=(3, 3), strides=(1, 1), padding='same')(x)
|
31 |
+
x = BatchNormalization()(x)
|
32 |
+
x = Activation('relu')(x)
|
33 |
+
x = MaxPooling2D(pool_size=(2, 2), strides=(2, 2))(x)
|
34 |
+
return x
|
35 |
+
|
36 |
+
# Define pointwise convolution block function
|
37 |
+
def pointwise_conv_block(x, filters):
|
38 |
+
x = Conv2D(filters, kernel_size=(1, 1), strides=(1, 1), padding='same')(x)
|
39 |
+
x = BatchNormalization()(x)
|
40 |
+
x = Activation('relu')(x)
|
41 |
+
return x
|
42 |
+
|
43 |
+
# Define the ViT model
|
44 |
+
input_shape = (224, 224, 3) # Example input shape
|
45 |
+
num_classes = 4 # Example number of classes
|
46 |
+
vit_model = vit.vit_b32(
|
47 |
+
image_size=input_shape[:2],
|
48 |
+
include_top=False,
|
49 |
+
pretrained=True,
|
50 |
+
pretrained_top=False,
|
51 |
+
classes=num_classes,
|
52 |
+
weights="imagenet21k",
|
53 |
+
)
|
54 |
+
|
55 |
+
# Freeze the layers of the ViT model
|
56 |
+
for layer in vit_model.layers:
|
57 |
+
layer.trainable = False
|
58 |
+
|
59 |
+
# Define the modified VGG19 model
|
60 |
+
def modified_vgg19(input_tensor):
|
61 |
+
# Block 1
|
62 |
+
x = Conv2D(64, kernel_size=(3, 3), strides=(1, 1), padding='same')(input_tensor)
|
63 |
+
x = BatchNormalization()(x)
|
64 |
+
x = Activation('relu')(x)
|
65 |
+
x = transitional_block(x, 64)
|
66 |
+
|
67 |
+
# Block 2
|
68 |
+
x = transitional_block(x, 128)
|
69 |
+
x = pointwise_conv_block(x, 128)
|
70 |
+
|
71 |
+
# Block 3
|
72 |
+
x = transitional_block(x, 256)
|
73 |
+
x = pointwise_conv_block(x, 256)
|
74 |
+
x = pointwise_conv_block(x, 256)
|
75 |
+
x = pointwise_conv_block(x, 256)
|
76 |
+
|
77 |
+
# Block 4
|
78 |
+
x = transitional_block(x, 512)
|
79 |
+
x = pointwise_conv_block(x, 512)
|
80 |
+
x = pointwise_conv_block(x, 512)
|
81 |
+
x = pointwise_conv_block(x, 512)
|
82 |
+
x = pointwise_conv_block(x, 512)
|
83 |
+
|
84 |
+
# Block 5
|
85 |
+
x = transitional_block(x, 512)
|
86 |
+
x = pointwise_conv_block(x, 512)
|
87 |
+
x = pointwise_conv_block(x, 512)
|
88 |
+
x = pointwise_conv_block(x, 512)
|
89 |
+
x = pointwise_conv_block(x, 512)
|
90 |
+
|
91 |
+
x = transitional_block(x, 1024)
|
92 |
+
x = pointwise_conv_block(x, 1024)
|
93 |
+
x = pointwise_conv_block(x, 1024)
|
94 |
+
x = pointwise_conv_block(x, 1024)
|
95 |
+
x = pointwise_conv_block(x, 1024)
|
96 |
+
|
97 |
+
x = Flatten()(x)
|
98 |
+
x = Dense(256, activation='relu')(x)
|
99 |
+
x = Dense(256, activation='relu')(x)
|
100 |
+
output_layer = Dense(4, activation='softmax')(x)
|
101 |
+
|
102 |
+
return output_layer
|
103 |
+
|
104 |
+
# Register custom layers used in modified_vgg19
|
105 |
+
tf.keras.utils.get_custom_objects()['transitional_block'] = transitional_block
|
106 |
+
tf.keras.utils.get_custom_objects()['pointwise_conv_block'] = pointwise_conv_block
|
107 |
+
|
108 |
+
# Load the pre-trained model
|
109 |
+
path = "C:\\Users\\HI BUDDY\\Desktop\\App\\poultryapp\\Poultry.h5"
|
110 |
+
|
111 |
+
loaded_model = load_model(path, custom_objects={
|
112 |
+
'transitional_block': transitional_block,
|
113 |
+
'pointwise_conv_block': pointwise_conv_block,
|
114 |
+
})
|
115 |
+
|
116 |
+
# Function to preprocess the image
|
117 |
+
def preprocess_image(image_path):
|
118 |
+
img = image.load_img(image_path, target_size=(224, 224))
|
119 |
+
img_array = image.img_to_array(img)
|
120 |
+
img_array = np.expand_dims(img_array, axis=0)
|
121 |
+
img_array = img_array / 255.0
|
122 |
+
return img_array
|
123 |
+
|
124 |
+
# Function to check if the file has an allowed extension
|
125 |
+
def allowed_file(filename):
|
126 |
+
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
|
127 |
+
return '.' in filename and \
|
128 |
+
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
129 |
+
|
130 |
+
@app.route('/')
|
131 |
+
def index():
|
132 |
+
return render_template('index.html')
|
133 |
+
|
134 |
+
@app.route('/predict', methods=['POST'])
|
135 |
+
def predict():
|
136 |
+
# Check if the 'file' key is in the request
|
137 |
+
if 'file' not in request.files:
|
138 |
+
return jsonify({'error': 'No file part'})
|
139 |
+
|
140 |
+
file = request.files['file']
|
141 |
+
|
142 |
+
# Check if file is empty
|
143 |
+
if file.filename == '':
|
144 |
+
return jsonify({'error': 'No selected file'})
|
145 |
+
|
146 |
+
# Check if file is allowed
|
147 |
+
if file and allowed_file(file.filename):
|
148 |
+
# Create the upload directory if it doesn't exist
|
149 |
+
if not os.path.exists(app.config['UPLOAD_FOLDER']):
|
150 |
+
os.makedirs(app.config['UPLOAD_FOLDER'])
|
151 |
+
|
152 |
+
img_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
|
153 |
+
file.save(img_path)
|
154 |
+
|
155 |
+
# Preprocess the image
|
156 |
+
img_array = preprocess_image(img_path)
|
157 |
+
|
158 |
+
# Labels
|
159 |
+
class_labels = ['cocci', 'healthy', 'ncd', 'salmo']
|
160 |
+
# Make predictions
|
161 |
+
predictions = loaded_model.predict(img_array)
|
162 |
+
|
163 |
+
# Set confidence threshold
|
164 |
+
confidence_threshold = 0.50 # Adjust as needed
|
165 |
+
|
166 |
+
# Get the predicted class label and confidence
|
167 |
+
max_confidence = np.max(predictions)
|
168 |
+
|
169 |
+
if max_confidence >= confidence_threshold:
|
170 |
+
predicted_class_index = np.argmax(predictions)
|
171 |
+
predicted_class_label = class_labels[predicted_class_index]
|
172 |
+
return jsonify({'prediction': predicted_class_label})
|
173 |
+
else:
|
174 |
+
return jsonify({'prediction': "This format is not supported"})
|
175 |
+
else:
|
176 |
+
return jsonify({'error': 'Invalid file format'})
|
177 |
+
|
178 |
+
if __name__ == '__main__':
|
179 |
+
app.run(debug=True)
|
index.html
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Image Classifier</title>
|
7 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
8 |
+
</head>
|
9 |
+
<body>
|
10 |
+
<div id="headerContainer" class="header-container">
|
11 |
+
<h1>Poultry AI</h1>
|
12 |
+
</div>
|
13 |
+
|
14 |
+
<div id="mainContainer" style="display: flex;">
|
15 |
+
<div id="inputContainer" style="flex-grow: 1;">
|
16 |
+
<input type="file" id="uploadInput">
|
17 |
+
<button id="uploadButton">Upload</button>
|
18 |
+
<div id="predictionResult"></div>
|
19 |
+
<div id="diseaseInfo" style="display: none;">
|
20 |
+
<h2>General Precaution</h2>
|
21 |
+
<div id="diseaseDescription"></div>
|
22 |
+
<div id="prevention"></div>
|
23 |
+
<div id="suggestions"></div>
|
24 |
+
</div>
|
25 |
+
</div>
|
26 |
+
<div id="uploadedImageContainer" style="flex-grow: 1; margin-left: 20px;">
|
27 |
+
<img id="uploadedImage" src="#" alt="Uploaded Image" style="max-width: 100%; max-height: 300px; display: none;">
|
28 |
+
</div>
|
29 |
+
</div>
|
30 |
+
<script>
|
31 |
+
const allowedExtensions = ['png', 'jpg', 'jpeg', 'gif'];
|
32 |
+
|
33 |
+
document.getElementById('uploadInput').addEventListener('change', function() {
|
34 |
+
const fileInput = document.getElementById('uploadInput');
|
35 |
+
const file = fileInput.files[0];
|
36 |
+
if (!file) {
|
37 |
+
alert('Please select a file.');
|
38 |
+
return;
|
39 |
+
}
|
40 |
+
|
41 |
+
const fileExtension = file.name.split('.').pop().toLowerCase();
|
42 |
+
if (!allowedExtensions.includes(fileExtension)) {
|
43 |
+
alert('This file is not supported');
|
44 |
+
fileInput.value = ''; // Reset the file input
|
45 |
+
return;
|
46 |
+
}
|
47 |
+
|
48 |
+
// Display uploaded image
|
49 |
+
const uploadedImage = document.getElementById('uploadedImage');
|
50 |
+
uploadedImage.src = URL.createObjectURL(file);
|
51 |
+
uploadedImage.style.display = 'block';
|
52 |
+
});
|
53 |
+
|
54 |
+
document.getElementById('uploadButton').addEventListener('click', async function() {
|
55 |
+
const fileInput = document.getElementById('uploadInput');
|
56 |
+
const file = fileInput.files[0];
|
57 |
+
if (!file) {
|
58 |
+
alert('Please select a file.');
|
59 |
+
return;
|
60 |
+
}
|
61 |
+
|
62 |
+
const fileExtension = file.name.split('.').pop().toLowerCase();
|
63 |
+
if (!allowedExtensions.includes(fileExtension)) {
|
64 |
+
alert('This file is not supported');
|
65 |
+
fileInput.value = ''; // Reset the file input
|
66 |
+
return;
|
67 |
+
}
|
68 |
+
|
69 |
+
const formData = new FormData();
|
70 |
+
formData.append('file', file);
|
71 |
+
|
72 |
+
try {
|
73 |
+
const response = await fetch('/predict', {
|
74 |
+
method: 'POST',
|
75 |
+
body: formData
|
76 |
+
});
|
77 |
+
const data = await response.json();
|
78 |
+
document.getElementById('predictionResult').innerText = data.prediction;
|
79 |
+
|
80 |
+
// Display additional information based on prediction
|
81 |
+
const diseaseInfo = document.getElementById('diseaseInfo');
|
82 |
+
const diseaseDescription = document.getElementById('diseaseDescription');
|
83 |
+
const prevention = document.getElementById('prevention');
|
84 |
+
const suggestions = document.getElementById('suggestions');
|
85 |
+
|
86 |
+
// Reset previous content
|
87 |
+
diseaseDescription.innerHTML = '';
|
88 |
+
prevention.innerHTML = '';
|
89 |
+
suggestions.innerHTML = '';
|
90 |
+
|
91 |
+
switch (data.prediction.toLowerCase()) {
|
92 |
+
case 'salmo':
|
93 |
+
diseaseDescription.innerHTML = 'Salmonellosis is caused by Salmonella bacteria and can lead to digestive tract infections in poultry.';
|
94 |
+
prevention.innerHTML = 'Implement strict biosecurity measures on the farm to prevent contamination. Provide clean water and feed.';
|
95 |
+
suggestions.innerHTML = 'Consult a veterinarian for guidance on vaccination programs and proper antibiotic use if necessary.';
|
96 |
+
diseaseInfo.style.display = 'block';
|
97 |
+
break;
|
98 |
+
case 'healthy':
|
99 |
+
diseaseDescription.innerHTML = 'No disease detected. The image indicates a healthy condition in the poultry.';
|
100 |
+
diseaseInfo.style.display = 'none';
|
101 |
+
break;
|
102 |
+
case 'ncd':
|
103 |
+
diseaseDescription.innerHTML = 'Newcastle disease (NCD) is a viral disease affecting poultry respiratory, nervous, and digestive systems.';
|
104 |
+
prevention.innerHTML = 'Implement strict biosecurity measures on the farm. Vaccinate birds against Newcastle disease.';
|
105 |
+
suggestions.innerHTML = 'Consult a veterinarian ';
|
106 |
+
diseaseInfo.style.display = 'block';
|
107 |
+
break;
|
108 |
+
case 'cocci':
|
109 |
+
diseaseDescription.innerHTML = 'Coccidiosis is caused by protozoa of the genus Eimeria, affecting the intestinal tract of poultry.';
|
110 |
+
prevention.innerHTML = 'Practice proper sanitation and hygiene measures in the poultry house. ';
|
111 |
+
suggestions.innerHTML = 'Consult a veterinarian for guidance on coccidiosis prevention and control strategies tailored to your flock.';
|
112 |
+
diseaseInfo.style.display = 'block';
|
113 |
+
break;
|
114 |
+
default:
|
115 |
+
// If prediction does not match any specific case, hide the additional info
|
116 |
+
diseaseInfo.style.display = 'none';
|
117 |
+
break;
|
118 |
+
}
|
119 |
+
} catch (error) {
|
120 |
+
console.error('Error:', error);
|
121 |
+
}
|
122 |
+
});
|
123 |
+
</script>
|
124 |
+
</body>
|
125 |
+
</html>
|
requirements.txt
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
absl-py==2.1.0
|
2 |
+
astunparse==1.6.3
|
3 |
+
blinker==1.8.2
|
4 |
+
cachetools==5.3.3
|
5 |
+
certifi==2024.2.2
|
6 |
+
charset-normalizer==3.3.2
|
7 |
+
click==8.1.7
|
8 |
+
colorama==0.4.6
|
9 |
+
Flask==3.0.3
|
10 |
+
flatbuffers==24.3.25
|
11 |
+
gast==0.5.4
|
12 |
+
google-auth==2.29.0
|
13 |
+
google-auth-oauthlib==1.0.0
|
14 |
+
google-pasta==0.2.0
|
15 |
+
grpcio==1.63.0
|
16 |
+
h5py==3.11.0
|
17 |
+
idna==3.7
|
18 |
+
itsdangerous==2.2.0
|
19 |
+
Jinja2==3.1.4
|
20 |
+
keras==2.14.0
|
21 |
+
libclang==18.1.1
|
22 |
+
Markdown==3.6
|
23 |
+
MarkupSafe==2.1.5
|
24 |
+
ml-dtypes==0.2.0
|
25 |
+
numpy==1.26.4
|
26 |
+
oauthlib==3.2.2
|
27 |
+
opencv-python==4.9.0.80
|
28 |
+
opt-einsum==3.3.0
|
29 |
+
packaging==24.0
|
30 |
+
pillow==10.3.0
|
31 |
+
protobuf==4.25.3
|
32 |
+
pyasn1==0.6.0
|
33 |
+
pyasn1-modules==0.4.0
|
34 |
+
requests==2.31.0
|
35 |
+
requests-oauthlib==2.0.0
|
36 |
+
rsa==4.9
|
37 |
+
scipy==1.13.0
|
38 |
+
setuptools==57.4.0
|
39 |
+
six==1.16.0
|
40 |
+
tensorboard==2.14.1
|
41 |
+
tensorboard-data-server==0.7.2
|
42 |
+
tensorflow==2.14.0
|
43 |
+
tensorflow-addons==0.22.0
|
44 |
+
tensorflow-estimator==2.14.0
|
45 |
+
# tensorflow-intel==2.14.0
|
46 |
+
tensorflow-io-gcs-filesystem==0.31.0
|
47 |
+
termcolor==2.4.0
|
48 |
+
typeguard==2.13.3
|
49 |
+
typing-extensions==4.11.0
|
50 |
+
urllib3==2.2.1
|
51 |
+
validators==0.28.1
|
52 |
+
vit-keras==0.1.2
|
53 |
+
Werkzeug==3.0.3
|
54 |
+
wheel==0.43.0
|
55 |
+
wrapt==1.14.1
|
styles.css
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
body {
|
2 |
+
font-family: Arial, sans-serif;
|
3 |
+
margin: 0;
|
4 |
+
padding: 0;
|
5 |
+
display: flex;
|
6 |
+
flex-direction: column;
|
7 |
+
align-items: center;
|
8 |
+
justify-content: center;
|
9 |
+
height: 100vh;
|
10 |
+
background-color: #54819a;
|
11 |
+
}
|
12 |
+
|
13 |
+
h1 {
|
14 |
+
margin-bottom: 20px;
|
15 |
+
}
|
16 |
+
|
17 |
+
#uploadInput {
|
18 |
+
margin-bottom: 20px;
|
19 |
+
}
|
20 |
+
|
21 |
+
#uploadButton {
|
22 |
+
padding: 10px 20px;
|
23 |
+
background-color: #4caf50;
|
24 |
+
color: white;
|
25 |
+
border: none;
|
26 |
+
border-radius: 5px;
|
27 |
+
cursor: pointer;
|
28 |
+
}
|
29 |
+
|
30 |
+
#uploadButton:hover {
|
31 |
+
background-color: #45a049;
|
32 |
+
}
|
33 |
+
|
34 |
+
#predictionResult {
|
35 |
+
margin-top: 20px;
|
36 |
+
font-weight: bold;
|
37 |
+
}
|
38 |
+
|
39 |
+
/* Added styles for uploaded image container */
|
40 |
+
#uploadedImageContainer {
|
41 |
+
display: flex;
|
42 |
+
justify-content: center;
|
43 |
+
align-items: center;
|
44 |
+
|
45 |
+
}
|
46 |
+
|
47 |
+
/* Added styles for disease information container */
|
48 |
+
#diseaseInfo {
|
49 |
+
margin-top: 20px;
|
50 |
+
padding: 20px;
|
51 |
+
background-color: #fff;
|
52 |
+
border-radius: 5px;
|
53 |
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
54 |
+
}
|
55 |
+
|
56 |
+
#diseaseInfo h2 {
|
57 |
+
margin-bottom: 10px;
|
58 |
+
color: #333;
|
59 |
+
}
|
60 |
+
|
61 |
+
#diseaseInfo div {
|
62 |
+
margin-bottom: 10px;
|
63 |
+
}
|
64 |
+
|