|
import gradio as gr |
|
import requests |
|
import json |
|
from datetime import datetime |
|
import os |
|
|
|
|
|
MCP_SERVER_URL = os.getenv("MCP_SERVER_URL", "https://elanuk-mcp-hf.hf.space/") |
|
|
|
|
|
BIHAR_DISTRICTS = [ |
|
"Patna", "Gaya", "Bhagalpur", "Muzaffarpur", "Darbhanga", "Siwan", |
|
"Begusarai", "Katihar", "Nalanda", "Rohtas", "Saran", "Samastipur", |
|
"Madhubani", "Purnia", "Araria", "Kishanganj", "Supaul", "Madhepura", |
|
"Saharsa", "Khagaria", "Munger", "Lakhisarai", "Sheikhpura", "Nawada", |
|
"Jamui", "Jehanabad", "Aurangabad", "Arwal", "Kaimur", "Buxar", |
|
"Bhojpur", "Saran", "Siwan", "Gopalganj", "East Champaran", "West Champaran", |
|
"Sitamarhi", "Sheohar", "Vaishali" |
|
] |
|
|
|
def format_workflow_output(raw_output): |
|
"""Format the workflow output for better display""" |
|
if not raw_output: |
|
return "β No output received" |
|
|
|
|
|
lines = raw_output.split('\n') |
|
formatted_lines = [] |
|
|
|
for line in lines: |
|
line = line.strip() |
|
if not line: |
|
formatted_lines.append("") |
|
continue |
|
|
|
|
|
if line.startswith('πΎ') and 'Workflow' in line: |
|
formatted_lines.append(f"## {line}") |
|
elif line.startswith('=') or line.startswith('-'): |
|
continue |
|
elif line.startswith('π€οΈ') or line.startswith('β
Workflow'): |
|
formatted_lines.append(f"### {line}") |
|
elif line.startswith('π±') or line.startswith('π') or line.startswith('ποΈ') or line.startswith('π€'): |
|
formatted_lines.append(f"#### {line}") |
|
elif line.startswith('β
') or line.startswith('β'): |
|
formatted_lines.append(f"- {line}") |
|
elif line.startswith(' '): |
|
formatted_lines.append(f" {line.strip()}") |
|
else: |
|
formatted_lines.append(line) |
|
|
|
return '\n'.join(formatted_lines) |
|
|
|
def format_alert_summary(raw_data): |
|
"""Create a formatted summary of the alert data""" |
|
if not raw_data or 'alert_data' not in raw_data: |
|
return "No alert data available" |
|
|
|
alert_data = raw_data['alert_data'] |
|
|
|
summary = f""" |
|
## π¨ Alert Summary |
|
|
|
**π Location:** {alert_data['location']['village']}, {alert_data['location']['district']}, {alert_data['location']['state']} |
|
|
|
**πΎ Crop Information:** |
|
- **Crop:** {alert_data['crop']['name'].title()} |
|
- **Growth Stage:** {alert_data['crop']['stage']} |
|
- **Season:** {alert_data['crop']['season'].title()} |
|
|
|
**π€οΈ Weather Conditions:** |
|
- **Temperature:** {alert_data['weather']['temperature']} |
|
- **Expected Rainfall:** {alert_data['weather']['expected_rainfall']} |
|
- **Wind Speed:** {alert_data['weather']['wind_speed']} |
|
- **Rain Probability:** {alert_data['weather']['rain_probability']}% |
|
|
|
**β οΈ Alert Details:** |
|
- **Type:** {alert_data['alert']['type'].replace('_', ' ').title()} |
|
- **Urgency:** {alert_data['alert']['urgency'].upper()} |
|
- **AI Enhanced:** {'β
Yes' if alert_data['alert']['ai_generated'] else 'β No'} |
|
|
|
**π¨ Alert Message:** |
|
{alert_data['alert']['message']} |
|
|
|
**π― Action Items:** |
|
{chr(10).join([f"- {item.replace('_', ' ').title()}" for item in alert_data['alert']['action_items']])} |
|
""" |
|
return summary |
|
|
|
def test_mcp_workflow(district): |
|
"""Test the MCP workflow for a given district""" |
|
if not district: |
|
return "β Please select a district", "", "" |
|
|
|
try: |
|
|
|
payload = { |
|
"state": "bihar", |
|
"district": district.lower() |
|
} |
|
|
|
response = requests.post( |
|
f"{MCP_SERVER_URL}/api/run-workflow", |
|
json=payload, |
|
timeout=30 |
|
) |
|
|
|
if response.status_code == 200: |
|
result = response.json() |
|
|
|
|
|
workflow_output = format_workflow_output(result.get('message', '')) |
|
alert_summary = format_alert_summary(result.get('raw_data', {})) |
|
|
|
|
|
csv_content = result.get('csv', '') |
|
|
|
return workflow_output, alert_summary, csv_content |
|
|
|
else: |
|
error_msg = f"β Server Error ({response.status_code}): {response.text}" |
|
return error_msg, "", "" |
|
|
|
except requests.exceptions.Timeout: |
|
return "β° Request timed out. The server might be processing...", "", "" |
|
except requests.exceptions.ConnectionError: |
|
return f"π Connection Error: Cannot reach MCP server at {MCP_SERVER_URL}", "", "" |
|
except Exception as e: |
|
return f"β Error: {str(e)}", "", "" |
|
|
|
def check_server_health(): |
|
"""Check if the MCP server is running""" |
|
try: |
|
response = requests.get(f"{MCP_SERVER_URL}/api/health", timeout=10) |
|
if response.status_code == 200: |
|
data = response.json() |
|
return f"β
Server Online | OpenAI: {'β
' if data.get('openai_available') else 'β'} | Time: {data.get('timestamp', 'N/A')}" |
|
else: |
|
return f"β οΈ Server responded with status {response.status_code}" |
|
except: |
|
return f"β Server Offline or Unreachable ({MCP_SERVER_URL})" |
|
|
|
|
|
with gr.Blocks( |
|
title="BIHAR AgMCP - Agricultural Weather Alerts", |
|
theme=gr.themes.Soft(), |
|
css=""" |
|
.gradio-container { |
|
max-width: 1200px; |
|
margin: auto; |
|
} |
|
.status-box { |
|
padding: 10px; |
|
border-radius: 5px; |
|
margin: 10px 0; |
|
} |
|
""" |
|
) as demo: |
|
|
|
gr.Markdown(""" |
|
# πΎ BIHAR AgMCP - Agricultural Weather Alert System |
|
|
|
**AI-Powered Weather Alerts for Bihar Farmers** |
|
|
|
This interface tests the MCP (Model Context Protocol) server that generates personalized weather alerts for agricultural activities in Bihar districts. |
|
|
|
## π How to Use: |
|
1. **Select District**: Choose a Bihar district from the dropdown |
|
2. **Run Workflow**: Click the button to generate weather alerts |
|
3. **View Results**: See formatted workflow output and alert summary |
|
4. **Download Data**: Get CSV export of the alert data |
|
|
|
The system will: |
|
- Select a random village in the district |
|
- Choose appropriate crops based on season and region |
|
- Generate weather-based agricultural alerts |
|
- Create messages for multiple communication channels (SMS, WhatsApp, etc.) |
|
""") |
|
|
|
|
|
with gr.Row(): |
|
server_status = gr.Textbox( |
|
label="π§ Server Status", |
|
value=check_server_health(), |
|
interactive=False, |
|
container=True |
|
) |
|
|
|
refresh_btn = gr.Button("π Refresh Status", size="sm") |
|
refresh_btn.click(check_server_health, outputs=server_status) |
|
|
|
|
|
with gr.Row(): |
|
with gr.Column(scale=1): |
|
district_input = gr.Dropdown( |
|
choices=BIHAR_DISTRICTS, |
|
label="π Select Bihar District", |
|
placeholder="Choose a district...", |
|
value="Patna" |
|
) |
|
|
|
run_btn = gr.Button( |
|
"π Generate Weather Alert", |
|
variant="primary", |
|
size="lg" |
|
) |
|
|
|
gr.Markdown(""" |
|
### π‘ What happens next? |
|
- Weather data collection |
|
- Crop stage estimation |
|
- AI-powered alert generation |
|
- Multi-channel message creation |
|
- CSV data export |
|
""") |
|
|
|
|
|
with gr.Row(): |
|
with gr.Column(scale=2): |
|
workflow_output = gr.Markdown( |
|
label="π Workflow Output", |
|
value="Click 'Generate Weather Alert' to see results..." |
|
) |
|
|
|
with gr.Column(scale=1): |
|
alert_summary = gr.Markdown( |
|
label="π Alert Summary", |
|
value="Alert details will appear here..." |
|
) |
|
|
|
|
|
with gr.Row(): |
|
csv_output = gr.File( |
|
label="π Download CSV Data", |
|
visible=False |
|
) |
|
|
|
|
|
def run_workflow_with_csv(district): |
|
workflow, summary, csv_content = test_mcp_workflow(district) |
|
|
|
|
|
if csv_content: |
|
filename = f"bihar_alert_{district.lower()}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" |
|
with open(filename, 'w') as f: |
|
f.write(csv_content) |
|
return workflow, summary, gr.File(value=filename, visible=True) |
|
else: |
|
return workflow, summary, gr.File(visible=False) |
|
|
|
run_btn.click( |
|
run_workflow_with_csv, |
|
inputs=[district_input], |
|
outputs=[workflow_output, alert_summary, csv_output] |
|
) |
|
|
|
|
|
gr.Markdown(""" |
|
--- |
|
|
|
### π System Information: |
|
- **State Coverage**: Bihar (38 districts) |
|
- **Crops Supported**: Rice, Wheat, Maize, Sugarcane, Mustard, and more |
|
- **Weather Sources**: Open-Meteo API with AI enhancement |
|
- **Communication Channels**: SMS, WhatsApp, USSD, IVR, Telegram |
|
|
|
### π Agent Outputs: |
|
The system generates formatted messages for: |
|
- **π± SMS**: Short text alerts for basic phones |
|
- **π± WhatsApp**: Rich media messages with emojis |
|
- **π USSD**: Interactive menu systems |
|
- **ποΈ IVR**: Voice script for phone calls |
|
- **π€ Telegram**: Bot-friendly formatted messages |
|
|
|
*Built with MCP (Model Context Protocol) for agricultural intelligence* |
|
""") |
|
|
|
|
|
if __name__ == "__main__": |
|
demo.launch( |
|
share=True, |
|
server_name="0.0.0.0", |
|
server_port=7860, |
|
show_error=True |
|
) |