KabsiMontassar commited on
Commit
d65f7e4
·
1 Parent(s): d2354c3

Add application file

Browse files
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ .env
2
+ assets
app.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import numpy as np
4
+ import gradio as gr
5
+ from PIL import Image
6
+ from model_loader import load_model, preprocess_image, predict_disease
7
+ from chat_app import groq_chatbot
8
+
9
+ # Load the disease diagnosis model
10
+ model_path = "attached_assets/mobilenetv2.h5"
11
+ model = load_model(model_path)
12
+
13
+ # Load class labels
14
+ with open("class_labels.json", "r") as f:
15
+ class_labels = json.load(f)
16
+
17
+ # Disease treatments dictionary
18
+ DEMO_TREATMENTS = {
19
+ "Apple - Apple Scab": "Rake and destroy fallen leaves, prune for good air circulation, apply fungicides like captan or sulfur before rainy periods, and plant resistant apple varieties.",
20
+ "Apple - Black Rot": "Prune and remove infected branches, destroy fallen leaves and fruit, apply copper-based fungicides, and ensure proper spacing between trees.",
21
+ "Apple - Cedar Apple Rust": "Remove nearby juniper or cedar trees if possible, apply fungicides like myclobutanil, and plant resistant apple varieties.",
22
+ "Apple - Healthy": "Your apple tree appears healthy! Continue regular maintenance, including pruning, watering, and monitoring for pests or disease symptoms.",
23
+ "Background without Leaves": "No plants detected. Please upload an image containing leaves to diagnose.",
24
+ "Blueberry - Healthy": "Your blueberry plant is healthy! Ensure consistent watering, proper mulching, and protect it from frost during early spring.",
25
+ "Cherry - Powdery Mildew": "Remove infected leaves, avoid overhead watering, ensure good air circulation, and apply fungicides containing sulfur or potassium bicarbonate.",
26
+ "Cherry - Healthy": "Your cherry tree is healthy! Continue providing proper care, including regular pruning, watering, and monitoring for pests or diseases.",
27
+ "Corn - Cercospora Leaf Spot (Gray Leaf Spot)": "Rotate crops annually, apply fungicides like strobilurins or triazoles, and ensure good field drainage and proper plant spacing.",
28
+ "Corn - Common Rust": "Apply fungicides containing propiconazole or azoxystrobin, plant resistant corn varieties, and avoid overhead irrigation.",
29
+ "Corn - Northern Leaf Blight": "Rotate crops, plant resistant varieties, and apply fungicides like mancozeb or strobilurin when symptoms first appear.",
30
+ "Corn - Healthy": "Your corn plant looks healthy! Continue to monitor for any signs of disease and ensure proper spacing for airflow.",
31
+ "Grape - Black Rot": "Remove mummified berries and infected leaves, prune for good air circulation, and apply fungicides such as myclobutanil or captan.",
32
+ "Grape - Esca (Black Measles)": "Prune and destroy infected parts, practice proper vineyard sanitation, and avoid mechanical injuries to the vines.",
33
+ "Grape - Leaf Blight (Isariopsis Leaf Spot)": "Remove and destroy infected leaves, apply fungicides containing copper, and ensure proper spacing for air circulation.",
34
+ "Grape - Healthy": "Your grapevine is healthy! Maintain regular pruning, proper watering, and monitoring for pests or diseases.",
35
+ "Orange - Huanglongbing (Citrus Greening)": "Unfortunately, there is no cure. Remove and destroy infected trees, control psyllid populations using insecticides, and plant disease-free certified saplings.",
36
+ "Peach - Bacterial Spot": "Apply copper-based bactericides, remove and destroy infected leaves and fruit, and plant resistant peach varieties.",
37
+ "Peach - Healthy": "Your peach tree looks healthy! Continue regular care, including pruning, fertilizing, and monitoring for pests or diseases.",
38
+ "Pepper (Bell) - Bacterial Spot": "Apply fixed copper sprays, avoid overhead irrigation, remove infected plants, and practice crop rotation.",
39
+ "Pepper (Bell) - Healthy": "Your bell pepper plant looks healthy! Ensure adequate sunlight, watering, and keep monitoring for any pests or diseases.",
40
+ "Potato - Early Blight": "Remove infected leaves, apply fungicides with active ingredients like chlorothalonil, and ensure proper spacing between plants.",
41
+ "Potato - Late Blight": "Apply fungicides like mancozeb or chlorothalonil, remove and destroy infected plants, and avoid overhead watering.",
42
+ "Potato - Healthy": "Your potato plant looks healthy! Maintain proper watering, ensure good soil drainage, and monitor for any signs of disease.",
43
+ "Raspberry - Healthy": "Your raspberry plant is healthy! Ensure proper support, regular pruning, and protect it from pests and harsh weather conditions.",
44
+ "Soybean - Healthy": "Your soybean crop is healthy! Monitor regularly for any signs of disease or pests, and maintain proper crop rotation.",
45
+ "Squash - Powdery Mildew": "Apply fungicides with sulfur or potassium bicarbonate, remove infected leaves, and ensure good air circulation.",
46
+ "Strawberry - Leaf Scorch": "Remove infected leaves, avoid overhead watering, and apply fungicides like captan or mancozeb.",
47
+ "Strawberry - Healthy": "Your strawberry plants are healthy! Maintain consistent watering, ensure good air circulation, and protect from frost.",
48
+ "Tomato - Bacterial Spot": "Remove infected leaves, apply fixed copper sprays, and avoid overhead irrigation. Ensure proper plant spacing.",
49
+ "Tomato - Early Blight": "Remove infected leaves, apply fungicides containing chlorothalonil or copper, and mulch around plants to prevent soil splashing.",
50
+ "Tomato - Late Blight": "Apply fungicides like chlorothalonil or mancozeb, remove infected plants, and ensure proper spacing for airflow.",
51
+ "Tomato - Leaf Mold": "Remove infected leaves, ensure proper air circulation, and apply fungicides containing chlorothalonil or copper.",
52
+ "Tomato - Septoria Leaf Spot": "Remove and destroy infected leaves, apply fungicides like mancozeb, and avoid overhead watering.",
53
+ "Tomato - Spider Mites (Two-Spotted Spider Mite)": "Spray the undersides of leaves with water, apply horticultural oils or insecticidal soaps, and maintain humidity around plants.",
54
+ "Tomato - Target Spot": "Remove infected leaves, apply fungicides like chlorothalonil, and ensure proper spacing between plants for air circulation.",
55
+ "Tomato - Tomato Yellow Leaf Curl Virus": "Remove infected plants, control whitefly populations with insecticides, and plant resistant tomato varieties.",
56
+ "Tomato - Tomato Mosaic Virus": "Remove infected plants, sterilize tools, and avoid handling plants when wet.",
57
+ "Tomato - Healthy": "Your tomato plant is healthy! Maintain regular watering, ensure adequate sunlight, and monitor for pests or diseases."
58
+ }
59
+
60
+ # Diagnosis function
61
+ def diagnose_image(image):
62
+ if image is None:
63
+ return "⚠️ Please upload an image for diagnosis."
64
+
65
+ try:
66
+ img_array = np.array(image)
67
+ preprocessed_img = preprocess_image(img_array)
68
+ disease_label, confidence = predict_disease(model, preprocessed_img, class_labels)
69
+ confidence_pct = f"{confidence:.1f}%"
70
+
71
+ treatment = DEMO_TREATMENTS.get(
72
+ disease_label,
73
+ "No specific treatment information available for this condition. Consult with an agricultural expert."
74
+ )
75
+
76
+ result = f"### 🌿 Diagnosis: {disease_label.replace('_', ' ')}\n"
77
+ result += f"**Confidence:** {confidence_pct}\n\n"
78
+ result += f"### 🛠 Recommended Treatment:\n{treatment}"
79
+ return result
80
+ except Exception as e:
81
+ return f"❌ Error during diagnosis: {e}"
82
+
83
+ # Build Gradio UI
84
+ with gr.Blocks(css="footer {visibility: hidden}") as app:
85
+ gr.Markdown("# 🌱 Plant Disease Diagnosis & Agricultural Chatbot")
86
+ gr.Markdown("Upload an image of a plant leaf for disease detection, or ask the chatbot for agricultural advice.")
87
+
88
+ with gr.Row():
89
+ # LEFT: Image Upload & Disease Diagnosis
90
+ with gr.Column(scale=1):
91
+ gr.Markdown("## 📸 Upload Image for Diagnosis")
92
+ image_input = gr.Image(type="numpy", label="Upload Leaf Image")
93
+ diagnose_button = gr.Button("🔍 Diagnose", variant="primary")
94
+ diagnosis_output = gr.Markdown(label="Diagnosis Results")
95
+
96
+ diagnose_button.click(fn=diagnose_image, inputs=[image_input], outputs=[diagnosis_output])
97
+
98
+ # RIGHT: Chatbot for Agricultural Advice
99
+ with gr.Column(scale=1):
100
+ gr.Markdown("## 🤖 Ask the Agricultural Chatbot")
101
+ chatbot = gr.Chatbot(height=400)
102
+ msg = gr.Textbox(placeholder="Ask a question about agriculture...", label="Your Question")
103
+ clear = gr.Button("🗑 Clear Chat")
104
+ chat_history_state = gr.State([])
105
+
106
+ msg.submit(fn=groq_chatbot, inputs=[msg, chat_history_state], outputs=[chatbot, msg])
107
+ clear.click(lambda: ([], ""), None, [chatbot, msg], queue=False)
108
+
109
+ gr.Markdown("---")
110
+ gr.Markdown("### ℹ️ About this Application")
111
+ gr.Markdown("This AI-powered tool helps diagnose plant diseases and provides treatment recommendations. It also includes a chatbot for general agricultural queries.")
112
+
113
+ # Launch Gradio app
114
+ if __name__ == "__main__":
115
+ app.launch(share=True)
chat_app.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from groq import Groq
3
+ import gradio as gr
4
+ from dotenv import load_dotenv
5
+ load_dotenv()
6
+ # Load API key from environment variable
7
+ API_KEY = os.getenv("GROQ_API_KEY")
8
+ if not API_KEY:
9
+ raise ValueError("Missing GROQ_API_KEY environment variable. Set it in Hugging Face Spaces Secrets.")
10
+
11
+ client = Groq(api_key=API_KEY)
12
+
13
+ VALIDATION_PROMPT = "You are an intelligent assistant. Analyze the input question carefully. Respond with 'Yes' if the input is agriculture-related, and 'No' otherwise."
14
+ RESPONSE_PROMPT = "You are an agriculture expert. Provide a concise and accurate answer to the following agriculture-related question:"
15
+
16
+ def validate_input(input_text):
17
+ try:
18
+ validation_response = client.chat.completions.create(
19
+ model="llama-3.1-8b-instant",
20
+ messages=[
21
+ {"role": "system", "content": "You are a helpful assistant."},
22
+ {"role": "user", "content": VALIDATION_PROMPT},
23
+ {"role": "user", "content": input_text},
24
+ ],
25
+ temperature=0,
26
+ max_completion_tokens=1,
27
+ )
28
+ return validation_response.choices[0].message.content.strip()
29
+ except Exception as e:
30
+ return f"Error: {e}"
31
+
32
+ def get_agriculture_response(input_text):
33
+ try:
34
+ detailed_response = client.chat.completions.create(
35
+ model="llama-3.1-8b-instant",
36
+ messages=[
37
+ {"role": "system", "content": "You are a helpful assistant."},
38
+ {"role": "user", "content": RESPONSE_PROMPT},
39
+ {"role": "user", "content": input_text},
40
+ ],
41
+ temperature=0.5,
42
+ max_completion_tokens=700,
43
+ )
44
+ return detailed_response.choices[0].message.content.strip()
45
+ except Exception as e:
46
+ return f"Error: {e}"
47
+
48
+ def groq_chatbot(input_text, chat_history):
49
+ validation_result = validate_input(input_text)
50
+
51
+ if validation_result.lower() == "yes":
52
+ response = get_agriculture_response(input_text)
53
+ elif validation_result.lower() == "no":
54
+ response = "❌ This is not an agriculture-related question."
55
+ else:
56
+ response = f"⚠️ Unexpected response: {validation_result}"
57
+
58
+ # Append to chat history
59
+ chat_history.append((input_text, response))
60
+ return chat_history, "" # Clears input field after submission
61
+
62
+ def launch_gradio_interface():
63
+ with gr.Blocks() as demo:
64
+ gr.Markdown("### 🌱 Agriculture AI Assistant")
65
+ gr.Markdown("Ask questions about plant diseases, treatments, or general agricultural topics.")
66
+
67
+ chatbot = gr.Chatbot(height=400)
68
+ msg = gr.Textbox(placeholder="Ask a question about agriculture...", label="Your Question")
69
+ clear = gr.Button("Clear Chat")
70
+
71
+ chat_history_state = gr.State([]) # Stores chat history
72
+
73
+ # ✅ Enter key submits the question
74
+ msg.submit(fn=groq_chatbot, inputs=[msg, chat_history_state], outputs=[chatbot, msg])
75
+
76
+ # ✅ Clicking "Clear Chat" resets history
77
+ clear.click(lambda: ([], ""), None, [chatbot, msg], queue=False)
78
+
79
+ demo.launch(share=True)
80
+
81
+ if __name__ == "__main__":
82
+ launch_gradio_interface()
class_labels.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "0": "Apple - Apple Scab",
3
+ "1": "Apple - Black Rot",
4
+ "2": "Apple - Cedar Apple Rust",
5
+ "3": "Apple - Healthy",
6
+ "4": "Background without Leaves",
7
+ "5": "Blueberry - Healthy",
8
+ "6": "Cherry - Powdery Mildew",
9
+ "7": "Cherry - Healthy",
10
+ "8": "Corn - Cercospora Leaf Spot (Gray Leaf Spot)",
11
+ "9": "Corn - Common Rust",
12
+ "10": "Corn - Northern Leaf Blight",
13
+ "11": "Corn - Healthy",
14
+ "12": "Grape - Black Rot",
15
+ "13": "Grape - Esca (Black Measles)",
16
+ "14": "Grape - Leaf Blight (Isariopsis Leaf Spot)",
17
+ "15": "Grape - Healthy",
18
+ "16": "Orange - Huanglongbing (Citrus Greening)",
19
+ "17": "Peach - Bacterial Spot",
20
+ "18": "Peach - Healthy",
21
+ "19": "Pepper (Bell) - Bacterial Spot",
22
+ "20": "Pepper (Bell) - Healthy",
23
+ "21": "Potato - Early Blight",
24
+ "22": "Potato - Late Blight",
25
+ "23": "Potato - Healthy",
26
+ "24": "Raspberry - Healthy",
27
+ "25": "Soybean - Healthy",
28
+ "26": "Squash - Powdery Mildew",
29
+ "27": "Strawberry - Leaf Scorch",
30
+ "28": "Strawberry - Healthy",
31
+ "29": "Tomato - Bacterial Spot",
32
+ "30": "Tomato - Early Blight",
33
+ "31": "Tomato - Late Blight",
34
+ "32": "Tomato - Leaf Mold",
35
+ "33": "Tomato - Septoria Leaf Spot",
36
+ "34": "Tomato - Spider Mites (Two-Spotted Spider Mite)",
37
+ "35": "Tomato - Target Spot",
38
+ "36": "Tomato - Tomato Yellow Leaf Curl Virus",
39
+ "37": "Tomato - Tomato Mosaic Virus",
40
+ "38": "Tomato - Healthy"
41
+ }
classification.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
detection.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
images/classification/graph.png ADDED
images/detection/fitting.png ADDED
images/detection/loading.png ADDED
model_loader.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import tensorflow as tf
3
+ import numpy as np
4
+ import cv2
5
+ import logging
6
+
7
+ # Setup logging
8
+ logging.basicConfig(level=logging.DEBUG)
9
+ logger = logging.getLogger(__name__)
10
+
11
+ def load_model(model_path):
12
+ """
13
+ Load the MobileNetV2 model from the specified path
14
+
15
+ Args:
16
+ model_path: Path to the .h5 model file
17
+
18
+ Returns:
19
+ Loaded TensorFlow model
20
+ """
21
+ try:
22
+ logger.info(f"Loading model from {model_path}")
23
+ model = tf.keras.models.load_model(model_path)
24
+ logger.info("Model loaded successfully")
25
+ return model
26
+ except Exception as e:
27
+ logger.error(f"Error loading model: {str(e)}")
28
+ raise
29
+
30
+ def preprocess_image(image, target_size=(224, 224)):
31
+ """
32
+ Preprocess the image for model input
33
+
34
+ Args:
35
+ image: Input image (numpy array from OpenCV)
36
+ target_size: Target size for model input (default: 224x224)
37
+
38
+ Returns:
39
+ Preprocessed image ready for model input
40
+ """
41
+ try:
42
+ # Convert BGR to RGB if from OpenCV
43
+ if len(image.shape) == 3 and image.shape[2] == 3:
44
+ image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
45
+
46
+ # Resize image
47
+ image_resized = cv2.resize(image, target_size)
48
+
49
+ # Convert to float and normalize
50
+ image_normalized = image_resized.astype(np.float32) / 255.0
51
+
52
+ # Expand dimensions to create batch
53
+ image_batch = np.expand_dims(image_normalized, axis=0)
54
+
55
+ return image_batch
56
+ except Exception as e:
57
+ logger.error(f"Error preprocessing image: {str(e)}")
58
+ raise
59
+
60
+ def predict_disease(model, preprocessed_image, class_labels):
61
+ """
62
+ Predict disease from preprocessed image
63
+
64
+ Args:
65
+ model: Loaded TensorFlow model
66
+ preprocessed_image: Preprocessed image batch
67
+ class_labels: Dictionary mapping class indices to labels
68
+
69
+ Returns:
70
+ Tuple of (predicted disease label, confidence percentage)
71
+ """
72
+ try:
73
+ # Make prediction
74
+ predictions = model.predict(preprocessed_image)
75
+
76
+ # Get the predicted class index
77
+ predicted_class_idx = np.argmax(predictions[0])
78
+
79
+ # Get confidence score
80
+ confidence = float(predictions[0][predicted_class_idx] * 100)
81
+
82
+ # Convert to label
83
+ label = class_labels.get(str(predicted_class_idx), f"Unknown class {predicted_class_idx}")
84
+
85
+ return label, confidence
86
+ except Exception as e:
87
+ logger.error(f"Error making prediction: {str(e)}")
88
+ raise
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ tensorflow==2.15.0
2
+ numpy>=1.22.0
3
+ pillow>=10.0.0
4
+ gradio>=4.0.0
5
+ groq
6
+ opencv-python
7
+ opencv-python-headless
8
+ bing_image_downloader
9
+ python-dotenv
style.css ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ font-family: 'Arial', sans-serif;
3
+ background-color: #1e1e1e;
4
+ color: white;
5
+ }
6
+
7
+ #title {
8
+ margin-bottom: 20px;
9
+ }
10
+
11
+ #input-box textarea {
12
+ background-color: #2c2c2c !important;
13
+ color: white;
14
+ border-radius: 10px;
15
+ font-size: 16px;
16
+ }
17
+
18
+ #validate-button {
19
+ background-color: #4CAF50 !important;
20
+ color: white;
21
+ font-size: 18px;
22
+ border-radius: 8px;
23
+ padding: 10px 15px;
24
+ }
25
+
26
+ #validation-result, #output-box {
27
+ background-color: #2c2c2c !important;
28
+ color: white;
29
+ font-size: 16px;
30
+ border-radius: 8px;
31
+ padding: 10px;
32
+ }
utils.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ import logging
3
+ from difflib import get_close_matches
4
+
5
+ # Setup logging
6
+ logging.basicConfig(level=logging.DEBUG)
7
+ logger = logging.getLogger(__name__)
8
+
9
+ def extract_disease_name(prediction):
10
+ """
11
+ Extract just the disease name from a prediction that might include plant name
12
+
13
+ Args:
14
+ prediction: Full prediction string (e.g., "Tomato_Late_blight")
15
+
16
+ Returns:
17
+ Extracted disease name
18
+ """
19
+ try:
20
+ # Handle common formats like "Plant_Disease" or "Plant Disease"
21
+ if '_' in prediction:
22
+ parts = prediction.split('_')
23
+ else:
24
+ parts = prediction.split(' ')
25
+
26
+ if len(parts) <= 1:
27
+ return prediction # Return as is if can't split
28
+
29
+ # Skip the plant name (first part) and join the rest
30
+ disease_parts = parts[1:]
31
+ disease_name = ' '.join(disease_parts)
32
+
33
+ # Clean up the disease name
34
+ disease_name = disease_name.replace('_', ' ').strip()
35
+
36
+ return disease_name
37
+ except Exception as e:
38
+ logger.error(f"Error extracting disease name: {str(e)}")
39
+ return prediction # Return original on error
40
+
41
+ def normalize_disease_name(disease_name):
42
+ """
43
+ Normalize disease names for better matching
44
+
45
+ Args:
46
+ disease_name: Disease name to normalize
47
+
48
+ Returns:
49
+ Normalized disease name
50
+ """
51
+ # Convert to lowercase
52
+ normalized = disease_name.lower()
53
+
54
+ # Remove special characters
55
+ normalized = re.sub(r'[^a-z0-9\s]', '', normalized)
56
+
57
+ # Replace multiple spaces with single space
58
+ normalized = re.sub(r'\s+', ' ', normalized).strip()
59
+
60
+ return normalized
61
+
62
+ def find_similar_disease(disease_name, known_diseases):
63
+ """
64
+ Find the most similar disease name in a list of known diseases
65
+
66
+ Args:
67
+ disease_name: Query disease name
68
+ known_diseases: List of known disease names
69
+
70
+ Returns:
71
+ Most similar disease name, or the original if no good match
72
+ """
73
+ # Normalize the query
74
+ norm_query = normalize_disease_name(disease_name)
75
+
76
+ # Normalize all known diseases
77
+ norm_known = [normalize_disease_name(d) for d in known_diseases]
78
+
79
+ # Find close matches
80
+ matches = get_close_matches(norm_query, norm_known, n=1, cutoff=0.6)
81
+
82
+ if matches:
83
+ # Get the index of the match in the normalized list
84
+ match_idx = norm_known.index(matches[0])
85
+ # Return the original form of the matched disease
86
+ return known_diseases[match_idx]
87
+
88
+ return disease_name # Return original if no good matches