MultiAgenticAI / app.py
Chaitanya895's picture
Update app.py
88eb45d verified
raw
history blame
135 kB
import streamlit as st
st.set_page_config(page_title="Sustainable Farming Recommendation System", page_icon="🌾")
import sys
import os
import shutil
from pathlib import Path
import sqlite3
import pandas as pd
from datetime import datetime
from agents.init_db import initialize_db
import plotly.graph_objects as go
from PIL import Image
import numpy as np
import re
import base64
import io
import time
import json
import folium
try:
from streamlit_folium import st_folium
except Exception:
# Graceful fallback if streamlit-folium is not available in the environment
def st_folium(*args, **kwargs):
st.warning("streamlit-folium is not installed. Maps are disabled. Install it to enable map features.")
return {}
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Reduce model/cache footprint in hosted environments (e.g., Hugging Face)
# Route large caches to ephemeral /tmp and disable telemetry
os.environ.setdefault('TRANSFORMERS_CACHE', '/tmp/transformers')
os.environ.setdefault('HF_HOME', '/tmp/hf')
os.environ.setdefault('HF_HUB_DISABLE_TELEMETRY', '1')
os.environ.setdefault('HF_HUB_ENABLE_HF_TRANSFER', '0')
def clear_runtime_caches():
"""Delete common ML caches to free disk space at runtime."""
cache_dirs = [
Path.home() / '.cache' / 'huggingface',
Path.home() / '.cache' / 'torch',
Path('/tmp/transformers'),
Path('/tmp/hf')
]
cleared = []
for d in cache_dirs:
try:
if d.exists():
shutil.rmtree(d, ignore_errors=True)
cleared.append(str(d))
except Exception:
pass
return cleared
# Import speech interface at the top level
try:
from models.speech_interface import SpeechInterface
except ImportError as e:
st.error(f"Could not import SpeechInterface: {e}")
SpeechInterface = None
# --- Multilingual Support ---
LANGUAGES = {
'English': {
'title': "Sustainable Farming Recommendation System",
'farm_details': "📏 Farm Details",
'crop_preference': "🌱 Crop Preference",
'soil_analysis': "🗺️ Soil Analysis",
'upload_photo': "📸 Upload a photo",
'manual_selection': "📝 Manual selection",
'select_soil_type': "Select soil type",
'generate_recommendation': "💡 Generate Smart Recommendation",
'personalized_recommendation': "### 🎯 Your Personalized Recommendation",
'weather_forecast': "#### 🌤️ Weather Forecast (AI Model)",
'pest_prediction': "#### 🐛 Pest/Disease Prediction (AI Model)",
'details': "Details:",
'crop_rotation_planner': "🌱 Crop Rotation Planner",
'fertilizer_optimization': "🧪 Fertilizer Optimization Calculator",
'previous_recommendations': "📜 Previous Recommendations",
'built_with': "Built with ❤️ for sustainable farming",
'last_updated': "Last updated: ",
'signup_title': "🌾 Join the Farming Community",
'login_title': "🌾 Welcome Back",
'username': "👤 Farmer Name",
'farm_name': "🏡 Farm Name",
'profile_picture': "📷 Profile Picture (Optional)",
'signup_button': "✅ Join Now",
'login_button': "✅ Login",
'signup_instruction': "Fill in your details to get started!",
'login_instruction': "Select your farmer profile to continue.",
'no_account': "No account yet? Sign up!",
'signup_success': "Welcome, {username}! Your account is created.",
'login_success': "Welcome back, {username}!",
'username_exists': "⚠️ Farmer name already taken. Try another.",
'no_users': "No farmers registered yet. Sign up to start!"
},
'Telugu': {
'title': "సస్టైనబుల్ వ్యవసాయ సూచన వ్యవస్థ",
'farm_details': "📏 వ్యవసాయ వివరాలు",
'crop_preference': "🌱 పంట ప్రాధాన్యత",
'soil_analysis': "🗺️ నేల విశ్లేషణ",
'upload_photo': "📸 ఫోటోను అప్‌లోడ్ చేయండి",
'manual_selection': "📝 మాన్యువల్ ఎంపిక",
'select_soil_type': "నేల రకాన్ని ఎంచుకోండి",
'generate_recommendation': "💡 స్మార్ట్ సూచనను రూపొందించండి",
'personalized_recommendation': "### 🎯 మీ వ్యక్తిగత సూచన",
'weather_forecast': "#### 🌤️ వాతావరణ సూచన (AI మోడల్)",
'pest_prediction': "#### 🐛 తెగులు/పురుగు సూచన (AI మోడల్)",
'details': "వివరాలు:",
'crop_rotation_planner': "🌱 పంట మార్పిడి ప్రణాళిక",
'fertilizer_optimization': "🧪 ఎరువు ఆప్టిమైజేషన్ కాలిక్యులేటర్",
'previous_recommendations': "📜 గత సూచనలు",
'built_with': "సస్టైనబుల్ వ్యవసాయం కోసం ప్రేమతో నిర్మించబడింది",
'last_updated': "చివరిగా నవీకరించబడింది: ",
'signup_title': "🌾 వ్యవసాయ సమాజంలో చేరండి",
'login_title': "🌾 తిరిగి స్వాగతం",
'username': "👤 రైతు పేరు",
'farm_name': "🏡 వ్యవసాయం పేరు",
'profile_picture': "📷 ప్రొఫైల్ చిత్రం (ఐచ్ఛికం)",
'signup_button': "✅ ఇప్పుడు చేరండి",
'login_button': "✅ లాగిన్",
'signup_instruction': "మీ వివరాలను నమోదు చేయండి!",
'login_instruction': "మీ రైతు ప్రొఫైల్‌ను ఎంచుకోండి.",
'no_account': "ఇంకా ఖాతా లేదా? సైన్ అప్ చేయండి!",
'signup_success': "స్వాగతం, {username}! మీ ఖాతా సృష్టించబడింది.",
'login_success': "తిరిగి స్వాగతం, {username}!",
'username_exists': "⚠️ రైతు పేరు ఇప్పటికే తీసుకోబడింది. వేరొకటి ప్రయత్నించండి.",
'no_users': "ఇంకా రైతులు నమోదు కాలేదు. సైన్ అప్ చేయండి!"
},
'Kannada': {
'title': "ಸ್ಥಿರ ಕೃಷಿ ಶಿಫಾರಸು ವ್ಯವಸ್ಥೆ",
'farm_details': "📏 ಕೃಷಿ ವಿವರಗಳು",
'crop_preference': "🌱 ಬೆಳೆ ಆದ್ಯತೆ",
'soil_analysis': "🗺️ ಮಣ್ಣು ವಿಶ್ಲೇಷಣೆ",
'upload_photo': "📸 ಫೋಟೋ ಅಪ್‌ಲೋಡ್ ಮಾಡಿ",
'manual_selection': "📝 ಕೈಯಾರೆ ಆಯ್ಕೆ",
'select_soil_type': "ಮಣ್ಣಿನ ಪ್ರಕಾರವನ್ನು ಆಯ್ಕೆಮಾಡಿ",
'generate_recommendation': "💡 ಸ್ಮಾರ್ಟ್ ಶಿಫಾರಸು ರಚಿಸಿ",
'personalized_recommendation': "### 🎯 ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಶಿಫಾರಸು",
'weather_forecast': "#### 🌤️ ಹವಾಮಾನ ಮುನ್ಸೂಚನೆ (AI ಮಾದರಿ)",
'pest_prediction': "#### 🐛 ಕೀಟ/ರೋಗ ಮುನ್ಸೂಚನೆ (AI ಮಾದರಿ)",
'details': "ವಿವರಗಳು:",
'crop_rotation_planner': "🌱 ಬೆಳೆ ಪರಿವರ್ತನೆ ಯೋಜನೆ",
'fertilizer_optimization': "🧪 ರಸಗೊಬ್ಬರ ಆಪ್ಟಿಮೈಸೇಶನ್ ಕ್ಯಾಲ್ಕ್ಯುಲೇಟರ್",
'previous_recommendations': "📜 ಹಿಂದಿನ ಶಿಫಾರಸುಗಳು",
'built_with': "ಸ್ಥಿರ ಕೃಷಿಗಾಗಿ ಪ್ರೀತಿಯಿಂದ ನಿರ್ಮಿಸಲಾಗಿದೆ",
'last_updated': "ಕೊನೆಯದಾಗಿ ನವೀಕರಿಸಲಾಗಿದೆ: ",
'signup_title': "🌾 ಕೃಷಿ ಸಮುದಾಯಕ್ಕೆ ಸೇರಿಕೊಳ್ಳಿ",
'login_title': "🌾 ಮತ್ತೆ ಸ್ವಾಗತ",
'username': "👤 ರೈತನ ಹೆಸರು",
'farm_name': "🏡 ಕೃಷಿ ಹೆಸರು",
'profile_picture': "📷 ಪ್ರೊಫೈಲ್ ಚಿತ್ರ (ಐಚ್ಛಿಕ)",
'signup_button': "✅ ಈಗ ಸೇರಿಕೊಳ್ಳಿ",
'login_button': "✅ ಲಾಗಿನ್",
'signup_instruction': "ಪ್ರಾರಂಭಿಸಲು ನಿಮ್ಮ ವಿವರಗಳನ್ನು ಭರ್ತಿ ಮಾಡಿ!",
'login_instruction': "ಮುಂದುವರಿಯಲು ನಿಮ್ಮ ರೈತ ಪ್ರೊಫೈಲ್ ಆಯ್ಕೆಮಾಡಿ.",
'no_account': "ಇನ್ನೂ ಖಾತೆ ಇಲ್ಲವೇ? ಸೈನ್ ಅಪ್ ಮಾಡಿ!",
'signup_success': "ಸ್ವಾಗತ, {username}! ನಿಮ್ಮ ಖಾತೆ ರಚಿಸಲಾಗಿದೆ.",
'login_success': "ಮತ್ತೆ ಸ್ವಾಗತ, {username}!",
'username_exists': "⚠️ ರೈತನ ಹೆಸರು ಈಗಾಗಲೇ ತೆಗೆದುಕೊಳ್ಳಲಾಗಿದೆ. ಬೇರೆಯೊಂದನ್ನು ಪ್ರಯತ್ನಿಸಿ.",
'no_users': "ಇನ್ನೂ ರೈತರು ನೋಂದಾಯಿಸಿಲ್ಲ. ಪ್ರಾರಂಭಿಸಲು ಸೈನ್ ಅಪ್ ಮಾಡಿ!"
},
'Hindi': {
'title': "सस्टेनेबल फार्मिंग सिफारिश प्रणाली",
'farm_details': "📏 कृषि विवरण",
'crop_preference': "🌱 फसल प्राथमिकता",
'soil_analysis': "🗺️ मिट्टी विश्लेषण",
'upload_photo': "📸 फोटो अपलोड करें",
'manual_selection': "📝 मैन्युअल चयन",
'select_soil_type': "मिट्टी का प्रकार चुनें",
'generate_recommendation': "💡 स्मार्ट सिफारिश उत्पन्न करें",
'personalized_recommendation': "### 🎯 आपकी व्यक्तिगत सिफारिश",
'weather_forecast': "#### 🌤️ मौसम पूर्वानुमान (AI मॉडल)",
'pest_prediction': "#### 🐛 कीट/रोग पूर्वानुमान (AI मॉडल)",
'details': "विवरण:",
'crop_rotation_planner': "🌱 फसल चक्र योजना",
'fertilizer_optimization': "🧪 उर्वरक अनुकूलन कैलकुलेटर",
'previous_recommendations': "📜 पिछली सिफारिशें",
'built_with': "सस्टेनेबल फार्मिंग के लिए प्यार से बनाया गया",
'last_updated': "अंतिम बार अपडेट किया गया: ",
'signup_title': "🌾 कृषक समुदाय में शामिल हों",
'login_title': "🌾 वापस स्वागत है",
'username': "👤 किसान का नाम",
'farm_name': "🏡 खेत का नाम",
'profile_picture': "📷 प्रोफाइल चित्र (वैकल्पिक)",
'signup_button': "✅ अब शामिल हों",
'login_button': "✅ लॉगिन",
'signup_instruction': "शुरू करने के लिए अपनी जानकारी भरें!",
'login_instruction': "जारी रखने के लिए अपनी किसान प्रोफाइल चुनें।",
'no_account': "अभी तक कोई खाता नहीं है? साइन अप करें!",
'signup_success': "स्वागत है, {username}! आपका खाता बन गया है।",
'login_success': "वापस स्वागत है, {username}!",
'username_exists': "⚠️ किसान का नाम पहले से लिया गया है। दूसरा नाम आज़माएं।",
'no_users': "अभी तक कोई किसान पंजीकृत नहीं है। शुरू करने के लिए साइन अप करें!"
},
'French': {
'title': "Système de recommandation agricole durable",
'farm_details': "📏 Détails de la ferme",
'crop_preference': "🌱 Préférence de culture",
'soil_analysis': "🗺️ Analyse du sol",
'upload_photo': "📸 Télécharger une photo",
'manual_selection': "📝 Sélection manuelle",
'select_soil_type': "Sélectionnez le type de sol",
'generate_recommendation': "💡 Générer une recommandation intelligente",
'personalized_recommendation': "### 🎯 Votre recommandation personnalisée",
'weather_forecast': "#### 🌤️ Prévision météo (modèle IA)",
'pest_prediction': "#### 🐛 Prévision des ravageurs/maladies (modèle IA)",
'details': "Détails:",
'crop_rotation_planner': "🌱 Planificateur de rotation des cultures",
'fertilizer_optimization': "🧪 Calculateur d'optimisation des engrais",
'previous_recommendations': "📜 Recommandations précédentes",
'built_with': "Construit avec ❤️ pour une agriculture durable",
'last_updated': "Dernière mise à jour: ",
'signup_title': "🌾 Rejoignez la communauté agricole",
'login_title': "🌾 Bienvenue à nouveau",
'username': "👤 Nom de l'agriculteur",
'farm_name': "🏡 Nom de la ferme",
'profile_picture': "📷 Photo de profil (facultatif)",
'signup_button': "✅ S'inscrire maintenant",
'login_button': "✅ Connexion",
'signup_instruction': "Remplissez vos informations pour commencer !",
'login_instruction': "Sélectionnez votre profil d'agriculteur pour continuer.",
'no_account': "Pas encore de compte ? Inscrivez-vous !",
'signup_success': "Bienvenue, {username} ! Votre compte a été créé.",
'login_success': "Bon retour, {username} !",
'username_exists': "⚠️ Nom d'agriculteur déjà pris. Essayez un autre.",
'no_users': "Aucun agriculteur enregistré pour le moment. Inscrivez-vous pour commencer !"
},
'Spanish': {
'title': "Sistema de Recomendación de Agricultura Sostenible",
'farm_details': "📏 Detalles de la granja",
'crop_preference': "🌱 Preferencia de cultivo",
'soil_analysis': "🗺️ Análisis del suelo",
'upload_photo': "📸 Subir foto",
'manual_selection': "📝 Selección manual",
'select_soil_type': "Seleccione el tipo de suelo",
'generate_recommendation': "💡 Generar recomendación inteligente",
'personalized_recommendation': "### 🎯 Su recomendación personalizada",
'weather_forecast': "#### 🌤️ Pronóstico del tiempo (modelo IA)",
'pest_prediction': "#### 🐛 Pronóstico de plagas/enfermedades (modelo IA)",
'details': "Detalles:",
'crop_rotation_planner': "🌱 Planificador de rotación de cultivos",
'fertilizer_optimization': "🧪 Calculadora de optimización de fertilizantes",
'previous_recommendations': "📜 Recomendaciones anteriores",
'built_with': "Construido con ❤️ para la agricultura sostenible",
'last_updated': "Última actualización: ",
'signup_title': "🌾 Únete a la comunidad agrícola",
'login_title': "🌾 Bienvenido de nuevo",
'username': "👤 Nombre del agricultor",
'farm_name': "🏡 Nombre de la granja",
'profile_picture': "📷 Foto de perfil (opcional)",
'signup_button': "✅ Únete ahora",
'login_button': "✅ Iniciar sesión",
'signup_instruction': "¡Completa tus datos para empezar!",
'login_instruction': "Selecciona tu perfil de agricultor para continuar.",
'no_account': "¿Aún no tienes cuenta? ¡Regístrate!",
'signup_success': "¡Bienvenido, {username}! Tu cuenta ha sido creada.",
'login_success': "¡Bienvenido de nuevo, {username}!",
'username_exists': "⚠️ Nombre de agricultor ya tomado. Prueba con otro.",
'no_users': "Aún no hay agricultores registrados. ¡Regístrate para comenzar!"
},
'Tamil': {
'title': "திடமான விவசாய பரிந்துரை அமைப்பு",
'farm_details': "📏 விவசாய விவரங்கள்",
'crop_preference': "🌱 பயிர் விருப்பம்",
'soil_analysis': "🗺️ மண் பகுப்பாய்வு",
'upload_photo': "📸 புகைப்படத்தை பதிவேற்றவும்",
'manual_selection': "📝 கைமுறையிலான தேர்வு",
'select_soil_type': "மண் வகையைத் தேர்ந்தெடுக்கவும்",
'generate_recommendation': "💡 ஸ்மார்ட் பரிந்துரையை உருவாக்கவும்",
'personalized_recommendation': "### 🎯 உங்கள் தனிப்பட்ட பரிந்துரை",
'weather_forecast': "#### 🌤️ வானிலை முன்னறிவு (AI மாதிரி)",
'pest_prediction': "#### 🐛 பூச்சி/நோய் முன்னறிவு (AI மாதிரி)",
'details': "விவரங்கள்:",
'crop_rotation_planner': "🌱 பயிர் சுழற்சி திட்டம்",
'fertilizer_optimization': "🧪 உரம் மேம்பாட்டு கணிப்பான்",
'previous_recommendations': "📜 முந்தைய பரிந்துரைகள்",
'built_with': "திடமான விவசாயத்திற்கு அன்புடன் உருவாக்கப்பட்டது",
'last_updated': "கடைசியாக புதுப்பிக்கப்பட்டது: ",
'signup_title': "🌾 விவசாய சமூகத்தில் சேரவும்",
'login_title': "🌾 மீண்டும் வரவேற்கிறோம்",
'username': "👤 விவசாயி பெயர்",
'farm_name': "🏡 பண்ணை பெயர்",
'profile_picture': "📷 சுயவிவர படம் (விருப்பமானது)",
'signup_button': "✅ இப்போது சேரவும்",
'login_button': "✅ உள்நுழை",
'signup_instruction': "தொடங்க உங்கள் விவரங்களை நிரப்பவும்!",
'login_instruction': "தொடர உங்கள் விவசாயி சுயவிவரத்தைத் தேர்ந்தெடுக்கவும்.",
'no_account': "இன்னும் கணக்கு இல்லையா? பதிவு செய்யவும்!",
'signup_success': "வரவேற்கிறோம், {username}! உங்கள் கணக்கு உருவாக்கப்பட்டது.",
'login_success': "மீண்டும் வரவேற்கிறோம், {username}!",
'username_exists': "⚠️ விவசாயி பெயர் ஏற்கனவே எடுக்கப்பட்டுள்ளது. வேறு ஒரு பெயரை முயற்சிக்கவும்.",
'no_users': "இன்னும் விவசாயிகள் பதிவு செய்யப்படவில்லை. தொடங்க பதிவு செய்யவும்!"
},
'Malayalam': {
'title': "സ്ഥിരമായ കൃഷി ശുപാർശ സംവിധാനം",
'farm_details': "📏 കൃഷി വിശദാംശങ്ങൾ",
'crop_preference': "🌱 വിളയുടെ മുൻഗണന",
'soil_analysis': "🗺️ മണ്ണ് വിശകലനം",
'upload_photo': "📸 ഫോട്ടോ അപ്‌ലോഡ് ചെയ്യുക",
'manual_selection': "📝 മാനുവൽ തിരഞ്ഞെടുപ്പ്",
'select_soil_type': "മണ്ണിന്റെ തരം തിരഞ്ഞെടുക്കുക",
'generate_recommendation': "💡 സ്മാർട്ട് ശുപാർശ സൃഷ്ടിക്കുക",
'personalized_recommendation': "### 🎯 നിങ്ങളുടെ വ്യക്തിഗത ശുപാർശ",
'weather_forecast': "#### 🌤️ കാലാവസ്ഥ പ്രവചനം (AI മോഡൽ)",
'pest_prediction': "#### 🐛 കീടം/രോഗം പ്രവചനം (AI മോഡൽ)",
'details': "വിശദാംശങ്ങൾ:",
'crop_rotation_planner': "🌱 വിള ചക്ര പദ്ധതി",
'fertilizer_optimization': "🧪 വളം ഓപ്റ്റിമൈസേഷൻ കാൽക്കുലേറ്റർ",
'previous_recommendations': "📜 മുമ്പത്തെ ശുപാർശകൾ",
'built_with': "സ്ഥിരമായ കൃഷിക്ക് സ്നേഹത്തോടെ നിർമ്മിച്ചു",
'last_updated': "അവസാനമായി പുതുക്കിയത്: ",
'signup_title': "🌾 കൃഷി സമൂഹത്തിൽ ചേരുക",
'login_title': "🌾 വീണ്ടും സ്വാഗതം",
'username': "👤 കർഷകന്റെ പേര്",
'farm_name': "🏡 കൃഷിസ്ഥലത്തിന്റെ പേര്",
'profile_picture': "📷 പ്രൊഫൈൽ ചിത്രം (ഓപ്ഷണൽ)",
'signup_button': "✅ ഇപ്പോൾ ചേരുക",
'login_button': "✅ ലോഗിൻ",
'signup_instruction': "തുടങ്ങാൻ നിന്റെ വിശദാംശങ്ങൾ നൽകുക!",
'login_instruction': "തുടരാൻ നിന്റെ കർഷക പ്രൊഫൈൽ തിരഞ്ഞെടുക്കുക.",
'no_account': "ഇതുവരെ അക്കൗണ്ട് ഇല്ലേ? സൈൻ അപ്പ് ചെയ്യുക!",
'signup_success': "സ്വാഗതം, {username}! നിന്റെ അക്കൗണ്ട് സൃഷ്ടിച്ചു.",
'login_success': "വീണ്ടും സ്വാഗതം, {username}!",
'username_exists': "⚠️ കർഷകന്റെ പേര് ഇതിനകം എടുത്തിട്ടുണ്ട്. മറ്റൊരു പേര് പരീക്ഷിക്കുക.",
'no_users': "ഇതുവരെ കർഷകർ രജിസ്റ്റർ ചെയ്തിട്ടില്ല. തുടങ്ങാൻ സൈൻ അപ്പ് ചെയ്യുക!"
},
'Marathi': {
'title': "शाश्वत शेती शिफारस प्रणाली",
'farm_details': "📏 शेती तपशील",
'crop_preference': "🌱 पिक प्राधान्य",
'soil_analysis': "🗺️ माती विश्लेषण",
'upload_photo': "📸 फोटो अपलोड करा",
'manual_selection': "📝 मॅन्युअल निवड",
'select_soil_type': "मातीचा प्रकार निवडा",
'generate_recommendation': "💡 स्मार्ट शिफारस तयार करा",
'personalized_recommendation': "### 🎯 आपली वैयक्तिक शिफारस",
'weather_forecast': "#### 🌤️ हवामान अंदाज (AI मॉडेल)",
'pest_prediction': "#### 🐛 कीटक/रोग अंदाज (AI मॉडेल)",
'details': "तपशील:",
'crop_rotation_planner': "🌱 पिक फेरपालट नियोजक",
'fertilizer_optimization': "🧪 खत ऑप्टिमायझेशन कॅल्क्युलेटर",
'previous_recommendations': "📜 मागील शिफारसी",
'built_with': "शाश्वत शेतीसाठी प्रेमाने तयार केले",
'last_updated': "शेवटचे अद्यतन: ",
'signup_title': "🌾 शेती समुदायात सामील व्हा",
'login_title': "🌾 परत स्वागत आहे",
'username': "👤 शेतकऱ्याचे नाव",
'farm_name': "🏡 शेताचे नाव",
'profile_picture': "📷 प्रोफाइल चित्र (पर्यायी)",
'signup_button': "✅ आता सामील व्हा",
'login_button': "✅ लॉगिन",
'signup_instruction': "सुरू करण्यासाठी आपले तपशील भरा!",
'login_instruction': "पुढे जाण्यासाठी आपले शेतकरी प्रोफाइल निवडा.",
'no_account': "अजून खाते नाही? साइन अप करा!",
'signup_success': "स्वागत आहे, {username}! आपले खाते तयार झाले आहे.",
'login_success': "परत स्वागत आहे, {username}!",
'username_exists': "⚠️ शेतकऱ्याचे नाव आधीच घेतले आहे. दुसरे नाव वापरून पहा.",
'no_users': "अजून कोणतेही शेतकरी नोंदणीकृत नाहीत. सुरू करण्यासाठी साइन अप करा!"
},
'Konkani': {
'title': "सस्टेनेबल फार्मिंग रेकमेंडेशन सिस्टिम",
'farm_details': "📏 शेतीचे तपशील",
'crop_preference': "🌱 पिकाची प्राधान्य",
'soil_analysis': "🗺️ मातीचे विश्लेषण",
'upload_photo': "📸 फोटो अपलोड करा",
'manual_selection': "📝 मॅन्युअल निवड",
'select_soil_type': "मातीचा प्रकार निवडा",
'generate_recommendation': "💡 स्मार्ट शिफारस तयार करा",
'personalized_recommendation': "### 🎯 तुमची वैयक्तिक शिफारस",
'weather_forecast': "#### 🌤️ हवामानाचा अंदाज (AI मॉडेल)",
'pest_prediction': "#### 🐛 कीटक/रोगाचा अंदाज (AI मॉडेल)",
'details': "तपशील:",
'crop_rotation_planner': "🌱 पिक फेरपालट नियोजक",
'fertilizer_optimization': "🧪 खत ऑप्टिमायझेशन कॅल्क्युलेटर",
'previous_recommendations': "📜 मागील शिफारसी",
'built_with': "सस्टेनेबल फार्मिंगसाठी प्रेमाने तयार केले",
'last_updated': "शेवटचे अद्यतन: ",
'signup_title': "🌾 शेती समुदायात सामील व्हा",
'login_title': "🌾 परत स्वागत आहे",
'username': "👤 शेतकऱ्याचे नाव",
'farm_name': "🏡 शेताचे नाव",
'profile_picture': "📷 प्रोफाइल चित्र (पर्यायी)",
'signup_button': "✅ आता सामील व्हा",
'login_button': "✅ लॉगिन",
'signup_instruction': "सुरू करण्यासाठी आपले तपशील भरा!",
'login_instruction': "पुढे जाण्यासाठी आपले शेतकरी प्रोफाइल निवडा.",
'no_account': "अजून खाते नाही? साइन अप करा!",
'signup_success': "स्वागत आहे, {username}! आपले खाते तयार झाले आहे.",
'login_success': "परत स्वागत आहे, {username}!",
'username_exists': "⚠️ शेतकऱ्याचे नाव आधीच घेतले आहे. दुसरे नाव वापरून पहा.",
'no_users': "अजून कोणतेही शेतकरी नोंदणीकृत नाहीत. सुरू करण्यासाठी साइन अप करा!"
},
'Urdu': {
'title': "پائیدار زراعت کی سفارشات کا نظام",
'farm_details': "📏 زرعی تفصیلات",
'crop_preference': "🌱 فصل کی ترجیح",
'soil_analysis': "🗺️ مٹی کا تجزیہ",
'upload_photo': "📸 تصویر اپ لوڈ کریں",
'manual_selection': "📝 دستی انتخاب",
'select_soil_type': "مٹی کی قسم منتخب کریں",
'generate_recommendation': "💡 اسمارٹ سفارش تیار کریں",
'personalized_recommendation': "### 🎯 آپ کی ذاتی سفارش",
'weather_forecast': "#### 🌤️ موسم کی پیش گوئی (AI ماڈل)",
'pest_prediction': "#### 🐛 کیڑوں/بیماری کی پیش گوئی (AI ماڈل)",
'details': "تفصیلات:",
'crop_rotation_planner': "🌱 فصل کی گردش کا منصوبہ",
'fertilizer_optimization': "🧪 کھاد کی اصلاح کیلکولیٹر",
'previous_recommendations': "📜 پچھلی سفارشات",
'built_with': "پائیدار زراعت کے لیے محبت سے تیار کیا گیا",
'last_updated': "آخری بار اپ ڈیٹ کیا گیا: ",
'signup_title': "🌾 زرعی برادری میں شامل ہوں",
'login_title': "🌾 واپس خوش آمدید",
'username': "👤 کسان کا نام",
'farm_name': "🏡 کھیت کا نام",
'profile_picture': "📷 پروفائل تصویر (اختیاری)",
'signup_button': "✅ ابھی شامل ہوں",
'login_button': "✅ لاگ ان",
'signup_instruction': "شروع کرنے کے لیے اپنی تفصیلات پُر کریں!",
'login_instruction': "جاری رکھنے کے لیے اپنا کسان پروفائل منتخب کریں۔",
'no_account': "ابھی تک کوئی اکاؤنٹ نہیں ہے؟ سائن اپ کریں!",
'signup_success': "خوش آمدید، {username}! آپ کا اکاؤنٹ بن گیا ہے۔",
'login_success': "واپس خوش آمدید، {username}!",
'username_exists': "⚠️ کسان کا نام پہلے سے لیا جا چکا ہے۔ کوئی اور نام آزمائیں۔",
'no_users': "ابھی تک کوئی کسان رجسٹرڈ نہیں ہیں۔ شروع کرنے کے لیے سائن اپ کریں!"
}
}
# Set page config FIRST, before any other Streamlit command
## st.set_page_config moved to top of file
# Update initialize_db to include users table and new features
def initialize_db():
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
# Create recommendations table with extended schema used by agents
cursor.execute('''CREATE TABLE IF NOT EXISTS recommendations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
crop TEXT,
score REAL,
rationale TEXT,
market_score REAL,
weather_score REAL,
sustainability_score REAL,
carbon_score REAL,
water_score REAL,
erosion_score REAL,
timestamp TEXT
)''')
# Ensure legacy databases are migrated to include new columns
try:
cursor.execute("PRAGMA table_info(recommendations)")
existing_cols = {row[1] for row in cursor.fetchall()}
missing_cols = []
if 'market_score' not in existing_cols:
missing_cols.append(("market_score", "REAL"))
if 'weather_score' not in existing_cols:
missing_cols.append(("weather_score", "REAL"))
if 'sustainability_score' not in existing_cols:
missing_cols.append(("sustainability_score", "REAL"))
for col_name, col_type in missing_cols:
cursor.execute(f"ALTER TABLE recommendations ADD COLUMN {col_name} {col_type}")
except Exception:
pass
# Create farmer_advisor table required by multiple models
cursor.execute('''CREATE TABLE IF NOT EXISTS farmer_advisor (
id INTEGER PRIMARY KEY AUTOINCREMENT,
Soil_pH REAL,
Soil_Moisture REAL,
Temperature_C REAL,
Rainfall_mm REAL,
Fertilizer_Usage_kg REAL,
Pesticide_Usage_kg REAL,
Crop_Yield_ton REAL,
Crop_Type TEXT,
Sustainability_Score REAL
)''')
# Seed minimal sample data if empty to avoid cold-start errors
cursor.execute('SELECT COUNT(*) FROM farmer_advisor')
fa_count = cursor.fetchone()[0]
if fa_count == 0:
sample_farmer_rows = [
(6.5, 30.0, 28.0, 120.0, 80.0, 10.0, 3.5, 'Wheat', 78.0),
(6.2, 35.0, 30.0, 90.0, 70.0, 8.0, 3.2, 'Rice', 75.0),
(6.8, 25.0, 32.0, 60.0, 60.0, 6.0, 2.8, 'Corn', 80.0),
(6.4, 33.0, 27.0, 100.0, 85.0, 9.0, 3.0, 'Soybean', 76.0)
]
cursor.executemany('''
INSERT INTO farmer_advisor (
Soil_pH, Soil_Moisture, Temperature_C, Rainfall_mm,
Fertilizer_Usage_kg, Pesticide_Usage_kg, Crop_Yield_ton,
Crop_Type, Sustainability_Score
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)''', sample_farmer_rows)
# Ensure market_researcher table exists (needed by MarketResearcher on import)
cursor.execute('''CREATE TABLE IF NOT EXISTS market_researcher (
id INTEGER PRIMARY KEY AUTOINCREMENT,
Product TEXT,
Market_Price_per_ton REAL,
Demand_Index REAL,
Supply_Index REAL,
Competitor_Price_per_ton REAL,
Economic_Indicator REAL,
Weather_Impact_Score REAL,
Seasonal_Factor TEXT,
Consumer_Trend_Index REAL
)''')
# Seed minimal sample data if empty to avoid cold-start errors
cursor.execute('SELECT COUNT(*) FROM market_researcher')
count = cursor.fetchone()[0]
if count == 0:
sample_data = [
("tomatoes", 950.0, 0.6, 0.4, 900.0, 0.8, 0.7, "High", 0.6),
("carrots", 800.0, 0.5, 0.5, 850.0, 0.7, 0.6, "Medium", 0.5),
("wheat", 600.0, 0.4, 0.6, 650.0, 0.9, 0.8, "Low", 0.7),
("corn", 700.0, 0.5, 0.5, 720.0, 0.8, 0.7, "Medium", 0.6)
]
cursor.executemany('''
INSERT INTO market_researcher (Product, Market_Price_per_ton, Demand_Index, Supply_Index,
Competitor_Price_per_ton, Economic_Indicator,
Weather_Impact_Score, Seasonal_Factor, Consumer_Trend_Index)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)''', sample_data)
# Create sustainability_scores table (existing)
cursor.execute('''CREATE TABLE IF NOT EXISTS sustainability_scores (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT,
water_score REAL,
fertilizer_use REAL,
rotation INTEGER,
score REAL
)''')
# Create users table
cursor.execute('''CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE,
farm_name TEXT,
profile_picture TEXT,
created_at TEXT
)''')
# Create farm_maps table for interactive farm mapping
cursor.execute('''CREATE TABLE IF NOT EXISTS farm_maps (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT,
farm_name TEXT,
map_data TEXT,
recommendations TEXT,
risk_areas TEXT,
created_at TEXT,
updated_at TEXT
)''')
# Create community_insights table for community-driven data
cursor.execute('''CREATE TABLE IF NOT EXISTS community_insights (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT,
crop_type TEXT,
yield_data REAL,
market_price REAL,
sustainability_practice TEXT,
region TEXT,
season TEXT,
created_at TEXT
)''')
# Create market_forecasts table for price predictions
cursor.execute('''CREATE TABLE IF NOT EXISTS market_forecasts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
crop TEXT,
predicted_price REAL,
confidence_score REAL,
forecast_date TEXT,
created_at TEXT
)''')
# Create chatbot_sessions table for chat history
cursor.execute('''CREATE TABLE IF NOT EXISTS chatbot_sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT,
session_id TEXT,
query TEXT,
response TEXT,
timestamp TEXT
)''')
# Create offline_data table for offline mode
cursor.execute('''CREATE TABLE IF NOT EXISTS offline_data (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT,
data_type TEXT,
data_content TEXT,
sync_status TEXT,
created_at TEXT,
synced_at TEXT
)''')
conn.commit()
# Initialize database
db_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'database', 'sustainable_farming.db'))
# Ensure database directory exists
os.makedirs(os.path.dirname(db_path), exist_ok=True)
# Initialize database with all tables
initialize_db()
# Helper: Convert image to base64 for storage
def image_to_base64(image_file):
if image_file:
image = Image.open(image_file)
buffered = io.BytesIO()
image.save(buffered, format="PNG")
return base64.b64encode(buffered.getvalue()).decode()
return None
# Helper: Display base64 image
def display_base64_image(base64_string, size=50):
if base64_string:
return f'<img src="data:image/png;base64,{base64_string}" width="{size}" style="border-radius:50%;margin-right:10px;">'
return '<span style="font-size:2em;margin-right:10px;">👤</span>'
# Helper: Generate chatbot response
def generate_chatbot_response(query):
"""Generate AI response for farming queries"""
query_lower = query.lower()
# Simple rule-based responses (in production, this would use the agent framework)
if any(word in query_lower for word in ['fertilizer', 'fertilizer', 'nutrient']):
if 'loamy' in query_lower:
return "For loamy soil, I recommend balanced NPK fertilizer (10-10-10) at 100-150 kg/hectare. Loamy soil has good drainage and nutrient retention, so moderate fertilization works well. Consider organic options like compost or manure for sustainable farming."
elif 'clay' in query_lower:
return "Clay soil requires careful fertilizer management. Use slow-release fertilizers and avoid over-application. I recommend 80-120 kg/hectare of NPK fertilizer. Clay soil holds nutrients well, so less frequent but consistent application is key."
elif 'sandy' in query_lower:
return "Sandy soil needs more frequent fertilization due to poor nutrient retention. Use 120-180 kg/hectare of NPK fertilizer in smaller, more frequent applications. Consider adding organic matter to improve soil structure."
else:
return "For fertilizer recommendations, I need to know your soil type. Generally, balanced NPK fertilizers work well for most crops. Consider soil testing for precise recommendations."
elif any(word in query_lower for word in ['pest', 'disease', 'insect']):
return "For pest and disease management, I recommend integrated pest management (IPM) approach: 1) Monitor regularly, 2) Use biological controls, 3) Apply chemical treatments only when necessary, 4) Practice crop rotation. What specific pest or disease are you dealing with?"
elif any(word in query_lower for word in ['water', 'irrigation', 'watering']):
return "Water management is crucial for crop health. I recommend: 1) Monitor soil moisture regularly, 2) Use drip irrigation for water efficiency, 3) Water early morning or evening, 4) Adjust based on weather conditions. What's your current irrigation setup?"
elif any(word in query_lower for word in ['crop', 'plant', 'growing']):
return "For crop selection, consider: 1) Soil type and climate, 2) Market demand and prices, 3) Your farming experience, 4) Water availability. What crops are you interested in growing?"
elif any(word in query_lower for word in ['soil', 'soil type', 'soil test']):
return "Soil health is fundamental to farming success. I recommend: 1) Get soil tested regularly, 2) Maintain proper pH levels (6.0-7.0 for most crops), 3) Add organic matter, 4) Practice crop rotation. Would you like help with soil testing or improvement?"
elif any(word in query_lower for word in ['weather', 'climate', 'season']):
return "Weather and climate play a crucial role in farming. I can help with: 1) Weather-based planting decisions, 2) Climate-appropriate crop selection, 3) Seasonal farming practices, 4) Weather risk management. What specific weather concern do you have?"
elif any(word in query_lower for word in ['yield', 'production', 'harvest']):
return "To improve crop yield, focus on: 1) Quality seeds and planting material, 2) Proper spacing and timing, 3) Adequate nutrition and water, 4) Pest and disease control, 5) Post-harvest management. What crop are you looking to improve yield for?"
else:
return "I'm here to help with all your farming questions! I can assist with soil management, crop selection, pest control, irrigation, weather planning, and much more. Could you be more specific about what you'd like to know?"
# --- Authentication ---
if 'user' not in st.session_state:
st.session_state['user'] = None
if 'lang' not in st.session_state:
st.session_state['lang'] = 'English'
# Language selection
lang = st.selectbox(
"🌐 " + LANGUAGES[st.session_state['lang']].get('select_language', 'Select Language'),
options=list(LANGUAGES.keys()),
index=list(LANGUAGES.keys()).index(st.session_state['lang']),
key="language_selector"
)
st.session_state['lang'] = lang
T = LANGUAGES[lang]
# Check if user is logged in
if not st.session_state['user']:
# Tabs for Signup and Login
tab1, tab2 = st.tabs([T['signup_title'], T['login_title']])
with tab1:
st.markdown(f"<div class='card-section'><span class='section-step'>👋</span><b style='font-size:1.3em'>{T['signup_title']}</b><div class='section-instructions'>{T['signup_instruction']}</div></div>", unsafe_allow_html=True)
with st.form("signup_form"):
col1, col2 = st.columns([1, 1])
with col1:
username = st.text_input(f"👤 {T['username']}", help=T['username'])
with col2:
farm_name = st.text_input(f"🏡 {T['farm_name']}", help=T['farm_name'])
profile_picture = st.file_uploader(f"📷 {T['profile_picture']}", type=["jpg", "jpeg", "png"])
submit_signup = st.form_submit_button(f"✅ {T['signup_button']}", type="primary")
if submit_signup:
if username and farm_name:
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute("SELECT username FROM users WHERE username = ?", (username,))
if cursor.fetchone():
st.error(T['username_exists'])
else:
profile_picture_base64 = image_to_base64(profile_picture)
cursor.execute(
"INSERT INTO users (username, farm_name, profile_picture, created_at) VALUES (?, ?, ?, ?)",
(username, farm_name, profile_picture_base64, datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
)
conn.commit()
st.session_state['user'] = {'username': username, 'farm_name': farm_name, 'profile_picture': profile_picture_base64}
st.success(T['signup_success'].format(username=username))
st.rerun()
else:
st.error(T.get('fill_all_fields', "Please fill in all required fields."))
with tab2:
st.markdown(f"<div class='card-section'><span class='section-step'>👋</span><b style='font-size:1.3em'>{T['login_title']}</b><div class='section-instructions'>{T['login_instruction']}</div></div>", unsafe_allow_html=True)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute("SELECT username, farm_name, profile_picture FROM users")
users = cursor.fetchall()
if users:
user_options = [
(f"{display_base64_image(user[2])} {user[0]} ({user[1]})", user) for user in users
]
selected_user = st.selectbox(
f"👤 {T.get('select_farmer', 'Select your farmer profile')}",
options=[u[0] for u in user_options],
format_func=lambda x: x,
help=T['login_instruction']
)
if st.button(f"✅ {T['login_button']}", type="primary"):
selected_user_data = next(u[1] for u in user_options if u[0] == selected_user)
st.session_state['user'] = {
'username': selected_user_data[0],
'farm_name': selected_user_data[1],
'profile_picture': selected_user_data[2]
}
st.success(T['login_success'].format(username=selected_user_data[0]))
st.rerun()
else:
st.info(T['no_users'])
st.markdown(f"<a href='#' onclick='st.set_page_config(page_title=\"{T['signup_title']}\");'>{T['no_account']}</a>", unsafe_allow_html=True)
else:
# Display logged-in user
user = st.session_state['user']
st.markdown(
f"<div style='display:flex;align-items:center;'>{display_base64_image(user['profile_picture'])} <b>{T.get('welcome', 'Welcome')}, {user['username']} ({user['farm_name']})!</b></div>",
unsafe_allow_html=True
)
if st.button(f"🔓 {T.get('logout', 'Logout')}"):
st.session_state['user'] = None
st.rerun()
# Check which page to display
current_page = st.session_state.get('current_page', '🏠 Main App')
if current_page == '👤 User Profile':
# User Profile Page
st.title("👤 User Profile")
# Profile tabs
tab_profile, tab_history, tab_settings = st.tabs(["📋 Profile Info", "📊 Farming History", "⚙️ Settings"])
with tab_profile:
st.markdown("### 👤 Personal Information")
col1, col2 = st.columns([1, 2])
with col1:
# Profile picture
st.markdown("#### Profile Picture")
current_pic = display_base64_image(user['profile_picture'], size=150)
st.markdown(current_pic, unsafe_allow_html=True)
# Upload new picture
new_picture = st.file_uploader("Upload new profile picture", type=['png', 'jpg', 'jpeg'], key="profile_pic_upload")
if new_picture:
new_pic_base64 = image_to_base64(new_picture)
st.session_state['user']['profile_picture'] = new_pic_base64
st.success("✅ Profile picture updated!")
st.rerun()
with col2:
# User information
st.markdown("#### User Details")
# Editable fields
new_username = st.text_input("Username", value=user['username'], key="edit_username")
new_farm_name = st.text_input("Farm Name", value=user['farm_name'], key="edit_farm_name")
# Additional profile fields
st.markdown("#### Additional Information")
email = st.text_input("Email (Optional)", value=st.session_state.get('user_email', ''), key="edit_email")
phone = st.text_input("Phone (Optional)", value=st.session_state.get('user_phone', ''), key="edit_phone")
location = st.text_input("Location (Optional)", value=st.session_state.get('user_location', ''), key="edit_location")
# Farming preferences
st.markdown("#### Farming Preferences")
experience_level = st.selectbox("Experience Level",
["Beginner", "Intermediate", "Advanced", "Expert"],
index=["Beginner", "Intermediate", "Advanced", "Expert"].index(st.session_state.get('experience_level', 'Beginner')),
key="edit_experience")
farm_size = st.number_input("Farm Size (hectares)",
min_value=0.1, max_value=1000.0,
value=float(st.session_state.get('farm_size', 5.0)),
step=0.1, key="edit_farm_size")
primary_crops = st.multiselect("Primary Crops",
["Rice", "Wheat", "Corn", "Soybean", "Vegetables", "Fruits", "Spices", "Other"],
default=st.session_state.get('primary_crops', []),
key="edit_primary_crops")
# Save button
if st.button("💾 Save Profile Changes", key="save_profile"):
# Update user data
st.session_state['user']['username'] = new_username
st.session_state['user']['farm_name'] = new_farm_name
st.session_state['user_email'] = email
st.session_state['user_phone'] = phone
st.session_state['user_location'] = location
st.session_state['experience_level'] = experience_level
st.session_state['farm_size'] = farm_size
st.session_state['primary_crops'] = primary_crops
# Update database
try:
conn = sqlite3.connect('database/sustainable_farming.db')
cursor = conn.cursor()
cursor.execute("""
UPDATE users
SET username = ?, farm_name = ?, profile_picture = ?
WHERE username = ?
""", (new_username, new_farm_name, st.session_state['user']['profile_picture'], user['username']))
conn.commit()
conn.close()
st.success("✅ Profile updated successfully!")
st.rerun()
except Exception as e:
st.error(f"❌ Error updating profile: {e}")
with tab_history:
st.markdown("### 📊 Farming History & Analytics")
# Recent recommendations
st.markdown("#### Recent Recommendations")
try:
conn = sqlite3.connect('database/sustainable_farming.db')
cursor = conn.cursor()
cursor.execute("""
SELECT recommendation, created_at, sustainability_score
FROM recommendations
WHERE username = ?
ORDER BY created_at DESC
LIMIT 10
""", (user['username'],))
recommendations = cursor.fetchall()
if recommendations:
for i, (rec, date, score) in enumerate(recommendations):
with st.expander(f"Recommendation {i+1} - {date[:10]} (Score: {score}/100)"):
st.text(rec[:500] + "..." if len(rec) > 500 else rec)
else:
st.info("No recommendations found. Generate some recommendations to see your history!")
conn.close()
except Exception as e:
st.warning(f"Could not load recommendations: {e}")
# Sustainability tracking
st.markdown("#### Sustainability Score History")
try:
conn = sqlite3.connect('database/sustainable_farming.db')
cursor = conn.cursor()
cursor.execute("""
SELECT sustainability_score, created_at
FROM sustainability_tracking
WHERE username = ?
ORDER BY created_at DESC
LIMIT 20
""", (user['username'],))
scores = cursor.fetchall()
if scores:
import pandas as pd
df = pd.DataFrame(scores, columns=['Score', 'Date'])
df['Date'] = pd.to_datetime(df['Date'])
# Create a simple line chart
import plotly.express as px
fig = px.line(df, x='Date', y='Score', title='Sustainability Score Over Time')
fig.update_layout(yaxis_title="Sustainability Score", xaxis_title="Date")
st.plotly_chart(fig, use_container_width=True)
else:
st.info("No sustainability data found. Start tracking your farming practices!")
conn.close()
except Exception as e:
st.warning(f"Could not load sustainability data: {e}")
with tab_settings:
st.markdown("### ⚙️ Account Settings")
# Language settings
st.markdown("#### Language & Voice Settings")
current_lang = st.session_state.get('language', 'English')
new_language = st.selectbox("Preferred Language",
["English", "Hindi", "Kannada", "Telugu", "Tamil", "Malayalam", "Bengali", "Gujarati", "Marathi", "Punjabi", "Odia", "Assamese", "French", "Spanish"],
index=["English", "Hindi", "Kannada", "Telugu", "Tamil", "Malayalam", "Bengali", "Gujarati", "Marathi", "Punjabi", "Odia", "Assamese", "French", "Spanish"].index(current_lang),
key="settings_language")
# Voice settings
voice_enabled = st.checkbox("Enable Voice Interface",
value=st.session_state.get('voice_enabled', True),
key="settings_voice")
# Notification settings
st.markdown("#### Notification Settings")
email_notifications = st.checkbox("Email Notifications",
value=st.session_state.get('email_notifications', False),
key="settings_email")
weather_alerts = st.checkbox("Weather Alerts",
value=st.session_state.get('weather_alerts', True),
key="settings_weather")
# Data export
st.markdown("#### Data Management")
if st.button("📥 Export My Data", key="export_data"):
try:
# Export user data
export_data = {
'username': user['username'],
'farm_name': user['farm_name'],
'email': st.session_state.get('user_email', ''),
'phone': st.session_state.get('user_phone', ''),
'location': st.session_state.get('user_location', ''),
'experience_level': st.session_state.get('experience_level', 'Beginner'),
'farm_size': st.session_state.get('farm_size', 5.0),
'primary_crops': st.session_state.get('primary_crops', []),
'language': st.session_state.get('language', 'English'),
'voice_enabled': st.session_state.get('voice_enabled', True)
}
import json
st.download_button(
label="⬇️ Download Profile Data",
data=json.dumps(export_data, indent=2),
file_name=f"{user['username']}_profile_data.json",
mime="application/json"
)
st.success("✅ Data export ready!")
except Exception as e:
st.error(f"❌ Error exporting data: {e}")
# Save settings
if st.button("💾 Save Settings", key="save_settings"):
st.session_state['language'] = new_language
st.session_state['voice_enabled'] = voice_enabled
st.session_state['email_notifications'] = email_notifications
st.session_state['weather_alerts'] = weather_alerts
st.success("✅ Settings saved successfully!")
else:
# Main App Page (existing content)
# Sidebar quick panel
with st.sidebar:
st.markdown("### 🌾 Quick Panel")
st.markdown(f"{display_base64_image(user['profile_picture'], size=36)} <b>{user['username']}</b><br><small>{user['farm_name']}</small>", unsafe_allow_html=True)
st.divider()
st.markdown("<b style='font-size:1.1em;color:#00bfff;'>Choose a feature:</b>", unsafe_allow_html=True)
quick_features = [
("🏡 Farm Details", "#farm-details", "#00c3ff"),
("🗺️ Soil Analysis", "#soil-analysis", "#f7971e"),
("💡 Smart Recommendation", "#smart-recommendation", "#00ff85"),
("🌱 Crop Rotation Planner", "#crop-rotation-planner", "#43cea2"),
("🧪 Fertilizer Optimization Calculator", "#fertilizer-optimization", "#f857a6"),
("📜 Previous Recommendations", "#previous-recommendations", "#ff5858"),
("🌍 Sustainability Score Tracker", "#sustainability-score-tracker", "#2af598"),
("🗺️ Interactive Farm Map", "#interactive-farm-map", "#ff6b6b"),
("👥 Community Insights", "#community-insights", "#4ecdc4"),
("📈 Market Dashboard", "#market-dashboard", "#45b7d1"),
("🤖 AI Chatbot", "#ai-chatbot", "#ff9f1c"),
("📱 Offline Mode", "#offline-mode", "#9b59b6")
]
for label, anchor, color in quick_features:
# Extract the section name from the anchor
section_name = anchor.replace('#', '')
st.markdown(f"""
<div class='nav-button' style='margin:8px 0;padding:12px 0;border-radius:14px;background:linear-gradient(90deg,{color} 0%,#fff 100%);text-align:center;box-shadow:0 2px 12px rgba(0,191,255,0.12);'
onclick="document.getElementById('{section_name}').scrollIntoView({{behavior: 'smooth'}});">
<span style='text-decoration:none;font-size:1.15em;font-weight:600;color:#1e3c72;cursor:pointer;'>{label}</span>
</div>
""", unsafe_allow_html=True)
st.session_state.setdefault('last_recs_csv', None)
if st.session_state['last_recs_csv']:
st.download_button("⬇ Download recent recommendations", data=st.session_state['last_recs_csv'], file_name="recent_recommendations.csv", mime="text/csv")
# Navigation
st.markdown("### 🧭 Navigation")
page = st.radio("Choose a page:", ["🏠 Main App", "👤 User Profile"], key="page_selector")
st.session_state['current_page'] = page
st.divider()
# API Configuration
st.markdown("### ⚙️ Configuration")
openweather_key = st.text_input(
"OpenWeatherMap API Key",
value=os.getenv('OPENWEATHER_API_KEY', 'e6f39f1d5c2c4ecea6d180422252609'),
type="password",
help="Get your free API key from openweathermap.org"
)
if openweather_key:
os.environ['OPENWEATHER_API_KEY'] = openweather_key
st.success("✅ API key configured")
else:
st.warning("⚠️ Using simulated weather data")
# Runtime cache management
st.markdown("### 🧹 Runtime Storage")
if st.button("Free up disk space (clear ML caches)"):
cleared = clear_runtime_caches()
if cleared:
st.success("Cleared caches: " + ", ".join(cleared))
else:
st.info("No caches found or already clean.")
# Speech Feature Integration
st.markdown("### 🎤 Voice Controls")
if 'speech_interface' not in st.session_state:
if SpeechInterface is not None:
st.session_state['speech_interface'] = SpeechInterface()
else:
st.session_state['speech_interface'] = None
speech_interface = st.session_state['speech_interface']
voice_enabled = st.checkbox("Enable Voice Interface", value=True, help="Allow voice input and output")
st.session_state['voice_enabled'] = voice_enabled
if voice_enabled:
if speech_interface is not None:
mic_ok = getattr(speech_interface, 'is_voice_available', lambda: False)()
tts_ok = getattr(speech_interface, 'has_tts', lambda: False)()
if mic_ok:
st.success("✅ Microphone available")
else:
# Clarify that WebRTC may enable mic even without PyAudio
st.warning("⚠️ Microphone not available (native). If using a browser, WebRTC capture will be used where supported.")
if tts_ok:
st.success("✅ Text-to-Speech available")
if st.button("🔊 Voice Help", help="Listen to voice instructions"):
speech_interface.create_voice_help_system(lang)
else:
st.warning("⚠️ Text-to-Speech not available")
else:
st.warning("⚠️ Speech interface not available. Please install speech dependencies.")
with st.expander("📋 Installation Instructions"):
st.markdown("""
**To enable voice features, install PyAudio:**
**Option 1 (Recommended):**
```bash
pip install pipwin
pipwin install pyaudio
```
**Option 2:**
```bash
conda install pyaudio
```
**Option 3:**
```bash
pip install pyaudio
```
**Note:** The app works perfectly without voice features - all farming functionality is available!
""")
# Location Configuration
st.markdown("### 📍 Location Settings")
location_option = st.radio(
"Choose location method:",
["Use my coordinates", "Enter city name", "Use default (Bangalore)"],
index=2
)
user_lat = 12.9716 # Default Bangalore
user_lon = 77.5946
if location_option == "Use my coordinates":
col1, col2 = st.columns(2)
with col1:
user_lat = st.number_input("Latitude", value=12.9716, min_value=-90.0, max_value=90.0, step=0.0001)
with col2:
user_lon = st.number_input("Longitude", value=77.5946, min_value=-180.0, max_value=180.0, step=0.0001)
elif location_option == "Enter city name":
city_name = st.text_input("City Name", value="Bangalore, India")
if city_name:
# Simple geocoding - you could enhance this with a proper geocoding service
city_coords = {
"bangalore, india": (12.9716, 77.5946),
"mumbai, india": (19.0760, 72.8777),
"delhi, india": (28.7041, 77.1025),
"chennai, india": (13.0827, 80.2707),
"kolkata, india": (22.5726, 88.3639),
"hyderabad, india": (17.3850, 78.4867),
"pune, india": (18.5204, 73.8567),
"ahmedabad, india": (23.0225, 72.5714),
"jaipur, india": (26.9124, 75.7873),
"lucknow, india": (26.8467, 80.9462)
}
city_lower = city_name.lower()
if city_lower in city_coords:
user_lat, user_lon = city_coords[city_lower]
st.success(f"📍 Found coordinates: {user_lat:.4f}, {user_lon:.4f}")
else:
st.warning("City not found in database. Using default location.")
# Store location in session state
st.session_state['user_lat'] = user_lat
st.session_state['user_lon'] = user_lon
st.divider()
st.markdown("- Generate a new recommendation below\n- Log sustainability in the tracker")
# Add the 'agents' directory to the Python path
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), 'agents')))
# Import the run_agent_collaboration function from agent_setup
from agents.agent_setup import run_agent_collaboration
# Import enhanced models with Llama 2 integration
from models.enhanced_weather_analyst import EnhancedWeatherAnalyst
from models.enhanced_pest_predictor import EnhancedPestDiseasePredictor
from crop_rotation_planner import CropRotationPlanner
from fertilizer_optimizer import FertilizerOptimizer
# --- Soil Analysis Function ---
def analyze_soil_from_photo(uploaded_file):
try:
image = Image.open(uploaded_file).convert("RGB")
image_array = np.array(image)
avg_color = np.mean(image_array, axis=(0, 1))
r, g, b = avg_color
# Define typical RGB ranges for soil types
if r > 120 and g < 110 and b < 110 and r > g and r > b:
return "Clay"
elif r > 90 and g > 90 and b < 80 and abs(r - g) < 30:
return "Sandy"
elif r < 120 and g < 120 and b < 120 and abs(r - g) < 20 and abs(g - b) < 20:
return "Loamy"
# Fallback with Euclidean distance
clay_rgb = (150, 80, 80)
sandy_rgb = (140, 120, 60)
loamy_rgb = (80, 70, 60)
def rgb_distance(rgb1, rgb2):
return np.sqrt(sum((a - b) ** 2 for a, b in zip(rgb1, rgb2)))
distances = {
"Clay": rgb_distance((r, g, b), clay_rgb),
"Sandy": rgb_distance((r, g, b), sandy_rgb),
"Loamy": rgb_distance((r, g, b), loamy_rgb)
}
return min(distances, key=distances.get)
except Exception as e:
st.error(f"Error processing image: {str(e)}")
return None
# --- Recommendation Parsing ---
def parse_recommendation(recommendation_text):
crops_data = []
crop_entries = recommendation_text.split("Plant ")[1:]
for entry in crop_entries:
crop_match = re.match(r"(\w+):", entry)
if not crop_match:
continue
crop = crop_match.group(1)
scores = {
"Market Score": float(re.search(r"market score: ([\d.]+)", entry).group(1)),
"Weather Suitability": float(re.search(r"weather suitability: ([\d.]+)", entry).group(1)),
"Sustainability": float(re.search(r"sustainability: ([\d.]+)", entry).group(1)),
"Carbon Footprint": float(re.search(r"carbon footprint: ([\d.]+)", entry).group(1)),
"Water": float(re.search(r"water: ([\d.]+)", entry).group(1)),
"Erosion": float(re.search(r"erosion: ([\d.]+)", entry).group(1)),
"Final Score": float(re.search(r"Final Score: ([\d.]+)", entry).group(1))
}
price_match = re.search(r"\(\$([\d.]+)/ton\)", entry)
market_price = float(price_match.group(1)) if price_match else 0.0
crops_data.append({"crop": crop, "scores": scores, "market_price": market_price})
return crops_data
# --- Enhanced Modern & Robust Custom CSS with Vibrant Colors, Gradients, and 3D Light Background ---
st.markdown("""
<style>
@keyframes fadeIn {
from {opacity: 0; transform: translateY(20px);}
to {opacity: 1; transform: translateY(0);}
}
@keyframes glow {
0% { text-shadow: 0 0 5px rgba(255,255,255,0.5); }
50% { text-shadow: 0 0 15px rgba(255,255,255,0.8); }
100% { text-shadow: 0 0 5px rgba(255,255,255,0.5); }
}
html, body, [class*="css"] {
font-family: 'Inter', 'Segoe UI', Arial, sans-serif;
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%), url('https://images.pexels.com/photos/4406323/pexels-photo-4406323.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2') no-repeat center center fixed;
background-size: cover;
background-blend-mode: lighten;
color: #ffffff;
}
.main { background-color: transparent !important; padding: 0; }
.stButton>button {
width: 100%;
margin-top: 1rem;
margin-bottom: 2rem;
background: linear-gradient(90deg, #00ff85 0%, #00bfff 100%);
color: #1e3c72;
border: none;
border-radius: 20px;
padding: 1rem;
font-weight: 700;
font-size: 1.2em;
letter-spacing: 0.5px;
transition: all 0.3s ease;
box-shadow: 0 6px 15px rgba(0,191,255,0.3);
}
.stButton>button:hover {
transform: translateY(-3px) scale(1.05);
box-shadow: 0 10px 30px rgba(0,191,255,0.5);
background: linear-gradient(90deg, #00bfff 0%, #00ff85 100%);
}
.card-section {
background: linear-gradient(135deg, rgba(255,255,255,0.9) 0%, rgba(227,242,253,0.9) 100%);
border-radius: 25px;
margin: 30px 0;
box-shadow: 0 10px 30px rgba(30,60,114,0.15);
padding: 2.5rem 2rem 2rem 2rem;
transition: all 0.3s ease;
animation: fadeIn 0.8s ease-out;
position: relative;
backdrop-filter: blur(5px);
}
.card-section:hover {
transform: translateY(-8px) scale(1.02);
box-shadow: 0 15px 40px rgba(30,60,114,0.25);
}
.section-step {
position: absolute;
top: -25px;
left: 30px;
background: linear-gradient(90deg, #00ff85 0%, #00bfff 100%);
color: #ffffff;
font-weight: 700;
font-size: 1.2em;
border-radius: 50px;
padding: 0.5em 1.3em;
box-shadow: 0 3px 10px rgba(0,191,255,0.2);
letter-spacing: 1px;
animation: glow 2s infinite;
}
.section-icon {
font-size: 2.2em;
margin-right: 0.6em;
vertical-align: middle;
color: #00bfff;
}
.section-instructions {
color: #1e3c72;
font-size: 1.1em;
margin-bottom: 1.2em;
margin-top: 0.6em;
font-weight: 500;
}
.score-header {
text-align: center;
color: #00ff85;
margin-bottom: 2.5rem;
font-weight: 700;
font-size: 2.2em;
text-shadow: 0 0 10px rgba(0,255,133,0.3);
animation: glow 2s infinite;
}
/* Smooth scrolling for navigation */
html {
scroll-behavior: smooth;
}
/* Navigation button hover effects */
.nav-button {
transition: all 0.3s ease;
cursor: pointer;
}
.nav-button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(0,191,255,0.3);
}
@media (max-width: 900px) {
.card-section, .score-header { font-size: 1em !important; }
.stButton>button { font-size: 1em; }
}
@media (max-width: 600px) {
.card-section { padding: 1.5rem; font-size: 0.95em; }
.score-header { font-size: 1.8em !important; }
.stButton>button { font-size: 1em; padding: 0.8rem; }
}
</style>
""", unsafe_allow_html=True)
# --- Hero Section ---
st.markdown("""
<div style='background: linear-gradient(120deg, #00ff85 0%, #00bfff 100%), url("https://images.unsplash.com/photo-1506744038136-46273834b3fb?auto=format&fit=crop&w=1200&q=80"); background-size: cover; background-blend-mode: overlay; border-radius: 25px; padding: 4rem 2rem 3rem 2rem; margin-bottom: 3rem; box-shadow: 0 10px 40px rgba(0,191,255,0.3); color: white; text-align: center; animation: fadeIn 1s ease-out;'>
<h1 style='font-size:3em; margin-bottom: 0.5em; letter-spacing: 1.5px; text-shadow: 0 0 10px rgba(255,255,255,0.5);'>🌾 Sustainable Farming AI Platform</h1>
<p style='font-size:1.4em; margin-bottom: 1.5em; max-width: 650px; margin-left:auto; margin-right:auto;'>Empowering farmers with <b>real-time, AI-powered recommendations</b> for a greener, more profitable future. Plan, optimize, and track your farm with ease—on any device.</p>
<div style='display: flex; flex-wrap: wrap; justify-content: center; gap: 1.5em; margin-bottom: 1.5em;'>
<div style='background: rgba(255,255,255,0.2); border-radius: 15px; padding: 1.2em 1.8em; font-size: 1.2em; display: flex; align-items: center; gap: 0.6em; box-shadow: 0 4px 15px rgba(255,255,255,0.2);'><span style='font-size:1.8em;'>🌱</span> Crop Planning</div>
<div style='background: rgba(255,255,255,0.2); border-radius: 15px; padding: 1.2em 1.8em; font-size: 1.2em; display: flex; align-items: center; gap: 0.6em; box-shadow: 0 4px 15px rgba(255,255,255,0.2);'><span style='font-size:1.8em;'>🧪</span> Fertilizer Optimization</div>
<div style='background: rgba(255,255,255,0.2); border-radius: 15px; padding: 1.2em 1.8em; font-size: 1.2em; display: flex; align-items: center; gap: 0.6em; box-shadow: 0 4px 15px rgba(255,255,255,0.2);'><span style='font-size:1.8em;'>📊</span> Sustainability Tracking</div>
<div style='background: rgba(255,255,255,0.2); border-radius: 15px; padding: 1.2em 1.8em; font-size: 1.2em; display: flex; align-items: center; gap: 0.6em; box-shadow: 0 4px 15px rgba(255,255,255,0.2);'><span style='font-size:1.8em;'>🤖</span> AI Insights</div>
</div>
<div style='margin-top: 1.5em; font-size: 1.2em; background: rgba(255,255,255,0.15); border-radius: 10px; display: inline-block; padding: 0.8em 1.8em; box-shadow: 0 4px 15px rgba(255,255,255,0.2);'>
<b>Get started below — follow the steps for a seamless experience!</b>
</div>
</div>
""", unsafe_allow_html=True)
# --- Farmer Usage Instructions ---
st.markdown("""
<div class='card-section'>
<span class='section-step'>📋</span>
<span class='section-icon'>📋</span>
<b style='font-size:1.3em'>How to Use This Platform</b>
<div class='section-instructions'>Follow these simple steps to get the most out of your farming AI assistant:</div>
</div>
""", unsafe_allow_html=True)
# Usage instructions
col1, col2 = st.columns(2)
with col1:
st.markdown("""
### 🌾 **Basic Farming Features**
**1. Farm Details & Soil Analysis**
- Enter your farm size (hectares or cents)
- Upload soil photos or select soil type manually
- Get AI-powered soil analysis and recommendations
**2. Smart Recommendations**
- Click "Generate Smart Recommendation" button
- Get personalized crop suggestions based on your data
- View detailed analysis with charts and insights
**3. Crop Rotation Planning**
- Plan your crop rotation for better soil health
- Get timeline-based planting schedules
- Optimize your farming calendar
""")
with col2:
st.markdown("""
### 🚀 **Advanced Features**
**4. Interactive Farm Map**
- Create visual maps of your farm
- Mark soil zones and risk areas
- Get location-specific recommendations
**5. Community Insights**
- Share your farming data (anonymous)
- Learn from other farmers' experiences
- Get regional yield and price insights
**6. AI Chatbot**
- Ask any farming question
- Get instant expert advice
- Chat history is saved for reference
""")
st.markdown("""
### 💡 **Pro Tips for Farmers**
- **Start with Farm Details**: Always begin by entering your farm size and soil type
- **Use Voice Features**: Enable voice interface for hands-free operation
- **Share Community Data**: Help other farmers by sharing your yield data
- **Check Market Forecasts**: Use price predictions to plan your crops
- **Enable Offline Mode**: Use the app without internet when needed
- **Save Your Maps**: Create and save farm maps for future reference
""")
st.info("🎯 **Quick Start**: Click on any feature button in the sidebar to jump directly to that section!")
# --- Main Content ---
# Anchor for Farm Details
st.markdown('<div id="farm-details"></div>', unsafe_allow_html=True)
st.markdown(f"""
<div class='card-section'>
<span class='section-step'>1</span>
<span class='section-icon'>📏</span>
<b style='font-size:1.3em'>{T['farm_details']}</b>
<div class='section-instructions'>{T.get('farm_details_instruction', 'Enter your farm size and crop preference.')}</div>
<div style='display:flex;gap:2em;justify-content:center;margin-top:1em;'>
<div style='text-align:center;'>
<span style='font-size:2.5em;'>🌾</span><br><span style='font-size:1.1em;'>{T.get('farm_size_label', 'Farm size')}</span>
</div>
<div style='text-align:center;'>
<span style='font-size:2.5em;'>🌱</span><br><span style='font-size:1.1em;'>{T.get('crop_preference_label', 'Crop type')}</span>
</div>
</div>
</div>
""", unsafe_allow_html=True)
# Voice input for farm details
if (st.session_state.get('speech_interface') is not None and
st.session_state.get('voice_enabled', True)):
st.markdown("### 🎤 Voice Input for Farm Details")
voice_data = st.session_state['speech_interface'].create_voice_interface_for_farm_details(lang)
# Update form values with voice input
if voice_data:
if 'land_size' in voice_data:
st.session_state['land_size_voice'] = voice_data['land_size']
if 'crop_preference' in voice_data:
st.session_state['crop_preference_voice'] = voice_data['crop_preference']
if 'soil_type' in voice_data:
st.session_state['soil_type_voice'] = voice_data['soil_type']
col1, col2 = st.columns(2, gap="large")
with col1:
# Use voice input if available, otherwise use slider
if st.session_state.get('land_size_voice'):
land_size = st.session_state['land_size_voice']
st.info(f"🌾 Farm size from voice: {land_size} hectares")
else:
land_size = st.select_slider(
f"🌾 {T.get('farm_size_label', 'Farm size')}",
options=[1, 2, 5, 8, 10, 15, 20],
value=8,
help=T.get('farm_size_help', "Slide to select your farm size")
)
size_unit = st.selectbox(
"Unit",
options=["Hectares", "Cents"],
index=0 # Default to Hectares
)
if size_unit == "Cents":
land_size = land_size * 0.00404686 # Convert cents to hectares
st.caption(f"Converted to {land_size:.2f} hectares for calculations.")
with col2:
# Use voice input if available, otherwise use selectbox
if st.session_state.get('crop_preference_voice'):
crop_preference = st.session_state['crop_preference_voice']
st.info(f"🌱 Crop preference from voice: {crop_preference}")
else:
crop_preference = st.selectbox(
f"🌱 {T.get('crop_preference_label', 'What would you like to grow?')}",
options=["Grains", "Vegetables", "Fruits"],
help=T.get('crop_preference_help', "Choose your preferred crop type")
)
# Anchor for Soil Analysis
st.markdown('<div id="soil-analysis"></div>', unsafe_allow_html=True)
st.markdown(f"""
<div class='card-section'>
<span class='section-step'>2</span>
<span class='section-icon'>🗺️</span>
<b style='font-size:1.3em'>{T['soil_analysis']}</b>
<div class='section-instructions'>{T.get('soil_analysis_instruction', 'Analyze your soil by uploading a photo or selecting manually.')}</div>
<div style='display:flex;gap:2em;justify-content:center;margin-top:1em;'>
<div style='text-align:center;'>
<span style='font-size:2.5em;'>📸</span><br><span style='font-size:1.1em;'>{T['upload_photo']}</span>
</div>
<div style='text-align:center;'>
<span style='font-size:2.5em;'>📝</span><br><span style='font-size:1.1em;'>{T['manual_selection']}</span>
</div>
</div>
</div>
""", unsafe_allow_html=True)
soil_type = None
# Check for voice input for soil type
if st.session_state.get('soil_type_voice'):
soil_type = st.session_state['soil_type_voice']
st.info(f"🗺️ Soil type from voice: {soil_type}")
else:
soil_option = st.radio(
f"🗺️ {T.get('soil_option_label', 'How would you like to determine your soil type?')}",
[T['upload_photo'], T['manual_selection']],
horizontal=True
)
if soil_option == T['upload_photo']:
soil_photo = st.file_uploader(f"📸 {T['upload_photo']}", type=["jpg", "jpeg", "png"], key="soil_photo_uploader")
if soil_photo:
soil_type = analyze_soil_from_photo(soil_photo)
if soil_type:
st.success(f"✅ {T.get('detected_soil_type', 'Detected soil type')}: {soil_type}")
else:
st.warning(T.get('could_not_detect_soil', "⚠️ Could not determine soil type from photo. Please select manually."))
soil_type = st.selectbox(f"📝 {T['select_soil_type']}", options=["Loamy", "Sandy", "Clay"], key="manual_soil_select")
else:
soil_type = st.selectbox(f"📝 {T['select_soil_type']}", options=["Loamy", "Sandy", "Clay"], key="manual_soil_select_fallback")
elif soil_option == T['manual_selection']:
soil_type = st.selectbox(f"📝 {T['select_soil_type']}", options=["Loamy", "Sandy", "Clay"], key="manual_soil_select")
# Anchor for Smart Recommendation
st.markdown('<div id="smart-recommendation"></div>', unsafe_allow_html=True)
st.markdown(f"""
<div class='card-section'>
<span class='section-step'>3</span>
<span class='section-icon'>💡</span>
<b style='font-size:1.3em'>{T['generate_recommendation']}</b>
<div class='section-instructions'>{T.get('recommendation_instruction', 'Click the button below to get your personalized AI-powered recommendation!')}</div>
<div style='display:flex;gap:2em;justify-content:center;margin-top:1em;'>
<div style='text-align:center;'>
<span style='font-size:2.5em;'>🤖</span><br><span style='font-size:1.1em;'>{T['generate_recommendation']}</span>
</div>
</div>
</div>
""", unsafe_allow_html=True)
# --- Recommendation Generation ---
if st.button(T['generate_recommendation'], type="primary"):
# Progress feedback
progress = st.progress(0)
for i in range(0, 61, 12):
time.sleep(0.05)
progress.progress(min(i, 60))
with st.spinner("🔄 Analyzing your farm conditions..."):
try:
result = run_agent_collaboration(land_size=land_size, soil_type=soil_type, crop_preference=crop_preference)
progress.progress(80)
crops_data = parse_recommendation(result['recommendation'])
# --- Enhanced Weather Forecasting with Llama 2 ---
weather_analyst = EnhancedWeatherAnalyst()
soil_ph = 6.5
soil_moisture = 25
# Get user's location from session state
user_lat = st.session_state.get('user_lat', 12.9716)
user_lon = st.session_state.get('user_lon', 77.5946)
# Get comprehensive weather forecast with agricultural insights
weather_data = weather_analyst.forecast_agricultural_conditions(
lat=user_lat,
lon=user_lon,
crop_type=crop_preference
)
# Organize results into tabs
tab_summary, tab_charts, tab_details = st.tabs(["Summary", "Charts", "Details"])
with tab_summary:
st.markdown(T['weather_forecast'])
# Display location info
st.info(f"📍 **Location:** {user_lat:.4f}°N, {user_lon:.4f}°E")
# Display current weather
current = weather_data['current_weather']
st.info(f"**Current Conditions:** Temperature: {current['temperature']:.1f}°C, "
f"Humidity: {current['humidity']:.1f}%, "
f"Description: {current['description']}")
# Display forecast metrics
metrics = weather_data['metrics']
st.info(f"**5-Day Forecast:** Avg Temperature: {metrics['avg_temperature']:.1f}°C, "
f"Total Rainfall: {metrics['total_rainfall']:.1f}mm, "
f"Avg Humidity: {metrics['avg_humidity']:.1f}%")
# Display AI analysis
st.markdown("**🤖 AI Weather Analysis:**")
st.text(weather_data['analysis'])
# Display agricultural conditions
conditions = weather_data['agricultural_conditions']
risk_color = "🔴" if conditions['overall_risk'] == 'high' else "🟡" if conditions['overall_risk'] == 'medium' else "🟢"
st.markdown(f"**Agricultural Risk Level:** {risk_color} {conditions['overall_risk'].upper()}")
# Display recommendations
if weather_data['recommendations']:
st.markdown("**💡 Weather Recommendations:**")
for rec in weather_data['recommendations']:
st.text(f"• {rec}")
# --- Enhanced Pest/Disease Prediction with Llama 2 ---
pest_predictor = EnhancedPestDiseasePredictor()
pest_prediction = pest_predictor.predict(
crop_type=crop_preference,
soil_ph=soil_ph,
soil_moisture=soil_moisture,
temperature=current['temperature'],
rainfall=metrics['total_rainfall'],
additional_data={
'weather': current,
'soil': {'ph': soil_ph, 'moisture': soil_moisture, 'type': soil_type}
}
)
with tab_summary:
st.markdown(T['pest_prediction'])
st.text(pest_prediction)
st.markdown(T['personalized_recommendation'])
# Text-to-speech for recommendations
if (st.session_state.get('speech_interface') is not None and
st.session_state.get('voice_enabled', True)):
st.markdown("### 🔊 Listen to Recommendations")
# Debug information
with st.expander("🔧 Debug Information", expanded=False):
st.write(f"Speech interface available: {st.session_state.get('speech_interface') is not None}")
st.write(f"Voice enabled: {st.session_state.get('voice_enabled', False)}")
if st.session_state.get('speech_interface'):
si = st.session_state['speech_interface']
st.write(f"PyAudio available: {si.pyaudio_available}")
st.write(f"TTS engine available: {si.tts_engine is not None}")
st.write(f"Language: {lang}")
st.write(f"Recommendation length: {len(result['recommendation'])} characters")
# Test button
if st.button("🔊 Test TTS with Simple Text", key="test_tts_simple"):
with st.spinner("Testing TTS..."):
success = si.text_to_speech("Hello, this is a test of text to speech.", lang)
if success:
st.success("✅ TTS test successful!")
else:
st.error("❌ TTS test failed!")
# Main recommendation button
if st.button("🔊 Listen to Full Recommendation", key="speak_recommendation", help="Listen to the complete farming recommendation"):
with st.spinner("Generating audio for recommendation..."):
success = st.session_state['speech_interface'].text_to_speech(result['recommendation'], lang)
if success:
st.success("✅ Audio generated successfully! Check your speakers.")
else:
st.error("❌ Failed to generate audio. Please try again.")
# Additional analysis buttons
col1, col2 = st.columns(2)
with col1:
if st.button("🔊 Listen to Weather Analysis", key="speak_weather", help="Listen to weather analysis"):
with st.spinner("Generating weather audio..."):
success = st.session_state['speech_interface'].text_to_speech(weather_data['analysis'], lang)
if success:
st.success("✅ Weather audio generated!")
else:
st.error("❌ Failed to generate weather audio.")
with col2:
if st.button("🔊 Listen to Pest Prediction", key="speak_pest", help="Listen to pest and disease prediction"):
with st.spinner("Generating pest prediction audio..."):
success = st.session_state['speech_interface'].text_to_speech(pest_prediction, lang)
if success:
st.success("✅ Pest prediction audio generated!")
else:
st.error("❌ Failed to generate pest prediction audio.")
# Download button for full recommendation text
st.download_button(
label="⬇️ Download Recommendation",
data=result['recommendation'],
file_name="recommendation.txt",
mime="text/plain"
)
if 'Weather Forecast' in result and result['Weather Forecast']:
with tab_summary:
st.markdown("#### 🌤️ Weather Forecast (Agent)")
st.info(result['Weather Forecast'])
if 'Pest/Disease Prediction' in result and result['Pest/Disease Prediction']:
with tab_summary:
st.markdown("#### 🐛 Pest/Disease Prediction (Agent)")
st.info(result['Pest/Disease Prediction'])
if 'Warnings' in result and result['Warnings']:
with tab_summary:
for warn in result['Warnings']:
st.warning(f"Weather Alert: {warn}")
if 'Pest/Disease Advice' in result and result['Pest/Disease Advice']:
with tab_summary:
st.info(f"Pest/Disease Advice: {result['Pest/Disease Advice']}")
with tab_charts:
for crop_data in crops_data:
crop = crop_data['crop']
scores = crop_data['scores']
market_price = crop_data['market_price']
labels = list(scores.keys())
values = [score * 100 for score in scores.values()]
fig = go.Figure(data=[go.Bar(y=labels, x=values, orientation='h', marker=dict(color=[
"#00ff85", "#00bfff", "#ffcc00", "#ff6b6b", "#4ecdc4", "#45b7d1", "#ff9f1c"
]), text=[f"{val:.1f}%" for val in values], textposition='auto')])
fig.update_layout(title=f"{crop.capitalize()} Scores (Market Price: ${market_price:.2f}/ton)", title_x=0.5, xaxis_title="Score (%)", yaxis_title="Category", xaxis=dict(range=[0, 100]), margin=dict(l=0, r=0, t=40, b=0), height=400)
st.plotly_chart(fig, use_container_width=True)
with tab_charts:
st.markdown("<h3 class='score-header'>📊 Detailed Score Analysis</h3>", unsafe_allow_html=True)
for chart in result['chart_data']:
crop = chart['crop']
labels = chart['labels']
values = chart['values']
fig = go.Figure(data=[go.Pie(labels=labels, values=values, textinfo='label+percent', hoverinfo='label+value', marker=dict(colors=[
"#00ff85", "#00bfff", "#ffcc00", "#ff6b6b", "#4ecdc4", "#45b7d1", "#ff9f1c"
]))])
fig.update_layout(title=f"{crop.capitalize()} Score Distribution", title_x=0.5, margin=dict(l=0, r=0, t=40, b=0), legend=dict(orientation="h", yanchor="bottom", y=-0.2, xanchor="center", x=0.5))
st.plotly_chart(fig, use_container_width=True)
with tab_details:
details = result['recommendation'].split("Details:")[1].strip()
details_html = details.replace('\n', '<br>')
st.markdown(f"<div class='card-section'><strong>{T['details']}</strong><br>{details_html}</div>", unsafe_allow_html=True)
# Text-to-speech for details
if (st.session_state.get('speech_interface') is not None and
st.session_state.get('voice_enabled', True)):
st.markdown("### 🔊 Listen to Details")
if st.button("🔊 Listen to Recommendation Details", key="speak_details", help="Listen to the detailed farming recommendations"):
with st.spinner("Generating details audio..."):
success = st.session_state['speech_interface'].text_to_speech(details, lang)
if success:
st.success("✅ Details audio generated!")
else:
st.error("❌ Failed to generate details audio.")
progress.progress(100)
st.balloons()
except Exception as e:
st.error(f"⚠️ An error occurred: {str(e)}")
# Anchor for Crop Rotation Planner
st.markdown('<div id="crop-rotation-planner"></div>', unsafe_allow_html=True)
st.markdown("<hr>", unsafe_allow_html=True)
st.header(T['crop_rotation_planner'])
planner = CropRotationPlanner(db_path=db_path)
try:
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute("SELECT crop FROM recommendations ORDER BY timestamp DESC LIMIT 1")
latest_crop = cursor.fetchone()
if latest_crop:
latest_crop = latest_crop[0]
plan = planner.generate_plan(latest_crop)
st.success(f"Last planted crop: {latest_crop}. Suggested rotation plan:")
st.plotly_chart(planner.create_timeline(plan), use_container_width=True)
else:
st.info("No crop history found. Generate a recommendation to start building your rotation plan!")
except Exception as e:
st.warning(f"Could not load crop rotation plan: {str(e)}")
# Anchor for Fertilizer Optimization
st.markdown('<div id="fertilizer-optimization"></div>', unsafe_allow_html=True)
st.markdown("<hr>", unsafe_allow_html=True)
st.header(T['fertilizer_optimization'])
with st.form("fertilizer_form"):
col1, col2, col3 = st.columns(3)
with col1:
fert_soil = st.selectbox("Soil Type", ["Loamy", "Sandy", "Clay"], key="fert_soil")
with col2:
fert_crop = st.selectbox("Crop Type", ["Wheat", "Corn", "Rice", "Soybeans", "Tomatoes", "Carrots"], key="fert_crop")
with col3:
fert_land = st.number_input("Land Size (hectares)", min_value=1, max_value=100, value=8, key="fert_land")
submitted = st.form_submit_button("Calculate Optimal Fertilizer")
if submitted and 'fert_soil' in st.session_state and 'fert_crop' in st.session_state and 'fert_land' in st.session_state:
optimizer = FertilizerOptimizer(db_path=db_path)
result = optimizer.calculate_fertilizer(st.session_state['fert_land'], st.session_state['fert_soil'], st.session_state['fert_crop'])
st.success(f"For {st.session_state['fert_land']} hectares of {st.session_state['fert_soil'].lower()} soil planting {st.session_state['fert_crop'].lower()}, use:")
st.write(f"- Nitrogen: {result['nitrogen_kg']} kg")
st.write(f"- Phosphorus: {result['phosphorus_kg']} kg")
st.write(f"- Potassium: {result['potassium_kg']} kg")
st.caption("*This recommendation factors in sustainability by reducing excess fertilizer to lower carbon footprint.")
# Anchor for Previous Recommendations
st.markdown('<div id="previous-recommendations"></div>', unsafe_allow_html=True)
st.markdown(f"<h3 class='score-header'>{T['previous_recommendations']}</h3>", unsafe_allow_html=True)
st.subheader(T['previous_recommendations'], divider="green")
try:
with sqlite3.connect(db_path) as conn:
past_recommendations = pd.read_sql("SELECT * FROM recommendations ORDER BY timestamp DESC LIMIT 5", conn)
if not past_recommendations.empty:
st.dataframe(
past_recommendations[['crop', 'score', 'rationale', 'carbon_score', 'water_score', 'erosion_score', 'timestamp']],
use_container_width=True,
column_config={
"crop": "Crop",
"score": "Final Score",
"rationale": "Rationale",
"carbon_score": "Carbon Footprint Score",
"water_score": "Water Score",
"erosion_score": "Erosion Score",
"timestamp": "Timestamp"
},
hide_index=True
)
# Update sidebar CSV download
st.session_state['last_recs_csv'] = past_recommendations.to_csv(index=False)
else:
st.info("No past recommendations found.")
except Exception as e:
st.warning(f"Could not load past recommendations: {str(e)}")
# Anchor for Sustainability Score Tracker
st.markdown('<div id="sustainability-score-tracker"></div>', unsafe_allow_html=True)
# --- Sustainability Score Tracker ---
st.markdown("<hr>", unsafe_allow_html=True)
st.header("🌱 Sustainability Score Tracker")
# Recommended values
RECOMMENDED_WATER = 2.0 # e.g., 2 ML/ha/season
RECOMMENDED_FERTILIZER = 1.5 # e.g., 1.5 tons/ha/season
# Helper: Calculate sustainability score
def calculate_sustainability_score(row):
score = 100
water = row.get('water_score', 0)
if water > RECOMMENDED_WATER:
score -= min(30, 30 * (water - RECOMMENDED_WATER) / RECOMMENDED_WATER)
fert = row.get('fertilizer_use', 0)
if fert > RECOMMENDED_FERTILIZER:
score -= min(30, 30 * (fert - RECOMMENDED_FERTILIZER) / RECOMMENDED_FERTILIZER)
if row.get('rotation', False):
score += 10
else:
score -= 10
return max(0, min(100, score))
# Ensure sustainability_scores table exists
with sqlite3.connect(db_path) as conn:
conn.execute('''CREATE TABLE IF NOT EXISTS sustainability_scores (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT,
water_score REAL,
fertilizer_use REAL,
rotation INTEGER,
score REAL
)''')
conn.commit()
# --- Voice Input for Sustainability Data ---
if (st.session_state.get('speech_interface') is not None and
st.session_state.get('voice_enabled', True)):
st.markdown("### 🎤 Voice Input for Sustainability Data")
voice_sustainability_data = st.session_state['speech_interface'].create_voice_interface_for_sustainability(lang)
# Update form values with voice input
if voice_sustainability_data:
if 'water_score' in voice_sustainability_data:
st.session_state['voice_water_score'] = voice_sustainability_data['water_score']
if 'fertilizer_use' in voice_sustainability_data:
st.session_state['voice_fertilizer_use'] = voice_sustainability_data['fertilizer_use']
if 'rotation' in voice_sustainability_data:
st.session_state['voice_rotation'] = voice_sustainability_data['rotation']
# --- User Input for Current Season ---
with st.form("sustainability_form"):
st.markdown("**Log your current season's practices:**")
col1, col2, col3 = st.columns(3)
with col1:
# Use voice input if available
if st.session_state.get('voice_water_score'):
water_score = st.session_state['voice_water_score']
st.info(f"💧 Water usage from voice: {water_score} ML/ha")
else:
water_score = st.number_input("Water usage (ML/ha)", min_value=0.0, max_value=10.0, value=RECOMMENDED_WATER, step=0.1)
with col2:
# Use voice input if available
if st.session_state.get('voice_fertilizer_use'):
fertilizer_use = st.session_state['voice_fertilizer_use']
st.info(f"🧪 Fertilizer use from voice: {fertilizer_use} tons/ha")
else:
fertilizer_use = st.number_input("Fertilizer use (tons/ha)", min_value=0.0, max_value=10.0, value=RECOMMENDED_FERTILIZER, step=0.1)
with col3:
# Use voice input if available
if st.session_state.get('voice_rotation') is not None:
rotation = st.session_state['voice_rotation']
st.info(f"🔄 Crop rotation from voice: {'Yes' if rotation else 'No'}")
else:
rotation = st.checkbox("Practiced crop rotation?", value=True)
submitted = st.form_submit_button("Log Season")
if submitted:
score = calculate_sustainability_score({'water_score': water_score, 'fertilizer_use': fertilizer_use, 'rotation': rotation})
ts = datetime.now().strftime("%Y-%m-%d")
with sqlite3.connect(db_path) as conn:
conn.execute("INSERT INTO sustainability_scores (timestamp, water_score, fertilizer_use, rotation, score) VALUES (?, ?, ?, ?, ?)",
(ts, water_score, fertilizer_use, int(rotation), score))
conn.commit()
st.success(f"Logged! Your sustainability score for this season: {score:.1f}")
# Fetch all scores
with sqlite3.connect(db_path) as conn:
df_scores = pd.read_sql("SELECT * FROM sustainability_scores ORDER BY timestamp ASC", conn)
# Plot trend chart
if not df_scores.empty:
fig = go.Figure()
fig.add_trace(go.Scatter(x=df_scores['timestamp'], y=df_scores['score'], mode='lines+markers', name='Sustainability Score', line=dict(color='#00ff85', width=3)))
fig.update_layout(title="Sustainability Score Over Time", xaxis_title="Season", yaxis_title="Score", height=350)
st.plotly_chart(fig, use_container_width=True)
if len(df_scores) > 1:
prev = df_scores['score'].iloc[-2]
curr = df_scores['score'].iloc[-1]
pct = ((curr - prev) / prev) * 100 if prev != 0 else 0
if pct > 0:
st.success(f"Your sustainability score has improved by {pct:.1f}% since last season!")
elif pct < 0:
st.warning(f"Your sustainability score has decreased by {abs(pct):.1f}% since last season.")
else:
st.info("Your sustainability score is unchanged since last season.")
tips = []
last = df_scores.iloc[-1]
if last['fertilizer_use'] > RECOMMENDED_FERTILIZER:
tips.append(f"Reduce fertilizer use to below {RECOMMENDED_FERTILIZER} tons/ha. Try organic options.")
if last['water_score'] > RECOMMENDED_WATER:
tips.append(f"Reduce water usage to below {RECOMMENDED_WATER} ML/ha. Consider drip irrigation or mulching.")
if not last['rotation']:
tips.append("Practice crop rotation next season to improve soil health and sustainability.")
if tips:
st.markdown("**Tips to improve your score:**")
for tip in tips:
st.info(tip)
else:
st.success("Great job! Your practices are highly sustainable.")
else:
st.info("No sustainability score data found. Log your first season above!")
# --- Interactive Farm Map ---
st.markdown('<div id="interactive-farm-map"></div>', unsafe_allow_html=True)
st.markdown("<hr style='border-color: rgba(255,255,255,0.3);'>", unsafe_allow_html=True)
st.header("🗺️ Interactive Farm Map")
# Farm Map Section
st.markdown("""
<div class='card-section'>
<span class='section-step'>🗺️</span>
<span class='section-icon'>🗺️</span>
<b style='font-size:1.3em'>Interactive Farm Mapping</b>
<div class='section-instructions'>Upload or draw your farm map to get location-specific recommendations and risk analysis.</div>
</div>
""", unsafe_allow_html=True)
# Map creation options
map_option = st.radio(
"Choose map creation method:",
["Create New Map", "Load Existing Map", "Upload Farm Image"],
horizontal=True
)
if map_option == "Create New Map":
# Get farm coordinates
col1, col2 = st.columns(2)
with col1:
farm_lat = st.number_input("Farm Latitude", value=12.9716, min_value=-90.0, max_value=90.0, step=0.0001)
with col2:
farm_lon = st.number_input("Farm Longitude", value=77.5946, min_value=-180.0, max_value=180.0, step=0.0001)
# Create interactive map
m = folium.Map(
location=[farm_lat, farm_lon],
zoom_start=15,
tiles='OpenStreetMap'
)
# Add farm boundary (example)
farm_boundary = folium.Rectangle(
bounds=[[farm_lat-0.001, farm_lon-0.001], [farm_lat+0.001, farm_lon+0.001]],
color='green',
fill=True,
fillColor='lightgreen',
fillOpacity=0.3,
popup='Your Farm'
)
farm_boundary.add_to(m)
# Add soil zones
soil_zones = [
{"lat": farm_lat-0.0005, "lon": farm_lon-0.0005, "soil": "Clay", "color": "brown"},
{"lat": farm_lat+0.0005, "lon": farm_lon-0.0005, "soil": "Sandy", "color": "yellow"},
{"lat": farm_lat-0.0005, "lon": farm_lon+0.0005, "soil": "Loamy", "color": "green"},
{"lat": farm_lat+0.0005, "lon": farm_lon+0.0005, "soil": "Clay", "color": "brown"}
]
for zone in soil_zones:
folium.CircleMarker(
location=[zone["lat"], zone["lon"]],
radius=20,
popup=f"Soil Type: {zone['soil']}",
color=zone["color"],
fill=True,
fillColor=zone["color"],
fillOpacity=0.7
).add_to(m)
# Add risk areas
risk_areas = [
{"lat": farm_lat-0.0003, "lon": farm_lon+0.0003, "risk": "Erosion Risk", "color": "red"},
{"lat": farm_lat+0.0003, "lon": farm_lon-0.0003, "risk": "Waterlogging", "color": "blue"}
]
for area in risk_areas:
folium.Marker(
location=[area["lat"], area["lon"]],
popup=f"⚠️ {area['risk']}",
icon=folium.Icon(color=area["color"], icon='warning-sign')
).add_to(m)
# Display map
st_folium(m, width=700, height=500)
# Map Legend and Explanation
st.markdown("### 🗺️ Map Legend & Features")
col1, col2, col3 = st.columns(3)
with col1:
st.markdown("""
**🌱 Soil Zones:**
- 🟤 **Brown Circles**: Clay soil areas
- 🟡 **Yellow Circles**: Sandy soil areas
- 🟢 **Green Circles**: Loamy soil areas
""")
with col2:
st.markdown("""
**⚠️ Risk Areas:**
- 🔴 **Red Markers**: Erosion risk zones
- 🔵 **Blue Markers**: Waterlogging areas
- ⚠️ **Warning Icons**: High-risk locations
""")
with col3:
st.markdown("""
**🏡 Farm Features:**
- 🟢 **Green Rectangle**: Your farm boundary
- 📍 **Markers**: Specific locations
- 🗺️ **Interactive**: Click and zoom to explore
""")
st.info("💡 **Tip**: Click on any marker or zone to see detailed information about that area!")
# Save map data
if st.button("💾 Save Farm Map"):
map_data = {
"center": [farm_lat, farm_lon],
"soil_zones": soil_zones,
"risk_areas": risk_areas,
"boundary": [[farm_lat-0.001, farm_lon-0.001], [farm_lat+0.001, farm_lon+0.001]]
}
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute("""
INSERT OR REPLACE INTO farm_maps
(username, farm_name, map_data, recommendations, risk_areas, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?)
""", (
user['username'],
user['farm_name'],
json.dumps(map_data),
json.dumps({"recommendations": ["Plant soybeans in northern section", "Avoid planting in erosion risk area"]}),
json.dumps(risk_areas),
datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
datetime.now().strftime("%Y-%m-%d %H:%M:%S")
))
conn.commit()
st.success("✅ Farm map saved successfully!")
elif map_option == "Load Existing Map":
try:
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM farm_maps WHERE username = ? ORDER BY updated_at DESC LIMIT 1", (user['username'],))
map_record = cursor.fetchone()
except Exception as e:
st.error(f"Could not load farm map: {e}")
map_record = None
if map_record:
map_data = json.loads(map_record[3])
recommendations = json.loads(map_record[4])
risk_areas = json.loads(map_record[5])
# Recreate map from saved data
m = folium.Map(
location=map_data["center"],
zoom_start=15,
tiles='OpenStreetMap'
)
# Add farm boundary
farm_boundary = folium.Rectangle(
bounds=map_data["boundary"],
color='green',
fill=True,
fillColor='lightgreen',
fillOpacity=0.3,
popup='Your Farm'
)
farm_boundary.add_to(m)
# Add soil zones
for zone in map_data["soil_zones"]:
folium.CircleMarker(
location=[zone["lat"], zone["lon"]],
radius=20,
popup=f"Soil Type: {zone['soil']}",
color=zone["color"],
fill=True,
fillColor=zone["color"],
fillOpacity=0.7
).add_to(m)
# Add risk areas
for area in risk_areas:
folium.Marker(
location=[area["lat"], area["lon"]],
popup=f"⚠️ {area['risk']}",
icon=folium.Icon(color=area["color"], icon='warning-sign')
).add_to(m)
st_folium(m, width=700, height=500)
# Map Legend for Loaded Map
st.markdown("### 🗺️ Your Farm Map Legend")
col1, col2, col3 = st.columns(3)
with col1:
st.markdown("""
**🌱 Soil Zones:**
- 🟤 **Brown**: Clay soil
- 🟡 **Yellow**: Sandy soil
- 🟢 **Green**: Loamy soil
""")
with col2:
st.markdown("""
**⚠️ Risk Areas:**
- 🔴 **Red**: Erosion risk
- 🔵 **Blue**: Waterlogging
- ⚠️ **Warning**: High risk
""")
with col3:
st.markdown("""
**🏡 Farm Layout:**
- 🟢 **Green**: Farm boundary
- 📍 **Markers**: Key locations
- 🗺️ **Interactive**: Click to explore
""")
# Display recommendations
st.markdown("### 📋 Location-Specific Recommendations")
for rec in recommendations["recommendations"]:
st.info(f"💡 {rec}")
else:
st.info("No saved farm map found. Create a new map first!")
elif map_option == "Upload Farm Image":
uploaded_image = st.file_uploader("Upload Farm Image", type=["jpg", "jpeg", "png"])
if uploaded_image:
st.image(uploaded_image, caption="Your Farm Image", use_column_width=True)
st.info("🔄 Image analysis in progress... This feature will analyze your farm image and create recommendations based on visual soil and terrain analysis.")
# --- Community Insights ---
st.markdown('<div id="community-insights"></div>', unsafe_allow_html=True)
st.markdown("<hr style='border-color: rgba(255,255,255,0.3);'>", unsafe_allow_html=True)
st.header("👥 Community Insights")
st.markdown("""
<div class='card-section'>
<span class='section-step'>👥</span>
<span class='section-icon'>👥</span>
<b style='font-size:1.3em'>Community-Driven Insights</b>
<div class='section-instructions'>Share and learn from anonymized community data on crop yields, market prices, and sustainability practices.</div>
</div>
""", unsafe_allow_html=True)
# Community data sharing
with st.expander("📊 Share Your Data (Anonymous)"):
st.markdown("**Help the community by sharing your farming data:**")
with st.form("community_data_form"):
col1, col2 = st.columns(2)
with col1:
crop_type = st.selectbox("Crop Type", ["Rice", "Wheat", "Corn", "Soybean", "Tomato", "Potato", "Other"])
yield_data = st.number_input("Yield (tons/hectare)", min_value=0.0, max_value=50.0, step=0.1)
with col2:
market_price = st.number_input("Market Price (₹/ton)", min_value=0, max_value=100000, step=100)
region = st.selectbox("Region", ["North", "South", "East", "West", "Central"])
sustainability_practice = st.selectbox("Sustainability Practice", [
"Organic Farming", "Drip Irrigation", "Crop Rotation",
"Integrated Pest Management", "Conservation Tillage", "Other"
])
season = st.selectbox("Season", ["Kharif", "Rabi", "Zaid", "Year-round"])
if st.form_submit_button("📤 Share Data"):
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute("""
INSERT INTO community_insights
(username, crop_type, yield_data, market_price, sustainability_practice, region, season, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
""", (
user['username'], crop_type, yield_data, market_price,
sustainability_practice, region, season,
datetime.now().strftime("%Y-%m-%d %H:%M:%S")
))
conn.commit()
st.success("✅ Data shared successfully! Thank you for contributing to the community.")
# Community insights display
st.markdown("### 📈 Community Insights Dashboard")
# Get community data
try:
with sqlite3.connect(db_path) as conn:
community_data = pd.read_sql("""
SELECT crop_type, AVG(yield_data) as avg_yield, AVG(market_price) as avg_price,
sustainability_practice, region, season, COUNT(*) as data_points
FROM community_insights
GROUP BY crop_type, sustainability_practice, region, season
ORDER BY data_points DESC
""", conn)
except Exception as e:
st.warning(f"Could not load community data: {e}")
community_data = pd.DataFrame()
if not community_data.empty:
# Display insights
st.markdown("#### 🌾 Regional Yield Insights")
for _, row in community_data.head(5).iterrows():
st.info(f"**{row['crop_type']}** in {row['region']} region: "
f"Average yield {row['avg_yield']:.1f} tons/hectare with {row['sustainability_practice']} "
f"({row['data_points']} farmers contributed)")
# Create insights chart
fig = go.Figure()
fig.add_trace(go.Bar(
x=community_data['crop_type'],
y=community_data['avg_yield'],
name='Average Yield',
marker_color='#00ff85'
))
fig.update_layout(
title="Community Yield Data by Crop Type",
xaxis_title="Crop Type",
yaxis_title="Average Yield (tons/hectare)",
height=400
)
st.plotly_chart(fig, use_container_width=True)
else:
st.info("No community data available yet. Be the first to share your data!")
# --- Market Price Forecasting Dashboard ---
st.markdown('<div id="market-dashboard"></div>', unsafe_allow_html=True)
st.markdown("<hr style='border-color: rgba(255,255,255,0.3);'>", unsafe_allow_html=True)
st.header("📈 Market Price Forecasting Dashboard")
st.markdown("""
<div class='card-section'>
<span class='section-step'>📈</span>
<span class='section-icon'>📈</span>
<b style='font-size:1.3em'>Market Price Forecasting</b>
<div class='section-instructions'>Get AI-powered market price predictions for your crops over the next 3-6 months.</div>
</div>
""", unsafe_allow_html=True)
# Market forecasting interface
col1, col2 = st.columns(2)
with col1:
forecast_crop = st.selectbox("Select Crop for Forecasting",
["Rice", "Wheat", "Corn", "Soybean", "Tomato", "Potato", "Cotton"])
with col2:
forecast_period = st.selectbox("Forecast Period", ["3 months", "6 months", "12 months"])
if st.button("🔮 Generate Price Forecast"):
# Simulate market forecasting (in real implementation, this would use ML models)
import random
base_prices = {
"Rice": 2500, "Wheat": 2000, "Corn": 1800, "Soybean": 3500,
"Tomato": 8000, "Potato": 1500, "Cotton": 6000
}
base_price = base_prices.get(forecast_crop, 2000)
# Generate forecast data
months = 3 if "3" in forecast_period else 6 if "6" in forecast_period else 12
forecast_data = []
current_price = base_price
for i in range(months):
# Simulate price fluctuations
change = random.uniform(-0.1, 0.15) # -10% to +15% change
current_price = current_price * (1 + change)
confidence = max(0.6, 1.0 - (i * 0.05)) # Decreasing confidence over time
forecast_data.append({
"month": f"Month {i+1}",
"price": round(current_price, 2),
"confidence": round(confidence, 2)
})
# Save forecast to database
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
for data in forecast_data:
cursor.execute("""
INSERT INTO market_forecasts
(crop, predicted_price, confidence_score, forecast_date, created_at)
VALUES (?, ?, ?, ?, ?)
""", (
forecast_crop, data["price"], data["confidence"],
data["month"], datetime.now().strftime("%Y-%m-%d %H:%M:%S")
))
conn.commit()
# Display forecast
st.markdown(f"### 📊 {forecast_crop} Price Forecast")
# Create forecast chart
fig = go.Figure()
fig.add_trace(go.Scatter(
x=[d["month"] for d in forecast_data],
y=[d["price"] for d in forecast_data],
mode='lines+markers',
name='Predicted Price',
line=dict(color='#00bfff', width=3),
marker=dict(size=8)
))
# Add confidence bands
upper_band = [d["price"] * (1 + (1-d["confidence"])) for d in forecast_data]
lower_band = [d["price"] * (1 - (1-d["confidence"])) for d in forecast_data]
fig.add_trace(go.Scatter(
x=[d["month"] for d in forecast_data],
y=upper_band,
mode='lines',
line=dict(width=0),
showlegend=False,
hoverinfo='skip'
))
fig.add_trace(go.Scatter(
x=[d["month"] for d in forecast_data],
y=lower_band,
mode='lines',
line=dict(width=0),
fill='tonexty',
fillcolor='rgba(0,191,255,0.2)',
name='Confidence Band',
hoverinfo='skip'
))
fig.update_layout(
title=f"{forecast_crop} Price Forecast ({forecast_period})",
xaxis_title="Time Period",
yaxis_title="Price (₹/ton)",
height=500
)
st.plotly_chart(fig, use_container_width=True)
# Display insights
st.markdown("### 💡 Market Insights")
current_price = forecast_data[0]["price"]
future_price = forecast_data[-1]["price"]
price_change = ((future_price - current_price) / current_price) * 100
if price_change > 0:
st.success(f"📈 {forecast_crop} prices are expected to **increase by {price_change:.1f}%** over {forecast_period}")
else:
st.warning(f"📉 {forecast_crop} prices are expected to **decrease by {abs(price_change):.1f}%** over {forecast_period}")
st.info(f"🎯 **Recommendation**: {'Consider planting' if price_change > 5 else 'Monitor market closely'} {forecast_crop} for optimal returns")
# --- AI Chatbot ---
st.markdown('<div id="ai-chatbot"></div>', unsafe_allow_html=True)
st.markdown("<hr style='border-color: rgba(255,255,255,0.3);'>", unsafe_allow_html=True)
st.header("🤖 AI Chatbot")
st.markdown("""
<div class='card-section'>
<span class='section-step'>🤖</span>
<span class='section-icon'>🤖</span>
<b style='font-size:1.3em'>AI Farming Assistant</b>
<div class='section-instructions'>Ask questions about farming practices, crop management, and get instant AI-powered answers.</div>
</div>
""", unsafe_allow_html=True)
# Initialize chat session
if 'chat_history' not in st.session_state:
st.session_state['chat_history'] = []
# Chat interface
st.markdown("### 💬 Chat with AI Assistant")
# Display chat history
for message in st.session_state['chat_history']:
if message['role'] == 'user':
st.markdown(f"**You:** {message['content']}")
else:
st.markdown(f"**AI Assistant:** {message['content']}")
# Chat input
user_query = st.text_input("Ask me anything about farming:", placeholder="e.g., What's the best fertilizer for loamy soil?")
if st.button("💬 Send Message") and user_query:
# Add user message to history
st.session_state['chat_history'].append({'role': 'user', 'content': user_query})
# Generate AI response (simplified - in real implementation, this would use the agent framework)
ai_response = generate_chatbot_response(user_query)
# Add AI response to history
st.session_state['chat_history'].append({'role': 'assistant', 'content': ai_response})
# Save to database
session_id = f"session_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute("""
INSERT INTO chatbot_sessions
(username, session_id, query, response, timestamp)
VALUES (?, ?, ?, ?, ?)
""", (
user['username'], session_id, user_query, ai_response,
datetime.now().strftime("%Y-%m-%d %H:%M:%S")
))
conn.commit()
st.rerun()
# Clear chat button
if st.button("🗑️ Clear Chat"):
st.session_state['chat_history'] = []
st.rerun()
# --- Offline Mode ---
st.markdown('<div id="offline-mode"></div>', unsafe_allow_html=True)
st.markdown("<hr style='border-color: rgba(255,255,255,0.3);'>", unsafe_allow_html=True)
st.header("📱 Offline Mode")
st.markdown("""
<div class='card-section'>
<span class='section-step'>📱</span>
<span class='section-icon'>📱</span>
<b style='font-size:1.3em'>Offline Farming Assistant</b>
<div class='section-instructions'>Use the app without internet connection. Data syncs automatically when online.</div>
</div>
""", unsafe_allow_html=True)
# Offline mode status
offline_status = st.session_state.get('offline_mode', False)
if st.checkbox("📱 Enable Offline Mode", value=offline_status):
st.session_state['offline_mode'] = True
st.success("✅ Offline mode enabled. You can now use the app without internet connection.")
# Offline data management
st.markdown("### 📊 Offline Data Management")
# Check for unsynced data
try:
with sqlite3.connect(db_path) as conn:
unsynced_data = pd.read_sql("""
SELECT data_type, COUNT(*) as count
FROM offline_data
WHERE sync_status = 'pending'
GROUP BY data_type
""", conn)
except Exception as e:
st.warning(f"Could not load offline data: {e}")
unsynced_data = pd.DataFrame()
if not unsynced_data.empty:
st.warning(f"⚠️ You have {unsynced_data['count'].sum()} unsynced data items")
for _, row in unsynced_data.iterrows():
st.info(f"📄 {row['data_type']}: {row['count']} items pending sync")
if st.button("🔄 Sync All Data"):
# Simulate data sync
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute("""
UPDATE offline_data
SET sync_status = 'synced', synced_at = ?
WHERE sync_status = 'pending'
""", (datetime.now().strftime("%Y-%m-%d %H:%M:%S"),))
conn.commit()
st.success("✅ All data synced successfully!")
else:
st.success("✅ All data is synced!")
else:
st.session_state['offline_mode'] = False
st.info("📶 Online mode enabled. All features available with internet connection.")
# --- Footer ---
current_time = datetime.now().strftime("%B %d, %Y at %I:%M %p IST")
st.markdown(f"""
---
<div style='text-align: center; color: #2ecc71; opacity: 0.95;'>
<p style='color:#2ecc71;'>{T['built_with']}</p>
<p><small style='color:#2ecc71;'>{T['last_updated']} {current_time}</small></p>
</div>
""", unsafe_allow_html=True)