aakashdg's picture
fix (sse_app)
9624d29 verified
"""
Farmer.chat Alert Summary Generator - FastAPI Application
"""
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Optional, Dict
from datetime import datetime
import os
# Import pipeline components
from src.pipeline import FarmerChatPipeline
# Import MCP servers
from src.servers.weather import WeatherServer
from src.servers.soil import SoilPropertiesServer
from src.servers.water import WaterServer
from src.servers.elevation import ElevationServer
from src.servers.pests import PestsServer
from mcp_server import sse_app
from starlette.applications import Starlette
# ============================================================================
# PYDANTIC MODELS
# ============================================================================
class LocationRequest(BaseModel):
"""Request model for alert generation"""
location_name: str
district: Optional[str] = None
class AlertResponse(BaseModel):
"""Response model for generated alerts"""
location: str
coordinates: Dict[str, float]
district: Optional[str]
alert_summary: str
timestamp: str
class QueryRequest(BaseModel):
"""Request model for specific queries"""
query: str
location_name: Optional[str] = None
district: Optional[str] = None
# ============================================================================
# BIHAR LOCATION DATA
# ============================================================================
BIHAR_DATA = {
"Araria": ["Araria", "Forbesganj", "Jokihat", "Raniganj"],
"Arwal": ["Arwal", "Kaler", "Karpi", "Kurtha"],
"Aurangabad": ["Aurangabad", "Daudnagar", "Obra", "Nabinagar"],
"Banka": ["Banka", "Amarpur", "Barahat", "Belhar"],
"Begusarai": ["Begusarai", "Bakhri", "Barauni", "Teghra"],
"Bhagalpur": ["Bhagalpur", "Sabour", "Nathnagar", "Kahalgaon"],
"Bhojpur": ["Arrah", "Jagdishpur", "Piro", "Shahpur"],
"Buxar": ["Buxar", "Dumraon", "Chausa", "Simri"],
"Darbhanga": ["Darbhanga", "Baheri", "Jale", "Benipur"],
"East Champaran": ["Motihari", "Raxaul", "Chakia", "Dhaka"],
"Gaya": ["Gaya", "Bodh Gaya", "Tekari", "Sherghati"],
"Gopalganj": ["Gopalganj", "Barauli", "Baikunthpur", "Kateya"],
"Jamui": ["Jamui", "Jhajha", "Sikandra", "Sono"],
"Jehanabad": ["Jehanabad", "Ghoshi", "Makhdumpur", "Modanganj"],
"Kaimur": ["Bhabua", "Mohania", "Ramgarh", "Chainpur"],
"Katihar": ["Katihar", "Barsoi", "Manihari", "Pranpur"],
"Khagaria": ["Khagaria", "Parbatta", "Alauli", "Beldaur"],
"Kishanganj": ["Kishanganj", "Bahadurganj", "Thakurganj", "Dighalbank"],
"Lakhisarai": ["Lakhisarai", "Halsi", "Suryagarha", "Pipariya"],
"Madhepura": ["Madhepura", "Udakishanganj", "Murliganj", "Alamnagar"],
"Madhubani": ["Madhubani", "Jhanjharpur", "Benipatti", "Jainagar"],
"Munger": ["Munger", "Jamalpur", "Asarganj", "Tarapur"],
"Muzaffarpur": ["Muzaffarpur", "Sitamarhi", "Minapur", "Bochaha"],
"Nalanda": ["Bihar Sharif", "Rajgir", "Hilsa", "Biharsharif"],
"Nawada": ["Nawada", "Rajauli", "Akbarpur", "Hisua"],
"Patna": ["Patna", "Danapur", "Fatuha", "Khagaul"],
"Purnia": ["Purnia", "Dhamdaha", "Kasba", "Banmankhi"],
"Rohtas": ["Sasaram", "Dehri", "Bikramganj", "Nasriganj"],
"Saharsa": ["Saharsa", "Sonbarsa", "Simri Bakhtiarpur", "Mahishi"],
"Samastipur": ["Samastipur", "Rosera", "Dalsinghsarai", "Pusa"],
"Saran": ["Chapra", "Marhaura", "Amnour", "Sonepur"],
"Sheikhpura": ["Sheikhpura", "Barbigha", "Ariari", "Shekhopur"],
"Sheohar": ["Sheohar", "Dumri Katsari", "Piprahi", "Tariyani"],
"Sitamarhi": ["Sitamarhi", "Pupri", "Belsand", "Bathnaha"],
"Siwan": ["Siwan", "Maharajganj", "Mairwa", "Darauli"],
"Supaul": ["Supaul", "Nirmali", "Triveniganj", "Chhatapur"],
"Vaishali": ["Hajipur", "Mahua", "Lalganj", "Desri"],
"West Champaran": ["Bettiah", "Bagaha", "Narkatiaganj", "Lauriya"]
}
LOCATIONS = {
"Araria": {"latitude": 26.1523, "longitude": 87.5167},
"Forbesganj": {"latitude": 26.3023, "longitude": 87.2664},
"Jokihat": {"latitude": 25.8998, "longitude": 87.2686},
"Raniganj": {"latitude": 26.0537, "longitude": 87.5333},
"Arwal": {"latitude": 25.2560, "longitude": 84.6819},
"Kaler": {"latitude": 25.1960, "longitude": 84.6219},
"Karpi": {"latitude": 25.2360, "longitude": 84.7019},
"Kurtha": {"latitude": 25.3160, "longitude": 84.6619},
"Aurangabad": {"latitude": 24.7521, "longitude": 84.3742},
"Daudnagar": {"latitude": 25.0337, "longitude": 84.4007},
"Obra": {"latitude": 24.9923, "longitude": 84.4342},
"Nabinagar": {"latitude": 24.6087, "longitude": 84.1269},
"Banka": {"latitude": 24.8893, "longitude": 86.9220},
"Amarpur": {"latitude": 25.0393, "longitude": 86.9020},
"Barahat": {"latitude": 24.8393, "longitude": 87.0020},
"Belhar": {"latitude": 24.9393, "longitude": 86.9620},
"Begusarai": {"latitude": 25.4182, "longitude": 86.1347},
"Bakhri": {"latitude": 25.4582, "longitude": 86.0547},
"Barauni": {"latitude": 25.4751, "longitude": 86.0458},
"Teghra": {"latitude": 25.5082, "longitude": 85.9347},
"Bhagalpur": {"latitude": 25.2425, "longitude": 86.9842},
"Sabour": {"latitude": 25.2375, "longitude": 87.0542},
"Nathnagar": {"latitude": 25.1225, "longitude": 87.0042},
"Kahalgaon": {"latitude": 25.1925, "longitude": 87.2142},
"Arrah": {"latitude": 25.5560, "longitude": 84.6631},
"Jagdishpur": {"latitude": 25.4660, "longitude": 84.4231},
"Piro": {"latitude": 25.3260, "longitude": 84.4031},
"Shahpur": {"latitude": 25.6060, "longitude": 84.4031},
"Buxar": {"latitude": 25.5641, "longitude": 83.9778},
"Dumraon": {"latitude": 25.5541, "longitude": 84.1478},
"Chausa": {"latitude": 25.5241, "longitude": 83.9178},
"Simri": {"latitude": 25.6141, "longitude": 84.0478},
"Darbhanga": {"latitude": 26.1542, "longitude": 85.8978},
"Baheri": {"latitude": 26.0442, "longitude": 85.8378},
"Jale": {"latitude": 26.2042, "longitude": 85.8578},
"Benipur": {"latitude": 26.1142, "longitude": 85.9478},
"Motihari": {"latitude": 26.6484, "longitude": 84.9194},
"Raxaul": {"latitude": 26.9784, "longitude": 84.8494},
"Chakia": {"latitude": 26.4184, "longitude": 85.0494},
"Dhaka": {"latitude": 26.6784, "longitude": 85.1694},
"Gaya": {"latitude": 24.7955, "longitude": 85.0002},
"Bodh Gaya": {"latitude": 24.6955, "longitude": 84.9902},
"Tekari": {"latitude": 24.9455, "longitude": 85.0402},
"Sherghati": {"latitude": 24.5655, "longitude": 84.7902},
"Gopalganj": {"latitude": 26.4685, "longitude": 84.4388},
"Barauli": {"latitude": 26.3785, "longitude": 84.5788},
"Baikunthpur": {"latitude": 26.5285, "longitude": 84.3588},
"Kateya": {"latitude": 26.4285, "longitude": 84.6388},
"Jamui": {"latitude": 24.9272, "longitude": 86.2231},
"Jhajha": {"latitude": 24.7772, "longitude": 86.3731},
"Sikandra": {"latitude": 24.9672, "longitude": 86.0631},
"Sono": {"latitude": 24.8372, "longitude": 86.1431},
"Jehanabad": {"latitude": 25.2078, "longitude": 84.9869},
"Ghoshi": {"latitude": 25.1478, "longitude": 84.9269},
"Makhdumpur": {"latitude": 25.2478, "longitude": 85.0469},
"Modanganj": {"latitude": 25.2678, "longitude": 84.9069},
"Bhabua": {"latitude": 25.0405, "longitude": 83.6074},
"Mohania": {"latitude": 25.1305, "longitude": 83.4774},
"Ramgarh": {"latitude": 24.9505, "longitude": 83.6874},
"Chainpur": {"latitude": 25.2005, "longitude": 83.7474},
"Katihar": {"latitude": 25.5394, "longitude": 87.5839},
"Barsoi": {"latitude": 25.3794, "longitude": 87.8839},
"Manihari": {"latitude": 25.3394, "longitude": 87.6239},
"Pranpur": {"latitude": 25.6894, "longitude": 87.7239},
"Khagaria": {"latitude": 25.5022, "longitude": 86.4665},
"Parbatta": {"latitude": 25.5422, "longitude": 86.5865},
"Alauli": {"latitude": 25.4622, "longitude": 86.3465},
"Beldaur": {"latitude": 25.5622, "longitude": 86.4265},
"Kishanganj": {"latitude": 26.1046, "longitude": 87.9475},
"Bahadurganj": {"latitude": 26.2646, "longitude": 88.1175},
"Thakurganj": {"latitude": 26.0446, "longitude": 87.8275},
"Dighalbank": {"latitude": 25.9046, "longitude": 87.9875},
"Lakhisarai": {"latitude": 25.1678, "longitude": 86.0927},
"Halsi": {"latitude": 25.2278, "longitude": 86.0327},
"Suryagarha": {"latitude": 25.1078, "longitude": 86.1527},
"Pipariya": {"latitude": 25.2078, "longitude": 86.1327},
"Madhepura": {"latitude": 25.9207, "longitude": 86.7940},
"Udakishanganj": {"latitude": 25.9807, "longitude": 86.6740},
"Murliganj": {"latitude": 25.8907, "longitude": 86.9940},
"Alamnagar": {"latitude": 25.9607, "longitude": 86.7340},
"Madhubani": {"latitude": 26.3561, "longitude": 86.0644},
"Jhanjharpur": {"latitude": 26.2661, "longitude": 86.2844},
"Benipatti": {"latitude": 26.5961, "longitude": 86.1444},
"Jainagar": {"latitude": 26.2061, "longitude": 86.1644},
"Munger": {"latitude": 25.3753, "longitude": 86.4734},
"Jamalpur": {"latitude": 25.3153, "longitude": 86.4934},
"Asarganj": {"latitude": 25.1453, "longitude": 86.6834},
"Tarapur": {"latitude": 25.0253, "longitude": 86.6334},
"Muzaffarpur": {"latitude": 26.1225, "longitude": 85.3906},
"Sitamarhi": {"latitude": 26.5925, "longitude": 85.4806},
"Minapur": {"latitude": 26.0625, "longitude": 85.2906},
"Bochaha": {"latitude": 26.0025, "longitude": 85.5306},
"Bihar Sharif": {"latitude": 25.1979, "longitude": 85.5238},
"Rajgir": {"latitude": 25.0279, "longitude": 85.4238},
"Hilsa": {"latitude": 25.3179, "longitude": 85.2838},
"Biharsharif": {"latitude": 25.1979, "longitude": 85.5238},
"Nawada": {"latitude": 24.8834, "longitude": 85.5387},
"Rajauli": {"latitude": 25.0634, "longitude": 85.6387},
"Akbarpur": {"latitude": 24.8234, "longitude": 85.4587},
"Hisua": {"latitude": 24.8334, "longitude": 85.4187},
"Patna": {"latitude": 25.5941, "longitude": 85.1376},
"Danapur": {"latitude": 25.6341, "longitude": 85.0476},
"Fatuha": {"latitude": 25.5041, "longitude": 85.3076},
"Khagaul": {"latitude": 25.5741, "longitude": 85.0476},
"Purnia": {"latitude": 25.7771, "longitude": 87.4753},
"Dhamdaha": {"latitude": 25.8871, "longitude": 87.5853},
"Kasba": {"latitude": 25.8471, "longitude": 87.5353},
"Banmankhi": {"latitude": 25.8871, "longitude": 87.1953},
"Sasaram": {"latitude": 24.9520, "longitude": 84.0328},
"Dehri": {"latitude": 24.9020, "longitude": 84.1828},
"Bikramganj": {"latitude": 25.2120, "longitude": 84.2628},
"Nasriganj": {"latitude": 25.0520, "longitude": 84.1228},
"Saharsa": {"latitude": 25.8769, "longitude": 86.5956},
"Sonbarsa": {"latitude": 25.9269, "longitude": 86.7356},
"Simri Bakhtiarpur": {"latitude": 25.9569, "longitude": 86.3556},
"Mahishi": {"latitude": 25.9969, "longitude": 86.4756},
"Samastipur": {"latitude": 25.8647, "longitude": 85.7817},
"Rosera": {"latitude": 25.7947, "longitude": 85.9317},
"Dalsinghsarai": {"latitude": 25.6647, "longitude": 85.8317},
"Pusa": {"latitude": 25.9847, "longitude": 85.6717},
"Chapra": {"latitude": 25.7805, "longitude": 84.7477},
"Marhaura": {"latitude": 25.9705, "longitude": 84.8677},
"Amnour": {"latitude": 25.8905, "longitude": 84.9077},
"Sonepur": {"latitude": 25.6905, "longitude": 85.1777},
"Sheikhpura": {"latitude": 25.1391, "longitude": 85.8354},
"Barbigha": {"latitude": 25.2191, "longitude": 85.7354},
"Ariari": {"latitude": 25.0591, "longitude": 85.9554},
"Shekhopur": {"latitude": 25.1391, "longitude": 85.8354},
"Sheohar": {"latitude": 26.5184, "longitude": 85.2959},
"Dumri Katsari": {"latitude": 26.5784, "longitude": 85.1959},
"Piprahi": {"latitude": 26.4684, "longitude": 85.4159},
"Tariyani": {"latitude": 26.5584, "longitude": 85.2359},
"Sitamarhi": {"latitude": 26.5925, "longitude": 85.4806},
"Pupri": {"latitude": 26.4725, "longitude": 85.7006},
"Belsand": {"latitude": 26.4425, "longitude": 85.4006},
"Bathnaha": {"latitude": 26.5925, "longitude": 85.5306},
"Siwan": {"latitude": 26.2195, "longitude": 84.3564},
"Maharajganj": {"latitude": 26.1095, "longitude": 84.5064},
"Mairwa": {"latitude": 26.2295, "longitude": 84.1664},
"Darauli": {"latitude": 26.1595, "longitude": 84.1464},
"Supaul": {"latitude": 26.1260, "longitude": 86.6050},
"Nirmali": {"latitude": 26.3160, "longitude": 86.5850},
"Triveniganj": {"latitude": 26.2160, "longitude": 87.0250},
"Chhatapur": {"latitude": 26.2160, "longitude": 86.9050},
"Hajipur": {"latitude": 25.6851, "longitude": 85.2095},
"Mahua": {"latitude": 25.9651, "longitude": 85.2895},
"Lalganj": {"latitude": 25.8751, "longitude": 85.1695},
"Desri": {"latitude": 25.6051, "longitude": 85.4895},
"Bettiah": {"latitude": 26.8022, "longitude": 84.5025},
"Bagaha": {"latitude": 27.0922, "longitude": 84.0925},
"Narkatiaganj": {"latitude": 26.4322, "longitude": 84.7925},
"Lauriya": {"latitude": 26.9822, "longitude": 84.3125}
}
# ============================================================================
# FASTAPI APPLICATION
# ============================================================================
# app = FastAPI(
# title="Farmer.chat Alert Summary API",
# description="Agricultural intelligence system with alert-focused MCP pipeline",
# version="2.0.0"
# )
# # CORS configuration - allow all for development
# app.add_middleware(
# CORSMiddleware,
# allow_origins=["*"],
# allow_credentials=True,
# allow_methods=["*"],
# allow_headers=["*"],
# )
# ============================================================================
# GLOBAL STATE
# ============================================================================
pipeline: Optional[FarmerChatPipeline] = None
servers: Dict = {}
# ============================================================================
# STARTUP & SHUTDOWN (using lifespan - modern FastAPI pattern)
# ============================================================================
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Initialize on startup, cleanup on shutdown"""
global pipeline, servers
# STARTUP
print("\n" + "="*60)
print("Initializing Farmer.chat Alert System")
print("="*60 + "\n")
try:
# Initialize MCP servers
print("Initializing MCP servers...")
servers = {
"weather": WeatherServer(),
"soil": SoilPropertiesServer(),
"water": WaterServer(),
"elevation": ElevationServer(),
"pests": PestsServer()
}
print("✓ All MCP servers initialized successfully\n")
# Initialize pipeline with default location (Patna)
default_location = {"latitude": 25.6093, "longitude": 85.1235}
pipeline = FarmerChatPipeline(
servers=servers,
location=default_location
)
print("\n" + "="*60)
print("✓ Farmer.chat Alert System Ready")
print("="*60 + "\n")
except Exception as e:
print(f"✗ Pipeline initialization failed: {str(e)}")
raise
yield # Application runs here
# SHUTDOWN
print("\nShutting down Farmer.chat Alert System...")
# Apply lifespan to app
app = FastAPI(
title="Farmer.chat Alert Summary API",
description="Agricultural intelligence system with alert-focused MCP pipeline",
version="2.0.0",
lifespan=lifespan
)
# Re-add CORS after recreating app
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Exposing endpoint for sse
app.mount("/mcp", sse_app)
# ============================================================================
# API ENDPOINTS
# ============================================================================
@app.get("/")
async def root():
"""Root endpoint with API information"""
return {
"service": "Farmer.chat Alert Summary Generator",
"version": "2.0.0",
"status": "operational",
"endpoints": {
"locations": "/locations",
"generate_alert": "/generate-alert",
"query": "/query",
"health": "/health"
}
}
@app.get("/health")
async def health_check():
"""Health check endpoint"""
if pipeline is None:
raise HTTPException(status_code=503, detail="Pipeline not initialized")
return {
"status": "healthy",
"pipeline": "operational",
"servers": len(servers),
"timestamp": datetime.utcnow().isoformat()
}
@app.get("/locations")
async def get_locations():
"""Get all available locations"""
return {
"districts": BIHAR_DATA,
"total_locations": len(LOCATIONS),
"coverage": "Bihar, India"
}
@app.post("/generate-alert", response_model=AlertResponse)
async def generate_alert(request: LocationRequest):
"""
Generate comprehensive alert summary for a location.
FIX: Now properly awaits the async pipeline method.
"""
if pipeline is None:
raise HTTPException(status_code=503, detail="Pipeline not initialized")
# Lookup location (case-insensitive)
location_key = request.location_name.lower().strip()
if location_key not in LOCATIONS:
# Try partial match
matches = [k for k in LOCATIONS.keys() if location_key in k.lower()]
if matches:
location_key = matches[0]
else:
raise HTTPException(
status_code=404,
detail=f"Location '{request.location_name}' not found"
)
coordinates = LOCATIONS[location_key]
try:
# FIX: AWAIT the async method!
result = await pipeline.generate_alert(
location=coordinates,
location_name=request.location_name
)
return AlertResponse(
location=request.location_name,
coordinates=coordinates,
district=request.district,
alert_summary=result["alert_summary"],
timestamp=datetime.utcnow().isoformat()
)
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"Failed to generate alert: {str(e)}"
)
@app.post("/query")
async def process_query(request: QueryRequest):
"""
Process a specific farmer query.
FIX: Now properly awaits the async pipeline method.
"""
if pipeline is None:
raise HTTPException(status_code=503, detail="Pipeline not initialized")
# Determine location
location = None
if request.location_name:
location_key = request.location_name.lower().strip()
if location_key in LOCATIONS:
location = LOCATIONS[location_key]
else:
matches = [k for k in LOCATIONS.keys() if location_key in k.lower()]
if matches:
location = LOCATIONS[matches[0]]
try:
# FIX: AWAIT the async method!
result = await pipeline.process_query(
query=request.query,
location=location
)
return {
"query": request.query,
"response": result["response"],
"location": result["location"],
"servers_queried": list(result["mcp_results"].keys()),
"timestamp": datetime.utcnow().isoformat()
}
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"Failed to process query: {str(e)}"
)
# ============================================================================
# MAIN
# ============================================================================
if __name__ == "__main__":
import uvicorn
port = int(os.getenv("PORT", 7860))
uvicorn.run(app, host="0.0.0.0", port=port)