Spaces:
Sleeping
Sleeping
| """ | |
| Policy Impact Simulator API endpoints | |
| Provides REST API access to policy simulation functionality | |
| """ | |
| from fastapi import APIRouter, HTTPException, Query | |
| from pydantic import BaseModel, Field | |
| from typing import List, Optional, Dict, Any | |
| from datetime import datetime, date | |
| from enum import Enum | |
| from policy_impact_simulator import ( | |
| PolicyImpactSimulator, | |
| PolicyScenario, | |
| PolicyParameter, | |
| create_sample_scenarios | |
| ) | |
| router = APIRouter(prefix="/api/policy-simulator", tags=["policy-simulator"]) | |
| # Pydantic models for API | |
| class PolicyParameterEnum(str, Enum): | |
| pension_factor = "pension_factor" | |
| dearness_relief = "dearness_relief" | |
| basic_pension = "basic_pension" | |
| minimum_pension = "minimum_pension" | |
| commutation_factor = "commutation_factor" | |
| medical_allowance = "medical_allowance" | |
| family_pension = "family_pension" | |
| gratuity_limit = "gratuity_limit" | |
| hra_percentage = "hra_percentage" | |
| retirement_age = "retirement_age" | |
| class PolicySimulationRequest(BaseModel): | |
| parameter: PolicyParameterEnum = Field(..., description="Policy parameter to simulate") | |
| current_value: float = Field(..., description="Current value of the parameter") | |
| proposed_value: float = Field(..., description="Proposed new value") | |
| effective_date: date = Field(..., description="When the policy change takes effect") | |
| affected_population: int = Field(..., description="Number of people affected") | |
| annual_growth_rate: float = Field(0.03, description="Annual population growth rate") | |
| inflation_rate: float = Field(0.06, description="Expected inflation rate") | |
| projection_years: int = Field(5, description="Number of years to project", ge=1, le=10) | |
| include_variants: bool = Field(True, description="Include best/worst case scenarios") | |
| class QuickSimulationRequest(BaseModel): | |
| scenario_name: str = Field(..., description="Name of predefined scenario") | |
| years: int = Field(5, description="Projection years", ge=1, le=10) | |
| # Initialize simulator | |
| simulator = PolicyImpactSimulator() | |
| async def simulate_policy_impact(request: PolicySimulationRequest): | |
| """ | |
| Simulate the impact of a policy change | |
| Provides comprehensive analysis including: | |
| - Baseline vs scenario projections | |
| - Best/base/worst case scenarios | |
| - Clause analysis and timeline | |
| - Exportable evidence pack | |
| """ | |
| try: | |
| # Convert API request to internal scenario | |
| scenario = PolicyScenario( | |
| parameter=PolicyParameter(request.parameter.value), | |
| current_value=request.current_value, | |
| proposed_value=request.proposed_value, | |
| effective_date=datetime.combine(request.effective_date, datetime.min.time()), | |
| affected_population=request.affected_population, | |
| annual_growth_rate=request.annual_growth_rate, | |
| inflation_rate=request.inflation_rate | |
| ) | |
| # Run simulation | |
| result = simulator.simulate_policy_impact( | |
| scenario=scenario, | |
| years=request.projection_years, | |
| include_variants=request.include_variants | |
| ) | |
| if "error" in result: | |
| raise HTTPException(status_code=500, detail=result["error"]) | |
| return { | |
| "success": True, | |
| "simulation_result": result, | |
| "api_version": "1.0", | |
| "generated_at": datetime.now().isoformat() | |
| } | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Simulation failed: {str(e)}") | |
| async def quick_simulate(request: QuickSimulationRequest): | |
| """ | |
| Run a quick simulation using predefined scenarios | |
| Available scenarios: | |
| - dr_increase_6_percent: Increase DR from 12% to 18% | |
| - basic_pension_boost: Increase basic pension from ₹6000 to ₹8000 | |
| - medical_allowance_double: Double medical allowance to ₹2000 | |
| """ | |
| try: | |
| predefined_scenarios = { | |
| "dr_increase_6_percent": PolicyScenario( | |
| parameter=PolicyParameter.DEARNESS_RELIEF, | |
| current_value=12.0, | |
| proposed_value=18.0, | |
| effective_date=datetime(2025, 4, 1), | |
| affected_population=510000 | |
| ), | |
| "basic_pension_boost": PolicyScenario( | |
| parameter=PolicyParameter.BASIC_PENSION, | |
| current_value=6000, | |
| proposed_value=8000, | |
| effective_date=datetime(2025, 7, 1), | |
| affected_population=450000 | |
| ), | |
| "medical_allowance_double": PolicyScenario( | |
| parameter=PolicyParameter.MEDICAL_ALLOWANCE, | |
| current_value=1000, | |
| proposed_value=2000, | |
| effective_date=datetime(2025, 10, 1), | |
| affected_population=510000 | |
| ) | |
| } | |
| if request.scenario_name not in predefined_scenarios: | |
| raise HTTPException( | |
| status_code=400, | |
| detail=f"Unknown scenario. Available: {list(predefined_scenarios.keys())}" | |
| ) | |
| scenario = predefined_scenarios[request.scenario_name] | |
| result = simulator.simulate_policy_impact(scenario, request.years, True) | |
| return { | |
| "success": True, | |
| "scenario_name": request.scenario_name, | |
| "simulation_result": result | |
| } | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def get_policy_parameters(): | |
| """Get available policy parameters with their definitions""" | |
| try: | |
| parameters = {} | |
| for param in PolicyParameter: | |
| param_def = simulator.policy_definitions.get(param, {}) | |
| parameters[param.value] = { | |
| "name": param_def.get("name", param.value), | |
| "description": param_def.get("description", ""), | |
| "unit": param_def.get("unit", ""), | |
| "typical_range": param_def.get("typical_range", (0, 100)), | |
| "current_rajasthan": param_def.get("current_rajasthan", 0), | |
| "impact_type": param_def.get("impact_type", "benefit") | |
| } | |
| return { | |
| "success": True, | |
| "parameters": parameters, | |
| "total_count": len(parameters) | |
| } | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def get_sample_scenarios(): | |
| """Get sample scenarios for testing and demonstration""" | |
| try: | |
| samples = create_sample_scenarios() | |
| scenarios_data = [] | |
| for i, scenario in enumerate(samples): | |
| scenarios_data.append({ | |
| "id": f"sample_{i+1}", | |
| "parameter": scenario.parameter.value, | |
| "parameter_name": simulator.policy_definitions[scenario.parameter]["name"], | |
| "current_value": scenario.current_value, | |
| "proposed_value": scenario.proposed_value, | |
| "effective_date": scenario.effective_date.date().isoformat(), | |
| "affected_population": scenario.affected_population, | |
| "description": f"Sample scenario: {simulator.policy_definitions[scenario.parameter]['name']} change" | |
| }) | |
| return { | |
| "success": True, | |
| "sample_scenarios": scenarios_data, | |
| "usage": "Use these scenarios with /quick-simulate endpoint" | |
| } | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def get_detailed_analysis(simulation_id: str): | |
| """Get detailed analysis for a completed simulation""" | |
| # This would typically fetch from a database | |
| # For now, return a placeholder response | |
| return { | |
| "success": True, | |
| "message": "Detailed analysis endpoint - would fetch stored simulation results", | |
| "simulation_id": simulation_id, | |
| "note": "In production, this would retrieve complete analysis from database" | |
| } | |
| async def compare_scenarios(scenarios: List[PolicySimulationRequest]): | |
| """Compare multiple policy scenarios side by side""" | |
| try: | |
| if len(scenarios) > 5: | |
| raise HTTPException(status_code=400, detail="Maximum 5 scenarios can be compared") | |
| comparison_results = [] | |
| for i, request in enumerate(scenarios): | |
| scenario = PolicyScenario( | |
| parameter=PolicyParameter(request.parameter.value), | |
| current_value=request.current_value, | |
| proposed_value=request.proposed_value, | |
| effective_date=datetime.combine(request.effective_date, datetime.min.time()), | |
| affected_population=request.affected_population, | |
| annual_growth_rate=request.annual_growth_rate, | |
| inflation_rate=request.inflation_rate | |
| ) | |
| result = simulator.simulate_policy_impact(scenario, request.projection_years, False) | |
| comparison_results.append({ | |
| "scenario_index": i + 1, | |
| "parameter": request.parameter.value, | |
| "impact_summary": result.get("total_impact", {}), | |
| "first_year_impact": result["scenario_projections"][0].impact if result.get("scenario_projections") else 0 | |
| }) | |
| # Create comparison summary | |
| total_impacts = [r.get("impact_summary", {}).get("total_additional_cost_crores", 0) for r in comparison_results] | |
| return { | |
| "success": True, | |
| "comparison_count": len(scenarios), | |
| "scenarios": comparison_results, | |
| "summary": { | |
| "highest_impact": max(total_impacts) if total_impacts else 0, | |
| "lowest_impact": min(total_impacts) if total_impacts else 0, | |
| "total_combined_impact": sum(total_impacts), | |
| "recommendation": "Detailed comparison analysis completed" | |
| } | |
| } | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def export_simulation_data( | |
| simulation_id: str, | |
| format: str = Query("json", regex="^(json|csv|pdf)$") | |
| ): | |
| """Export simulation results in various formats""" | |
| try: | |
| # This would typically fetch the simulation from database | |
| # For now, return export information | |
| export_info = { | |
| "json": "Complete simulation data in JSON format", | |
| "csv": "Yearly projections and impact data in CSV format", | |
| "pdf": "Formatted policy impact report in PDF format" | |
| } | |
| return { | |
| "success": True, | |
| "simulation_id": simulation_id, | |
| "export_format": format, | |
| "description": export_info.get(format, "Unknown format"), | |
| "download_url": f"/api/policy-simulator/download/{simulation_id}/{format}", | |
| "note": "In production, would generate actual downloadable files" | |
| } | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |