Spaces:
Sleeping
Sleeping
| """ | |
| 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 | |
| async def root(): | |
| return { | |
| "service": "Farmer.Chat Backend", | |
| "status": "operational", | |
| "version": "2.0.0", | |
| "endpoints": { | |
| "query": "/api/query", | |
| "health": "/api/health", | |
| "servers": "/api/servers" | |
| } | |
| } | |
| async def health_check(): | |
| """Health check endpoint""" | |
| return { | |
| "status": "healthy", | |
| "timestamp": datetime.now().isoformat(), | |
| "openai_configured": bool(OPENAI_API_KEY), | |
| "location": DEFAULT_LOCATION | |
| } | |
| 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 | |
| } | |
| 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)) | |
| 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 | |
| async def not_found_handler(request, exc): | |
| return JSONResponse( | |
| status_code=404, | |
| content={"error": "Endpoint not found", "path": str(request.url)} | |
| ) | |
| 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) | |