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'' return '👤' # 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"
👋{T['signup_title']}
{T['signup_instruction']}
", 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"
👋{T['login_title']}
{T['login_instruction']}
", 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"{T['no_account']}", unsafe_allow_html=True) else: # Display logged-in user user = st.session_state['user'] st.markdown( f"
{display_base64_image(user['profile_picture'])} {T.get('welcome', 'Welcome')}, {user['username']} ({user['farm_name']})!
", 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)} {user['username']}
{user['farm_name']}", unsafe_allow_html=True) st.divider() st.markdown("Choose a feature:", 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""" """, 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(""" """, unsafe_allow_html=True) # --- Hero Section --- st.markdown("""

🌾 Sustainable Farming AI Platform

Empowering farmers with real-time, AI-powered recommendations for a greener, more profitable future. Plan, optimize, and track your farm with ease—on any device.

🌱 Crop Planning
🧪 Fertilizer Optimization
📊 Sustainability Tracking
🤖 AI Insights
Get started below — follow the steps for a seamless experience!
""", unsafe_allow_html=True) # --- Farmer Usage Instructions --- st.markdown("""
📋 📋 How to Use This Platform
Follow these simple steps to get the most out of your farming AI assistant:
""", 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('
', unsafe_allow_html=True) st.markdown(f"""
1 📏 {T['farm_details']}
{T.get('farm_details_instruction', 'Enter your farm size and crop preference.')}
🌾
{T.get('farm_size_label', 'Farm size')}
🌱
{T.get('crop_preference_label', 'Crop type')}
""", 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('
', unsafe_allow_html=True) st.markdown(f"""
2 🗺️ {T['soil_analysis']}
{T.get('soil_analysis_instruction', 'Analyze your soil by uploading a photo or selecting manually.')}
📸
{T['upload_photo']}
📝
{T['manual_selection']}
""", 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('
', unsafe_allow_html=True) st.markdown(f"""
3 💡 {T['generate_recommendation']}
{T.get('recommendation_instruction', 'Click the button below to get your personalized AI-powered recommendation!')}
🤖
{T['generate_recommendation']}
""", 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("

📊 Detailed Score Analysis

", 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', '
') st.markdown(f"
{T['details']}
{details_html}
", 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('
', unsafe_allow_html=True) st.markdown("
", 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('
', unsafe_allow_html=True) st.markdown("
", 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('
', unsafe_allow_html=True) st.markdown(f"

{T['previous_recommendations']}

", 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('
', unsafe_allow_html=True) # --- Sustainability Score Tracker --- st.markdown("
", 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('
', unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) st.header("🗺️ Interactive Farm Map") # Farm Map Section st.markdown("""
🗺️ 🗺️ Interactive Farm Mapping
Upload or draw your farm map to get location-specific recommendations and risk analysis.
""", 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('
', unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) st.header("👥 Community Insights") st.markdown("""
👥 👥 Community-Driven Insights
Share and learn from anonymized community data on crop yields, market prices, and sustainability practices.
""", 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('
', unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) st.header("📈 Market Price Forecasting Dashboard") st.markdown("""
📈 📈 Market Price Forecasting
Get AI-powered market price predictions for your crops over the next 3-6 months.
""", 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('
', unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) st.header("🤖 AI Chatbot") st.markdown("""
🤖 🤖 AI Farming Assistant
Ask questions about farming practices, crop management, and get instant AI-powered answers.
""", 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('
', unsafe_allow_html=True) st.markdown("
", unsafe_allow_html=True) st.header("📱 Offline Mode") st.markdown("""
📱 📱 Offline Farming Assistant
Use the app without internet connection. Data syncs automatically when online.
""", 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""" ---

{T['built_with']}

{T['last_updated']} {current_time}

""", unsafe_allow_html=True)