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 | |