Spaces:
Sleeping
Sleeping
| import google.generativeai as genai | |
| import json | |
| import os | |
| from datetime import datetime, date | |
| from typing import Dict, Any, Optional | |
| import logging | |
| # Configure logging | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| class GeminiAIService: | |
| """Service class for Gemini AI integration""" | |
| def __init__(self, api_key: str): | |
| """Initialize Gemini AI service""" | |
| self.api_key = api_key | |
| genai.configure(api_key=api_key) | |
| self.model = genai.GenerativeModel('gemini-2.0-flash') | |
| def generate_daily_advisory(self, farmer_data: Dict[str, Any], farm_data: Dict[str, Any], | |
| soil_data: Dict[str, Any], weather_data: Dict[str, Any], | |
| current_date: str = None) -> Dict[str, str]: | |
| """ | |
| Generate daily farming advisory using Gemini AI | |
| Args: | |
| farmer_data: Farmer information | |
| farm_data: Farm details including crops | |
| soil_data: Current soil parameters | |
| weather_data: Current weather data | |
| current_date: Date for the advisory (default: today) | |
| Returns: | |
| Dictionary with task_to_do, task_to_avoid, and reason_explanation | |
| """ | |
| if current_date is None: | |
| current_date = date.today().strftime('%Y-%m-%d') | |
| # Prepare the prompt for Gemini | |
| prompt = self._create_advisory_prompt(farmer_data, farm_data, soil_data, weather_data, current_date) | |
| try: | |
| # Generate response from Gemini | |
| response = self.model.generate_content(prompt) | |
| # Parse the response | |
| advisory = self._parse_gemini_response(response.text) | |
| logger.info(f"Generated advisory for farmer {farmer_data.get('name')} on {current_date}") | |
| return advisory | |
| except Exception as e: | |
| logger.error(f"Error generating advisory: {str(e)}") | |
| return self._get_fallback_advisory() | |
| def _create_advisory_prompt(self, farmer_data: Dict[str, Any], farm_data: Dict[str, Any], | |
| soil_data: Dict[str, Any], weather_data: Dict[str, Any], | |
| current_date: str) -> str: | |
| """Create a detailed prompt for Gemini AI""" | |
| crop_types = ', '.join(farm_data.get('crop_types', [])) | |
| prompt = f""" | |
| You are an expert agricultural advisor. Generate a daily farming advisory for the following farmer: | |
| FARMER INFORMATION: | |
| - Name: {farmer_data.get('name', 'Unknown')} | |
| - Farm Name: {farm_data.get('farm_name', 'Unknown')} | |
| - Farm Size: {farm_data.get('farm_size', 0)} acres | |
| - Crops: {crop_types} | |
| - Irrigation Type: {farm_data.get('irrigation_type', 'Unknown')} | |
| SOIL CONDITIONS: | |
| - Soil Type: {soil_data.get('soil_type', 'Unknown')} | |
| - pH Level: {soil_data.get('ph_level', 'Unknown')} | |
| - Nitrogen: {soil_data.get('nitrogen_level', 'Unknown')} ppm | |
| - Phosphorus: {soil_data.get('phosphorus_level', 'Unknown')} ppm | |
| - Potassium: {soil_data.get('potassium_level', 'Unknown')} ppm | |
| - Moisture: {soil_data.get('moisture_percentage', 'Unknown')}% | |
| WEATHER CONDITIONS: | |
| - Date: {current_date} | |
| - Temperature: {weather_data.get('main', {}).get('temp_min', 'Unknown')}°C - {weather_data.get('main', {}).get('temp_max', 'Unknown')}°C | |
| - Humidity: {weather_data.get('main', {}).get('humidity', 'Unknown')}% | |
| - Wind Speed: {weather_data.get('wind', {}).get('speed', 0) * 3.6:.1f} km/h | |
| - Weather Condition: {weather_data.get('weather', [{}])[0].get('description', 'Unknown').title()} | |
| INSTRUCTIONS: | |
| Please provide a daily farming advisory in the following JSON format: | |
| {{ | |
| "task_to_do": "Specific task the farmer should do today", | |
| "task_to_avoid": "Specific task the farmer should avoid today", | |
| "reason_explanation": "Simple, farmer-friendly explanation for the recommendations", | |
| "crop_stage": "Current estimated crop growth stage" | |
| }} | |
| Consider the weather conditions, soil parameters, crop requirements, and seasonal farming practices. | |
| Provide practical, actionable advice that a farmer can easily understand and implement. | |
| Make the language simple and direct. | |
| """ | |
| return prompt | |
| def _parse_gemini_response(self, response_text: str) -> Dict[str, str]: | |
| """Parse Gemini's response and extract advisory information""" | |
| try: | |
| # Try to extract JSON from the response | |
| # Look for JSON-like content in the response | |
| start_idx = response_text.find('{') | |
| end_idx = response_text.rfind('}') + 1 | |
| if start_idx != -1 and end_idx != -1: | |
| json_text = response_text[start_idx:end_idx] | |
| advisory = json.loads(json_text) | |
| # Validate required fields | |
| required_fields = ['task_to_do', 'task_to_avoid', 'reason_explanation'] | |
| for field in required_fields: | |
| if field not in advisory: | |
| advisory[field] = "No recommendation available" | |
| return advisory | |
| else: | |
| # If no JSON found, try to parse manually | |
| return self._manual_parse_response(response_text) | |
| except json.JSONDecodeError: | |
| # If JSON parsing fails, try manual parsing | |
| return self._manual_parse_response(response_text) | |
| except Exception as e: | |
| logger.error(f"Error parsing Gemini response: {str(e)}") | |
| return self._get_fallback_advisory() | |
| def _manual_parse_response(self, response_text: str) -> Dict[str, str]: | |
| """Manually parse response if JSON parsing fails""" | |
| lines = response_text.split('\n') | |
| advisory = { | |
| 'task_to_do': 'No specific task recommended', | |
| 'task_to_avoid': 'No specific task to avoid', | |
| 'reason_explanation': 'Advisory not available', | |
| 'crop_stage': 'Unknown' | |
| } | |
| for line in lines: | |
| line = line.strip() | |
| if line.startswith('✅') or 'task_to_do' in line.lower(): | |
| advisory['task_to_do'] = line.replace('✅', '').strip() | |
| elif line.startswith('❌') or 'task_to_avoid' in line.lower(): | |
| advisory['task_to_avoid'] = line.replace('❌', '').strip() | |
| elif line.startswith('ℹ️') or 'reason' in line.lower(): | |
| advisory['reason_explanation'] = line.replace('ℹ️', '').strip() | |
| return advisory | |
| def _get_fallback_advisory(self) -> Dict[str, str]: | |
| """Provide a fallback advisory when Gemini fails""" | |
| return { | |
| 'task_to_do': 'Check crop condition and water levels', | |
| 'task_to_avoid': 'Avoid heavy farm work during extreme weather', | |
| 'reason_explanation': 'General farming best practices for safety and crop health', | |
| 'crop_stage': 'Unknown' | |
| } | |
| def generate_year_plan(self, farmer_data: Dict[str, Any], farm_data: Dict[str, Any], | |
| soil_data: Dict[str, Any]) -> Dict[str, Any]: | |
| """Generate a comprehensive year-long farming plan with detailed HTML formatting""" | |
| crop_types = ', '.join(farm_data.get('crop_types', [])) | |
| farm_size = farm_data.get('farm_size', 0) | |
| irrigation_type = farm_data.get('irrigation_type', 'Unknown') | |
| soil_type = soil_data.get('soil_type', 'Unknown') | |
| # Construct crop details with areas (assume equal distribution if not specified) | |
| crops = farm_data.get('crop_types', []) | |
| if crops and farm_size: | |
| area_per_crop = farm_size / len(crops) | |
| crop_details = ", ".join([f"{crop} ({area_per_crop:.1f} acres)" for crop in crops]) | |
| else: | |
| crop_details = crop_types or "Mixed crops" | |
| prompt = f""" | |
| You are a skilled agriculture expert and data analyst. I am providing you with the following farm details: | |
| FARM INFORMATION: | |
| - Farmer Name: {farmer_data.get('name', 'Unknown')} | |
| - Farm Name: {farm_data.get('farm_name', 'Unknown')} | |
| - Total Farm Area: {farm_size} acres | |
| - Location/Address: {farmer_data.get('address', 'Unknown')} | |
| - Irrigation Type: {irrigation_type} | |
| - Soil Type: {soil_type} | |
| - Soil pH: {soil_data.get('ph_level', 'Unknown')} | |
| - Nitrogen Level: {soil_data.get('nitrogen_level', 'Unknown')} ppm | |
| - Phosphorus Level: {soil_data.get('phosphorus_level', 'Unknown')} ppm | |
| - Potassium Level: {soil_data.get('potassium_level', 'Unknown')} ppm | |
| - Current Crops: {crop_details} | |
| Using the above input, please generate a fully formatted HTML page with enhanced CSS styling that includes the following sections: | |
| 1. **Main Heading:** | |
| - A centrally aligned, bold heading in green titled "Comprehensive Yearly Farming Plan 2025" with proper spacing and clear font sizes. | |
| 2. **Farm Overview Statistics:** | |
| - A left-aligned, blue bold subheading "Farm Overview & Current Status". | |
| - Below it, include a green table with columns for: | |
| - Parameter | |
| - Current Value | |
| - Recommended Range | |
| - Status (Good/Needs Improvement) | |
| - Include farm size, soil parameters, irrigation type, etc. | |
| 3. **Monthly Farming Calendar (12-Month Plan):** | |
| - A left-aligned, blue bold subheading titled "Monthly Farming Calendar". | |
| - Create a comprehensive green table displaying month-wise activities for the entire year: | |
| - Month | |
| - Primary Activities | |
| - Crop Operations | |
| - Fertilizer Schedule | |
| - Irrigation Requirements | |
| - Expected Weather Considerations | |
| - Include specific activities for each month based on crop cycles, seasons (Rabi/Kharif), and local agricultural practices. | |
| 4. **Crop-wise Annual Strategy:** | |
| - A left-aligned, blue bold subheading "Crop-wise Annual Strategy". | |
| - Add a detailed green table showing for each crop: | |
| - Crop Name | |
| - Sowing Period | |
| - Growing Duration | |
| - Harvest Period | |
| - Expected Yield (per acre) | |
| - Estimated Revenue | |
| - Key Care Instructions | |
| 5. **Financial Projections:** | |
| - Include a section with a blue left-aligned subheading "Annual Financial Forecast". | |
| - Present tables showing: | |
| - Expected Production Costs (seeds, fertilizers, labor, etc.) | |
| - Projected Revenue by crop | |
| - Estimated Profit Margins | |
| - Monthly cash flow predictions | |
| 6. **Soil Management Plan:** | |
| - A blue left-aligned subheading "Soil Health & Fertilizer Schedule". | |
| - Create tables for: | |
| - Soil testing schedule | |
| - Fertilizer application timeline | |
| - Organic matter enhancement plan | |
| - pH management strategies | |
| 7. **Risk Management & Weather Planning:** | |
| - A blue left-aligned subheading "Risk Management Strategies". | |
| - Include tables for: | |
| - Seasonal weather challenges | |
| - Pest and disease prevention calendar | |
| - Backup crop strategies | |
| - Insurance and financial protection | |
| 8. **Key Recommendations & Action Items:** | |
| - At the bottom, include a bullet-point list with specific, actionable recommendations. | |
| - Style each bullet point in bold with yellow highlights on key dates, quantities, and financial figures. | |
| - Include immediate actions, seasonal priorities, and long-term improvements. | |
| IMPORTANT REQUIREMENTS: | |
| - Generate the entire response in Hindi language. All text, headings, table headers, and content should be in Hindi. | |
| - Use realistic data based on Indian agricultural practices and the provided farm details. | |
| - Make tables interactive, beautiful, and colorful with proper spacing and margins. | |
| - Increase font size for headings and optimize spacing for readability. | |
| - Do not include any extra spacing at the beginning or end of the response. | |
| - Ensure all content is properly formatted as HTML with appropriate CSS styling. | |
| - Include specific dates, quantities, and actionable advice suitable for Indian farmers. | |
| - Consider Indian seasons (Rabi, Kharif, Zayad) and local agricultural practices. | |
| - Use metric measurements and Indian rupee currency where applicable. | |
| Generate a comprehensive, professional, and farmer-friendly yearly plan that can guide the farmer throughout the entire agricultural year. | |
| """ | |
| try: | |
| response = self.model.generate_content(prompt) | |
| # Return the comprehensive HTML plan | |
| html_plan = response.text.strip() | |
| return { | |
| 'plan': html_plan, | |
| 'type': 'comprehensive_html', | |
| 'generated_at': datetime.now().isoformat(), | |
| 'ai_generated': True, | |
| 'farmer_name': farmer_data.get('name'), | |
| 'farm_name': farm_data.get('farm_name') | |
| } | |
| except Exception as e: | |
| logger.error(f"Error generating comprehensive year plan: {str(e)}") | |
| return { | |
| 'plan': self._get_fallback_yearly_plan(farmer_data, farm_data, soil_data), | |
| 'type': 'fallback_html', | |
| 'generated_at': datetime.now().isoformat(), | |
| 'ai_generated': False | |
| } | |
| def _get_fallback_yearly_plan(self, farmer_data: Dict[str, Any], farm_data: Dict[str, Any], soil_data: Dict[str, Any]) -> str: | |
| """Generate a fallback yearly plan in HTML format when AI fails""" | |
| crop_types = ', '.join(farm_data.get('crop_types', ['Mixed crops'])) | |
| return f""" | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <style> | |
| body {{ font-family: Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }} | |
| .header {{ text-align: center; color: #2e7d32; font-size: 28px; font-weight: bold; margin-bottom: 30px; }} | |
| .section {{ margin-bottom: 25px; }} | |
| .section-title {{ color: #1976d2; font-size: 20px; font-weight: bold; margin-bottom: 15px; }} | |
| table {{ width: 100%; border-collapse: collapse; background-color: #e8f5e8; margin-bottom: 20px; }} | |
| th {{ background-color: #4caf50; color: white; padding: 12px; text-align: left; }} | |
| td {{ padding: 10px; border: 1px solid #ddd; }} | |
| .highlight {{ background-color: #ffeb3b; font-weight: bold; }} | |
| .recommendation {{ margin: 10px 0; padding: 10px; background-color: #fff3e0; border-left: 4px solid #ff9800; }} | |
| </style> | |
| </head> | |
| <body> | |
| <div class="header">वार्षिक खेती योजना 2025</div> | |
| <div class="section"> | |
| <div class="section-title">खेत की जानकारी</div> | |
| <table> | |
| <tr><th>विवरण</th><th>मान</th></tr> | |
| <tr><td>किसान का नाम</td><td>{farmer_data.get('name', 'अज्ञात')}</td></tr> | |
| <tr><td>खेत का नाम</td><td>{farm_data.get('farm_name', 'अज्ञात')}</td></tr> | |
| <tr><td>कुल क्षेत्रफल</td><td>{farm_data.get('farm_size', 0)} एकड़</td></tr> | |
| <tr><td>फसलें</td><td>{crop_types}</td></tr> | |
| <tr><td>सिंचाई प्रकार</td><td>{farm_data.get('irrigation_type', 'अज्ञात')}</td></tr> | |
| </table> | |
| </div> | |
| <div class="section"> | |
| <div class="section-title">मासिक गतिविधि कैलेंडर</div> | |
| <table> | |
| <tr><th>महीना</th><th>मुख्य गतिविधियां</th><th>सिंचाई</th></tr> | |
| <tr><td>जनवरी</td><td>रबी फसल की देखभाल, खाद डालना</td><td>आवश्यकता अनुसार</td></tr> | |
| <tr><td>फरवरी</td><td>फसल की निगरानी, कीट नियंत्रण</td><td>नियमित</td></tr> | |
| <tr><td>मार्च</td><td>रबी फसल की कटाई तैयारी</td><td>कम</td></tr> | |
| <tr><td>अप्रैल</td><td>रबी फसल कटाई, खरीफ की तैयारी</td><td>गर्मी के कारण अधिक</td></tr> | |
| <tr><td>मई</td><td>खेत की तैयारी, बीज खरीदारी</td><td>अधिक</td></tr> | |
| <tr><td>जून</td><td>खरीफ फसल बुआई</td><td>मानसून शुरुआत</td></tr> | |
| <tr><td>जुलाई</td><td>खरीफ फसल देखभाल</td><td>मानसून</td></tr> | |
| <tr><td>अगस्त</td><td>निराई-गुड़ाई, खाद</td><td>मानसून</td></tr> | |
| <tr><td>सितंबर</td><td>फसल निगरानी</td><td>मध्यम</td></tr> | |
| <tr><td>अक्टूबर</td><td>खरीफ कटाई, रबी तैयारी</td><td>आवश्यकता अनुसार</td></tr> | |
| <tr><td>नवंबर</td><td>रबी फसल बुआई</td><td>नियमित</td></tr> | |
| <tr><td>दिसंबर</td><td>रबी फसल देखभाल</td><td>ठंड में कम</td></tr> | |
| </table> | |
| </div> | |
| <div class="recommendation"> | |
| <strong>मुख्य सुझाव:</strong><br> | |
| • मिट्टी की जांच <span class="highlight">वर्ष में दो बार</span> कराएं<br> | |
| • उन्नत बीजों का प्रयोग करें<br> | |
| • <span class="highlight">समय पर</span> सिंचाई और खाद डालें<br> | |
| • कीट-रोग की नियमित निगरानी करें<br> | |
| • मौसम की जानकारी रखें | |
| </div> | |
| </body> | |
| </html> | |
| """ | |
| def format_sms_message(farmer_name: str, advisory: Dict[str, str]) -> str: | |
| """Format the advisory as an SMS message""" | |
| message = f"Good Morning, {farmer_name} 🌱\n" | |
| message += f"✅ Task: {advisory.get('task_to_do', 'No task')}\n" | |
| message += f"❌ Avoid: {advisory.get('task_to_avoid', 'No restrictions')}\n" | |
| if advisory.get('reason_explanation'): | |
| message += f"ℹ️ {advisory.get('reason_explanation')}" | |
| return message | |