import os
import gradio as gr
import re
from fastai.vision.all import *
from groq import Groq
from PIL import Image
# Load the trained model for grapevine disease classification
learn = load_learner('export.pkl') # Assumes you have a trained model for grapevine diseases
labels = learn.dls.vocab
# Initialize Groq client
client = Groq(
api_key=os.environ.get("GROQ_API_KEY"),
)
# Your existing functions remain the same
def clean_disease_name(name):
"""Clean disease name by removing numbers and special characters, and fix formatting"""
# Remove numbers and dots at the beginning
cleaned = re.sub(r'^\d+\.', '', name)
# Replace underscores with spaces
cleaned = cleaned.replace('_', ' ')
# Remove any remaining special characters
cleaned = re.sub(r'[^\w\s]', '', cleaned)
# Fix spacing
cleaned = ' '.join(cleaned.split())
return cleaned
def format_disease_info(raw_info):
"""Improve the formatting of disease information"""
# Add proper line breaks between sections and ensure consistent heading levels
formatted = raw_info
# Replace markdown headings with HTML headings for better control
formatted = re.sub(r'#+\s+(.*)', r'
\1
', formatted)
# Add paragraph tags for better spacing
formatted = re.sub(r'\n\*\s+(.*)', r'• \1
', formatted)
formatted = re.sub(r'\n([^<\n].*)', r'\1
', formatted)
# Remove any duplicate paragraph tags
formatted = formatted.replace('', '
')
formatted = formatted.replace('
', '')
return formatted
def get_disease_treatment(disease_name, language="swahili"):
"""Get direct treatment measures for the disease"""
clean_name = clean_disease_name(disease_name)
# Return healthy message if the prediction is healthy
if clean_name.lower() == "healthy" or "healthy" in clean_name.lower():
if language.lower() == "swahili":
return """
### Hali ya Jani: Afya nzuri
Jani hili liko katika hali nzuri ya afya. Hakuna dalili za magonjwa zinazoonekana. Endelea kutunza mizabibu yako vizuri kwa:
• Kumwagilia maji ipasavyo
• Kuhakikisha rutuba ya udongo
• Kupunguza matawi kwa usahihi
• Kufuatilia mara kwa mara kwa dalili za magonjwa
• Kudumisha hewa nzuri kuzunguka mmea
"""
else:
return """
### Leaf Status: Healthy
This leaf is in a healthy state. No signs of disease are present. Continue to maintain your vines by:
• Proper irrigation
• Ensuring soil fertility
• Appropriate pruning
• Regular monitoring for disease symptoms
• Maintaining good air circulation around the plant
"""
prompt = f"""
Provide a concise, practical list of DIRECT treatment measures for {clean_name} disease in grapevines.
Format your response as a bulleted list with 5-7 specific actions a vineyard manager should take IMMEDIATELY to treat the disease.
For each treatment measure:
1. Start with an action verb
2. Be specific about products/techniques to use
3. Include application rates/timing when relevant
The response should be in {"Swahili" if language.lower() == "swahili" else "English"}.
Begin with a short title: "HATUA ZA MATIBABU:" (if Swahili) or "TREATMENT MEASURES:" (if English)
"""
try:
chat_completion = client.chat.completions.create(
messages=[
{
"role": "user",
"content": prompt,
}
],
model="llama-3.3-70b-versatile",
)
return chat_completion.choices[0].message.content
except Exception as e:
error_msg = "Hitilafu kupata taarifa za matibabu" if language.lower() == "swahili" else "Error fetching treatment information"
return f"{error_msg}: {str(e)}"
def get_disease_info(disease_name, language="swahili"):
"""Get detailed information about a grapevine disease using Groq API"""
clean_name = clean_disease_name(disease_name)
# Return healthy message if the prediction is healthy
if clean_name.lower() == "healthy" or "healthy" in clean_name.lower():
if language.lower() == "swahili":
return """
# Hali ya Jani: Afya nzuri
Jani hili liko katika hali nzuri ya afya. Hakuna dalili za magonjwa zinazoonekana. Hii ni ishara nzuri kwamba:
- Mizabibu yako inapata virutubisho vya kutosha
- Umwagiliaji wa maji uko katika kiasi cha kutosha
- Hali ya hewa katika shamba lako ni nzuri
- Hakuna mashambulizi ya wadudu waharibifu
Endelea kudumisha utunzaji mzuri wa mizabibu yako ili kuhakikisha uzalishaji bora wa zabibu.
"""
else:
return """
# Leaf Status: Healthy
This leaf is in a healthy state. No signs of disease are present. This is a good indication that:
- Your vines are receiving adequate nutrition
- Irrigation levels are appropriate
- Climate conditions in your vineyard are favorable
- There are no pest invasions
Continue to maintain good vineyard practices to ensure optimal grape production.
"""
lang = "SWAHILI" if language.lower() == "swahili" else "ENGLISH"
prompt = f"""
Provide detailed information IN {lang} about {clean_name} disease in grapevines.
Structure your response like this:
1. A brief introduction about what this disease is (1-2 sentences)
2. Main symptoms and how to identify the disease (short paragraph)
3. FOCUS EXTENSIVELY on the treatment methods and prevention strategies (this should be the longest section)
4. Conclusion with practical advice for vineyard managers
Format your response in markdown for better readability.
Make sure the entire response is in {lang}.
"""
try:
chat_completion = client.chat.completions.create(
messages=[
{
"role": "user",
"content": prompt,
}
],
model="llama-3.3-70b-versatile",
)
return chat_completion.choices[0].message.content
except Exception as e:
error_msg = "Hitilafu kupata taarifa" if language.lower() == "swahili" else "Error fetching information"
return f"{error_msg}: {str(e)}"
def predict_and_get_info(img, language="swahili"):
"""Predict grapevine disease and get detailed information"""
# Process the image
img = PILImage.create(img)
# Get prediction
pred, pred_idx, probs = learn.predict(img)
# Get top 5 predictions (or all if less than 5)
num_classes = min(5, len(labels))
top_indices = probs.argsort(descending=True)[:num_classes]
top_probs = probs[top_indices]
top_labels = [labels[i] for i in top_indices]
# Format as dictionary with cleaned names for display
prediction_results = {clean_disease_name(top_labels[i]): float(top_probs[i]) for i in range(num_classes)}
# Get top prediction (original format for info retrieval)
top_disease = str(pred)
# Also keep a clean version for display
clean_top_disease = clean_disease_name(top_disease)
# Check if healthy
is_healthy = clean_top_disease.lower() == "healthy" or "healthy" in clean_top_disease.lower()
# Get detailed information about the top predicted disease
disease_info = get_disease_info(top_disease, language)
formatted_info = format_disease_info(disease_info)
# Get direct treatment measures
treatment_measures = get_disease_treatment(top_disease, language)
formatted_treatment = format_disease_info(treatment_measures)
# Create title text based on language and health status
if language.lower() == "swahili":
title_text = "Jani Zuri na Afya Njema" if is_healthy else f"Ugonjwa: {clean_top_disease}"
advice_title = "Ushauri wa Haraka kwa Wakulima"
advice_text = "Kumbuka: Fuata maelekezo ya kitaalamu na tumia dawa zilizoidhinishwa tu. Wasiliana na mtaalamu wa kilimo kwa ushauri zaidi."
treatment_title = "Hatua za Matibabu"
else:
title_text = "Healthy Leaf" if is_healthy else f"Disease: {clean_top_disease}"
advice_title = "Quick Advice for Vineyard Managers"
advice_text = "Remember: Follow professional instructions and use only approved treatments. Contact an agricultural expert for more advice."
treatment_title = "Treatment Measures"
# Create well-formatted display with improved fonts and styling
custom_css = """
"""
# Healthy banner HTML if needed
healthy_banner = ""
if is_healthy:
if language.lower() == "swahili":
healthy_banner = '✓ Jani hili liko katika hali nzuri ya afya
'
else:
healthy_banner = '✓ This leaf is in a healthy state
'
combined_info = f"""
{custom_css}
{title_text}
{healthy_banner}
{formatted_info}
{treatment_title}
{formatted_treatment}
{advice_title}
{advice_text}
"""
return prediction_results, combined_info, clean_top_disease
def follow_up_question(question, disease_name, language="swahili"):
"""Allow vineyard managers to ask follow-up questions about the identified disease"""
if not question.strip() or not disease_name:
return "Tafadhali tambua ugonjwa wa mizabibu kwanza na uulize swali mahususi kuuhusu." if language.lower() == "swahili" else "Please identify a grapevine disease first and ask a specific question about it."
lang = "SWAHILI" if language.lower() == "swahili" else "ENGLISH"
prompt = f"""
The vineyard manager is asking about {disease_name} disease: "{question}"
Provide a detailed answer IN {lang}, focusing on accurate plant pathology information.
If the question relates to treatment options, preventive measures, or climate change impacts, emphasize those aspects in your response.
IMPORTANT:
- Do not repeat basic introductory information about the disease that would have already been provided
- Directly answer the specific question asked
- The entire response must be in {lang}
- Focus on practical advice whenever possible
Format your response in markdown for better readability.
"""
try:
chat_completion = client.chat.completions.create(
messages=[
{
"role": "user",
"content": prompt,
}
],
model="llama-3.3-70b-versatile",
)
return chat_completion.choices[0].message.content
except Exception as e:
error_msg = "Hitilafu kupata taarifa" if language.lower() == "swahili" else "Error fetching information"
return f"{error_msg}: {str(e)}"
# Enhanced CSS for styling the improved language toggle
toggle_css = """
"""
# Create the Gradio interface
with gr.Blocks(theme=gr.themes.Soft(), css=toggle_css) as app:
# State for current language
current_language = gr.State("swahili")
# Create language-specific text dictionary
text_dict = {
"swahili": {
"title": "# Kitambulisho cha Magonjwa ya Mizabibu",
"subtitle": "Pakia picha ili kutambua magonjwa ya mizabibu na kupata taarifa za kina kuhusu mikakati ya udhibiti na chaguo za matibabu.",
"upload_label": "Pakia Picha ya Mizabibu",
"identify_btn": "Tambua Ugonjwa",
"prediction_label": "Utabiri wa Juu 5",
"disease_info_label": "Maelezo ya Ugonjwa",
"followup_title": "## Maswali ya Ufuatiliaji",
"question_label": "Uliza swali kuhusu ugonjwa huu",
"question_placeholder": "Mfano: Je, ni hatua gani bora za kuzuia ugonjwa huu?",
"submit_btn": "Wasilisha Swali",
"clear_btn": "Futa Mazungumzo",
"toggle_label": "Lugha:",
"error_no_image": "Tafadhali pakia picha",
"error_processing": "Hitilafu katika kuchakata picha"
},
"english": {
"title": "# Grapevine Disease Identification Tool",
"subtitle": "Upload an image to identify grapevine diseases and get detailed information on management strategies and treatment options.",
"upload_label": "Upload Grapevine Image",
"identify_btn": "Identify Disease",
"prediction_label": "Top 5 Predictions",
"disease_info_label": "Disease Information",
"followup_title": "## Follow-up Questions",
"question_label": "Ask a question about this disease",
"question_placeholder": "Example: What are the best preventative measures for this disease?",
"submit_btn": "Submit Question",
"clear_btn": "Clear Conversation",
"toggle_label": "Language:",
"error_no_image": "Please upload an image",
"error_processing": "Error processing image"
}
}
# UI Elements with default language
title_md = gr.Markdown(text_dict["swahili"]["title"], elem_classes="language-transition")
subtitle_md = gr.Markdown(text_dict["swahili"]["subtitle"], elem_classes="language-transition")
# Store the current disease for context
current_disease = gr.State("")
# Add improved language toggle at the top
with gr.Row(elem_classes="language-toggle-container"):
toggle_label = gr.Markdown(text_dict["swahili"]["toggle_label"], elem_classes="toggle-label language-transition")
# Custom HTML for flag icons
flag_html = gr.HTML("""
""")
with gr.Column(elem_classes="language-switcher", scale=1):
language_toggle = gr.Radio(
["Swahili", "English"],
value="Swahili",
label="",
interactive=True,
elem_id="language-toggle"
)
# Main identification section
with gr.Row():
with gr.Column(scale=1):
input_image = gr.Image(type="pil", label=text_dict["swahili"]["upload_label"], elem_classes="language-transition")
submit_btn = gr.Button(text_dict["swahili"]["identify_btn"], variant="primary", elem_classes="language-transition")
with gr.Column(scale=2):
prediction_output = gr.Label(label=text_dict["swahili"]["prediction_label"], num_top_classes=5, elem_classes="language-transition")
disease_info_output = gr.HTML(label=text_dict["swahili"]["disease_info_label"], elem_classes="language-transition")
# Clear divider
gr.Markdown("---")
# Follow-up question section with improved UI
followup_title_md = gr.Markdown(text_dict["swahili"]["followup_title"], elem_classes="language-transition")
conversation_history = gr.Markdown("", elem_classes="language-transition")
with gr.Row():
follow_up_input = gr.Textbox(
label=text_dict["swahili"]["question_label"],
placeholder=text_dict["swahili"]["question_placeholder"],
lines=2,
elem_classes="language-transition"
)
with gr.Row():
follow_up_btn = gr.Button(text_dict["swahili"]["submit_btn"], variant="primary", elem_classes="language-transition")
clear_btn = gr.Button(text_dict["swahili"]["clear_btn"], elem_classes="language-transition")
# Enhanced function to switch language based on toggle
def switch_language(selected_language, current_lang):
# Map the radio value to our language code
new_lang = "swahili" if selected_language == "Swahili" else "english"
# If language hasn't changed, don't update anything
if new_lang == current_lang:
return [current_lang] + [gr.update() for _ in range(11)]
# Debug message to verify the language switch
print(f"Switching language from {current_lang} to {new_lang}")
# Add custom JavaScript for smooth transition animation
js = """
document.querySelectorAll('.language-transition').forEach(el => {
el.style.opacity = 0;
setTimeout(() => { el.style.opacity = 1; }, 300);
});
"""
# Return updated values
return (
new_lang,
text_dict[new_lang]["title"],
text_dict[new_lang]["subtitle"],
text_dict[new_lang]["followup_title"],
gr.update(label=text_dict[new_lang]["upload_label"]),
text_dict[new_lang]["identify_btn"],
gr.update(label=text_dict[new_lang]["prediction_label"]),
gr.update(label=text_dict[new_lang]["disease_info_label"]),
gr.update(label=text_dict[new_lang]["question_label"], placeholder=text_dict[new_lang]["question_placeholder"]),
text_dict[new_lang]["submit_btn"],
text_dict[new_lang]["clear_btn"],
text_dict[new_lang]["toggle_label"]
)
# Set up event handlers
def process_image(img, lang):
if img is None:
return None, text_dict[lang]["error_no_image"], "", ""
try:
# Print debug message to verify language
print(f"Processing image with language: {lang}")
pred_results, info, clean_disease_name = predict_and_get_info(img, lang)
return pred_results, info, clean_disease_name, ""
except Exception as e:
return None, f"{text_dict[lang]['error_processing']}: {str(e)}", "", ""
def update_conversation(question, disease_name, history, lang):
if not question.strip():
return history
answer = follow_up_question(question, disease_name, lang)
# Format the conversation with clear separation
question_label = "Swali:" if lang == "swahili" else "Question:"
answer_label = "Jibu:" if lang == "swahili" else "Answer:"
new_exchange = f"""
### {question_label}
{question}
### {answer_label}
{answer}
---
"""
updated_history = new_exchange + history
return updated_history
def clear_conversation_history():
return ""
# Connect the language toggle with enhanced functionality
language_toggle.change(
switch_language,
inputs=[language_toggle, current_language],
outputs=[
current_language,
title_md,
subtitle_md,
followup_title_md,
input_image,
submit_btn,
prediction_output,
disease_info_output,
follow_up_input,
follow_up_btn,
clear_btn,
toggle_label
]
)
submit_btn.click(
process_image,
inputs=[input_image, current_language],
outputs=[prediction_output, disease_info_output, current_disease, conversation_history]
)
follow_up_btn.click(
update_conversation,
inputs=[follow_up_input, current_disease, conversation_history, current_language],
outputs=[conversation_history]
).then(
lambda: "",
outputs=follow_up_input
)
clear_btn.click(
clear_conversation_history,
outputs=[conversation_history]
)
# Launch the app
app.launch(share=True)odel
model_path = "export.pkl" # Change to "grapevine_model.pt" if converted
learner = load_learner(model_path)
# Dictionary of disease descriptions and treatments
disease_info = {
"Powdery Mildew": {
"description": "A fungal disease causing white, powdery spots on leaves and fruit.",
"treatment": "Apply sulfur-based fungicides. Improve air circulation by pruning."
},
"Downy Mildew": {
"description": "Yellow spots on leaves that turn brown and cause defoliation.",
"treatment": "Use copper-based fungicides. Avoid overhead watering."
},
"Black Rot": {
"description": "Causes black spots on leaves and shriveled grapes.",
"treatment": "Remove infected leaves and fruit. Use fungicides containing myclobutanil."
},
"Botrytis Bunch Rot": {
"description": "Gray mold on grape clusters, often in humid conditions.",
"treatment": "Ensure good air circulation. Apply biological fungicides like Bacillus subtilis."
},
"Healthy": {
"description": "Your grapevine appears to be healthy!",
"treatment": "Continue regular monitoring and proper care."
}
}
# Define prediction function
def predict(img):
img = Image.fromarray(img) # Convert NumPy array to PIL image
pred, _, probs = learner.predict(img)
disease = str(pred)
# Get disease details
info = disease_info.get(disease, {"description": "Unknown disease", "treatment": "Consult an expert."})
return {
"Disease": disease,
"Description": info["description"],
"Treatment": info["treatment"]
}
# Create Gradio interface
iface = gr.Interface(
fn=predict,
inputs=gr.Image(type="numpy"),
outputs=[
gr.Label(label="Disease"),
gr.Textbox(label="Description"),
gr.Textbox(label="Treatment")
],
title="Grapevine Disease Detection",
description="Upload an image of a grapevine leaf to identify the disease and receive treatment recommendations."
)
# Launch the app
if __name__ == "__main__":
iface.launch()