aakashdg's picture
test
ddc122d verified
raw
history blame
50.4 kB
# # """
# # Farmer.Chat Backend - FastAPI Application
# # Deploy to Hugging Face Space: https://huggingface.co/spaces/aakashdg/farmer-chat-backend
# # """
# # from fastapi import FastAPI, HTTPException
# # from fastapi.middleware.cors import CORSMiddleware
# # from fastapi.responses import FileResponse, JSONResponse
# # from pydantic import BaseModel, Field
# # from typing import Optional, Dict, Any
# # import os
# # import asyncio
# # import time
# # from datetime import datetime
# # # Import pipeline components
# # from src.pipeline import FarmerChatPipeline
# # from src.pdf_generator import generate_pdf_report
# # from openai import OpenAI
# # import httpx
# # # Initialize FastAPI
# # app = FastAPI(
# # title="Farmer.Chat Backend",
# # description="Multi-stage MCP pipeline for agricultural intelligence",
# # version="2.0.0"
# # )
# # # CORS - Allow all origins for demo (restrict in production)
# # app.add_middleware(
# # CORSMiddleware,
# # allow_origins=["*"],
# # allow_credentials=True,
# # allow_methods=["*"],
# # allow_headers=["*"],
# # )
# # # Initialize OpenAI client with FIXED httpx configuration
# # OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
# # if not OPENAI_API_KEY:
# # raise ValueError("OPENAI_API_KEY environment variable not set!")
# # # FIX: Create httpx client without proxy support
# # http_client = httpx.Client(
# # timeout=httpx.Timeout(60.0),
# # limits=httpx.Limits(max_keepalive_connections=5, max_connections=10)
# # )
# # # Initialize OpenAI with custom http client (bypasses proxy issues)
# # openai_client = OpenAI(
# # api_key=OPENAI_API_KEY,
# # http_client=http_client
# # )
# # print("✅ OpenAI client initialized with custom httpx client")
# # print(f" Model: gpt-4o")
# # # Default location (Bangalore Agricultural Region)
# # DEFAULT_LOCATION = {
# # "name": "Bangalore Agricultural Region",
# # "lat": 12.8716,
# # "lon": 77.4946
# # }
# # # Initialize pipeline
# # pipeline = FarmerChatPipeline(openai_client, DEFAULT_LOCATION)
# # # Request/Response Models
# # class QueryRequest(BaseModel):
# # query: str = Field(..., min_length=3, max_length=500, description="Farmer's question")
# # location: Optional[Dict[str, Any]] = Field(None, description="Custom location (lat, lon, name)")
# # class Config:
# # json_schema_extra = {
# # "example": {
# # "query": "Should I plant rice today?",
# # "location": {
# # "name": "Bangalore",
# # "lat": 12.8716,
# # "lon": 77.4946
# # }
# # }
# # }
# # class QueryResponse(BaseModel):
# # success: bool
# # query: str
# # advice: str
# # routing: Dict[str, Any]
# # data: Dict[str, Any]
# # execution_time_seconds: float
# # timestamp: str
# # # Health check
# # @app.get("/")
# # async def root():
# # return {
# # "service": "Farmer.Chat Backend",
# # "status": "operational",
# # "version": "2.0.0",
# # "endpoints": {
# # "query": "/api/query",
# # "health": "/api/health",
# # "servers": "/api/servers"
# # }
# # }
# # @app.get("/api/health")
# # async def health_check():
# # """Health check endpoint"""
# # return {
# # "status": "healthy",
# # "timestamp": datetime.now().isoformat(),
# # "openai_configured": bool(OPENAI_API_KEY),
# # "location": DEFAULT_LOCATION
# # }
# # @app.get("/api/servers")
# # async def list_servers():
# # """List available MCP servers"""
# # from src.executor import MCP_SERVER_REGISTRY
# # return {
# # "total_servers": len(MCP_SERVER_REGISTRY),
# # "servers": MCP_SERVER_REGISTRY
# # }
# # @app.post("/api/query", response_model=QueryResponse)
# # async def process_query(request: QueryRequest):
# # """
# # Main query endpoint - processes farmer questions through MCP pipeline
# # """
# # try:
# # start_time = time.time()
# # # Use custom location if provided, otherwise default
# # location = request.location if request.location else DEFAULT_LOCATION
# # # Update pipeline location if changed
# # if request.location:
# # pipeline.location = location
# # # Process query through pipeline
# # result = await pipeline.process_query(request.query, verbose=False)
# # execution_time = time.time() - start_time
# # return QueryResponse(
# # success=True,
# # query=request.query,
# # advice=result["advice"],
# # routing=result["routing"],
# # data=result["compiled_data"],
# # execution_time_seconds=round(execution_time, 2),
# # timestamp=datetime.now().isoformat()
# # )
# # except Exception as e:
# # raise HTTPException(status_code=500, detail=str(e))
# # @app.post("/api/export-pdf")
# # async def export_pdf(request: QueryRequest):
# # """
# # Export query result as PDF
# # """
# # try:
# # # Process query
# # result = await pipeline.process_query(request.query, verbose=False)
# # # Generate PDF
# # pdf_path = generate_pdf_report(
# # query=request.query,
# # advice=result["advice"],
# # data=result["compiled_data"],
# # location=pipeline.location
# # )
# # # Return PDF file
# # return FileResponse(
# # pdf_path,
# # media_type="application/pdf",
# # filename=f"farmer-chat-report-{int(time.time())}.pdf"
# # )
# # except Exception as e:
# # raise HTTPException(status_code=500, detail=str(e))
# # # Error handlers
# # @app.exception_handler(404)
# # async def not_found_handler(request, exc):
# # return JSONResponse(
# # status_code=404,
# # content={"error": "Endpoint not found", "path": str(request.url)}
# # )
# # @app.exception_handler(500)
# # async def server_error_handler(request, exc):
# # return JSONResponse(
# # status_code=500,
# # content={"error": "Internal server error", "detail": str(exc)}
# # )
# # if __name__ == "__main__":
# # import uvicorn
# # uvicorn.run(app, host="0.0.0.0", port=7860)
# """
# Alert Summary Generator Backend - Standalone Version
# FastAPI app with embedded pipeline and location data
# """
# from fastapi import FastAPI, HTTPException
# from fastapi.middleware.cors import CORSMiddleware
# from pydantic import BaseModel
# from typing import Optional, Dict, Any, List
# import os
# from datetime import datetime
# from openai import OpenAI
# import httpx
# # ============================================================================
# # OPENAI CLIENT SETUP
# # ============================================================================
# def get_openai_client():
# """Initialize OpenAI client with API key from environment"""
# api_key = os.getenv("OPENAI_API_KEY")
# if not api_key:
# raise ValueError("OPENAI_API_KEY environment variable not set")
# http_client = httpx.Client(
# timeout=httpx.Timeout(60.0, connect=10.0),
# limits=httpx.Limits(max_keepalive_connections=10, max_connections=20)
# )
# return OpenAI(api_key=api_key, http_client=http_client)
# # ============================================================================
# # PIPELINE COMPONENTS
# # ============================================================================
# class QueryRouter:
# """Routes queries to appropriate MCP servers"""
# def __init__(self, client):
# self.client = client
# def route_query(self, query: str, location: Dict[str, float]) -> Dict[str, Any]:
# """Determine which servers to call based on query"""
# prompt = f"""Given the farmer query: "{query}"
# Location: {location['latitude']}, {location['longitude']}
# Determine which data sources are needed. Return JSON:
# {{
# "weather": true/false,
# "soil": true/false,
# "water": true/false,
# "elevation": true/false,
# "pests": true/false
# }}"""
# response = self.client.chat.completions.create(
# model="gpt-4",
# messages=[{"role": "user", "content": prompt}],
# temperature=0
# )
# # Parse routing decision
# import json
# try:
# routing = json.loads(response.choices[0].message.content)
# except:
# # Default: query all servers for alerts
# routing = {
# "weather": True,
# "soil": True,
# "water": True,
# "elevation": True,
# "pests": True
# }
# return routing
# class MCPExecutor:
# """Executes parallel calls to MCP servers"""
# def __init__(self, client):
# self.client = client
# def execute_parallel(self, routing: Dict[str, bool], location: Dict[str, float]) -> Dict[str, str]:
# """Execute MCP server calls in parallel"""
# results = {}
# # Simulate MCP server calls (replace with actual server calls)
# if routing.get("weather"):
# results["weather"] = f"Weather data for {location['latitude']}, {location['longitude']}"
# if routing.get("soil"):
# results["soil"] = f"Soil data for {location['latitude']}, {location['longitude']}"
# if routing.get("water"):
# results["water"] = f"Water availability for {location['latitude']}, {location['longitude']}"
# if routing.get("elevation"):
# results["elevation"] = f"Elevation data for {location['latitude']}, {location['longitude']}"
# if routing.get("pests"):
# results["pests"] = f"Pest risk data for {location['latitude']}, {location['longitude']}"
# return results
# class ResponseCompiler:
# """Compiles MCP results into coherent response"""
# def __init__(self, client):
# self.client = client
# def compile_response(self, query: str, mcp_results: Dict[str, str], location: Dict[str, float]) -> str:
# """Compile MCP results into final response"""
# # Format MCP results for context
# context = "\n\n".join([f"{k.upper()}: {v}" for k, v in mcp_results.items()])
# prompt = f"""You are an agricultural assistant. Compile this data into a comprehensive alert summary.
# FARMER QUERY: {query}
# LOCATION: {location['latitude']}, {location['longitude']}
# DATA FROM SOURCES:
# {context}
# Provide a comprehensive agricultural alert covering:
# 1. Current weather conditions and forecast
# 2. Soil health and recommendations
# 3. Water availability status
# 4. Elevation/topography considerations
# 5. Pest risks and preventive measures
# Be specific, actionable, and farmer-friendly."""
# response = self.client.chat.completions.create(
# model="gpt-4",
# messages=[{"role": "user", "content": prompt}],
# temperature=0.7
# )
# return response.choices[0].message.content
# class HindiTranslator:
# """Translates responses to Hindi"""
# def __init__(self, client):
# self.client = client
# def translate(self, text: str, target_lang: str = "en") -> str:
# """Translate text if needed"""
# if target_lang == "en":
# return text
# # Add Hindi translation logic here
# return text
# class FarmerChatPipeline:
# """Main pipeline orchestrating all stages"""
# def __init__(self, client, location: Dict[str, float]):
# self.client = client
# self.location = location
# self.router = QueryRouter(client)
# self.executor = MCPExecutor(client)
# self.compiler = ResponseCompiler(client)
# self.translator = HindiTranslator(client)
# def process_query(self, query: str, language: str = "en") -> str:
# """Process query through full pipeline"""
# # Stage 1: Route query
# routing = self.router.route_query(query, self.location)
# # Stage 2: Execute MCP calls
# mcp_results = self.executor.execute_parallel(routing, self.location)
# # Stage 3: Compile response
# response = self.compiler.compile_response(query, mcp_results, self.location)
# # Stage 4: Translate if needed
# final_response = self.translator.translate(response, language)
# return final_response
# # ============================================================================
# # 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 APP
# # ============================================================================
# app = FastAPI(title="Farmer.chat Alert Summary API")
# # CORS middleware
# app.add_middleware(
# CORSMiddleware,
# allow_origins=["*"],
# allow_credentials=True,
# allow_methods=["*"],
# allow_headers=["*"],
# )
# # Initialize pipeline
# openai_client = None
# pipeline = None
# @app.on_event("startup")
# async def startup_event():
# """Initialize OpenAI client and pipeline on startup"""
# global openai_client, pipeline
# try:
# openai_client = get_openai_client()
# DEFAULT_LOCATION = {"latitude": 25.5941, "longitude": 85.1376}
# pipeline = FarmerChatPipeline(openai_client, DEFAULT_LOCATION)
# print("✓ Pipeline initialized successfully")
# except Exception as e:
# print(f"✗ Pipeline initialization failed: {e}")
# raise
# # ============================================================================
# # API MODELS
# # ============================================================================
# class LocationRequest(BaseModel):
# location_name: str
# district: Optional[str] = None
# class AlertResponse(BaseModel):
# location: str
# coordinates: Dict[str, float]
# district: Optional[str] = None
# alert_summary: str
# timestamp: str
# # ============================================================================
# # API ENDPOINTS
# # ============================================================================
# @app.get("/")
# async def root():
# """Root endpoint"""
# return {
# "message": "Farmer.chat Alert Summary API",
# "version": "1.0.0",
# "endpoints": {
# "/locations": "GET - List all districts and villages",
# "/generate-alert": "POST - Generate alert for location",
# "/health": "GET - Health check"
# }
# }
# @app.get("/health")
# async def health_check():
# """Health check endpoint"""
# return {
# "status": "healthy",
# "pipeline": "initialized" if pipeline else "not_initialized",
# "timestamp": datetime.now().isoformat()
# }
# @app.get("/locations")
# async def get_locations():
# """Get all districts and villages"""
# return {"districts": BIHAR_DATA}
# @app.post("/generate-alert", response_model=AlertResponse)
# async def generate_alert(request: LocationRequest):
# """Generate alert summary for selected location"""
# if not pipeline:
# raise HTTPException(status_code=500, detail="Pipeline not initialized")
# # Find location coordinates
# location_name = request.location_name.strip()
# coordinates = None
# # Case-insensitive search
# for loc_key, loc_coords in LOCATIONS.items():
# if loc_key.lower() == location_name.lower():
# coordinates = loc_coords
# break
# if not coordinates:
# raise HTTPException(
# status_code=404,
# detail=f"Location '{location_name}' not found in database"
# )
# # Update pipeline location
# pipeline.location = coordinates
# # Create comprehensive query for all MCP servers
# query = f"""Generate a comprehensive agricultural alert summary for {location_name} covering:
# 1. Current weather conditions and 7-day forecast
# 2. Soil health analysis and fertilizer recommendations
# 3. Groundwater availability and irrigation status
# 4. Elevation and topography considerations for farming
# 5. Current pest risks and preventive measures
# Provide actionable insights for farmers."""
# try:
# # Generate alert
# alert_summary = pipeline.process_query(query)
# return AlertResponse(
# location=location_name,
# coordinates=coordinates,
# district=request.district,
# alert_summary=alert_summary,
# timestamp=datetime.now().isoformat()
# )
# except Exception as e:
# raise HTTPException(
# status_code=500,
# detail=f"Error generating alert: {str(e)}"
# )
# # ============================================================================
# # RUN SERVER
# # ============================================================================
# if __name__ == "__main__":
# import uvicorn
# port = int(os.getenv("PORT", 7860))
# uvicorn.run(app, host="0.0.0.0", port=port)
"""
Farmer.chat Alert Summary Generator - FastAPI Application
Modular architecture with alert-focused intelligence
"""
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 (assuming they exist in src/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
# ============================================================================
# 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
# ============================================================================
# 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
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ============================================================================
# GLOBAL STATE
# ============================================================================
pipeline: Optional[FarmerChatPipeline] = None
servers: Dict = {}
# ============================================================================
# STARTUP & SHUTDOWN
# ============================================================================
@app.on_event("startup")
async def startup_event():
"""Initialize MCP servers and pipeline on startup"""
global pipeline, servers
try:
print("\n" + "="*60)
print("Initializing Farmer.chat Alert System")
print("="*60 + "\n")
# Initialize MCP servers
print("Initializing MCP servers...")
# Note: Your servers don't need arguments in their constructors
# WaterServer hardcodes cache_dir internally
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 = LOCATIONS.get("patna", {"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
@app.on_event("shutdown")
async def shutdown_event():
"""Cleanup on shutdown"""
print("\nShutting down Farmer.chat Alert System...")
# ============================================================================
# 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",
"architecture": "Modular MCP Pipeline",
"endpoints": {
"locations": "/locations - Get all available locations",
"generate_alert": "/generate-alert - Generate alert summary for location",
"query": "/query - Process specific farmer query",
"health": "/health - Health check",
"server_status": "/server-status - Check MCP server status"
}
}
@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("/server-status")
async def server_status():
"""Get status of all MCP servers"""
if pipeline is None:
raise HTTPException(status_code=503, detail="Pipeline not initialized")
status = pipeline.get_server_status()
return {
"servers": status,
"timestamp": datetime.utcnow().isoformat()
}
@app.get("/locations")
async def get_locations():
"""Get all available districts and villages"""
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.
Queries all MCP servers and compiles an actionable alert summary
focusing on critical information and recommendations.
"""
if pipeline is None:
raise HTTPException(status_code=503, detail="Pipeline not initialized")
# Lookup location coordinates
location_key = request.location_name.lower().strip()
if location_key not in LOCATIONS:
# Try case-insensitive 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 in database"
)
coordinates = LOCATIONS[location_key]
try:
# Generate alert using pipeline
result = 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.
Queries all MCP servers and returns a response focusing on
information relevant to the question.
"""
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:
# Process query through pipeline
result = 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 (for local testing)
# ============================================================================
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7680)