Raje19112003/Invoice_Dispute_Resolution_Environment
0
1"""2Invoice Dispute Resolution Environment — FastAPI Server3Exposes the environment via HTTP endpoints compatible with OpenEnv.4"""5from typing import Optional6import sys7import os8sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))9 10from fastapi import FastAPI, HTTPException11from fastapi.middleware.cors import CORSMiddleware12from fastapi.responses import HTMLResponse13from pydantic import BaseModel14from models import DisputeAction, DisputeObservation, DisputeState15from server.environment import InvoiceDisputeEnv16 17# ── App setup ──────────────────────────────────────────────────────────────────18app = FastAPI(19 title="Invoice Dispute Resolution Environment",20 description=(21 "An OpenEnv-compatible RL environment where an AI agent learns to resolve "22 "billing disputes correctly, efficiently, and in compliance with company policy. "23 "Supports 3 difficulty levels: easy, medium, hard."24 ),25 version="1.0.0",26)27 28app.add_middleware(29 CORSMiddleware,30 allow_origins=["*"],31 allow_methods=["*"],32 allow_headers=["*"],33)34 35# Global environment instance (starts with medium difficulty)36env = InvoiceDisputeEnv(difficulty="medium")37 38 39class ResetRequest(BaseModel):40 """Request body for reset endpoint with optional difficulty."""41 difficulty: str = "medium"42 43 44# ── Endpoints ──────────────────────────────────────────────────────────────────45 46@app.get("/", response_class=HTMLResponse)47def home():48 return """49 <html>50 <head>51 <title>Invoice Dispute Resolution Environment</title>52 <style>53 body {54 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto;55 max-width: 800px;56 margin: 50px auto;57 padding: 20px;58 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);59 color: white;60 }61 .container {62 background: rgba(255, 255, 255, 0.1);63 padding: 40px;64 border-radius: 12px;65 backdrop-filter: blur(10px);66 }67 h1 { margin-top: 0; }68 a { color: #fff; text-decoration: none; font-weight: bold; }69 a:hover { text-decoration: underline; }70 .button {71 display: inline-block;72 padding: 10px 20px;73 background: white;74 color: #667eea;75 border-radius: 6px;76 margin: 10px 10px 10px 0;77 font-weight: bold;78 cursor: pointer;79 }80 </style>81 </head>82 <body>83 <div class="container">84 <h1>🚀 Invoice Dispute Resolution Environment</h1>85 <p>An AI-powered system for resolving billing disputes using reinforcement learning.</p>86 87 <h2>📚 API Documentation</h2>88 <a href="/docs" class="button">📖 Swagger UI</a>89 <a href="/redoc" class="button">📋 ReDoc</a>90 91 <h2>🏥 Status</h2>92 <p>✅ Backend is running on port 7860</p>93 94 <h2>🎯 Quick Start</h2>95 <ul>96 <li>Visit <a href="/docs">/docs</a> to test APIs interactively</li>97 <li>Or use: <code>curl http://localhost:7860/health</code></li>98 </ul>99 </div>100 </body>101 </html>102 """103 104@app.get("/health")105def health_check():106 return {"status": "ok", "env": "invoice-dispute-env"}107 108 109@app.post("/reset", response_model=DisputeObservation)110def reset(request: Optional[ResetRequest] = None):111 """112 Start a new dispute episode.113 Defaults to 'easy' if no difficulty provided.114 """115 116 difficulty = "easy" # default117 118 if request and request.difficulty:119 if request.difficulty not in ["easy", "medium", "hard"]:120 raise HTTPException(121 status_code=400,122 detail="Difficulty must be: easy, medium, or hard"123 )124 difficulty = request.difficulty125 126 global env127 env = InvoiceDisputeEnv(difficulty=difficulty)128 obs = env.reset()129 130 return obs131 132 133@app.post("/step", response_model=DisputeObservation)134def step(action: DisputeAction):135 """136 Submit the agent's resolution decision.137 Returns reward, feedback, done flag, and customer reaction.138 """139 try:140 obs = env.step(action)141 return obs142 except RuntimeError as e:143 raise HTTPException(status_code=400, detail=str(e))144 145 146@app.get("/state", response_model=DisputeState)147def get_state():148 """149 Return the full current state of the environment.150 Includes invoice, dispute details, customer history, and company policy.151 """152 try:153 return env.state154 except RuntimeError as e:155 raise HTTPException(status_code=400, detail=str(e))156 157 158# ── Entry point ────────────────────────────────────────────────────────────────159def create_app() -> FastAPI:160 return app161 162import uvicorn163 164def main():165 uvicorn.run("server.app:app",host="0.0.0.0",port=7860)166 167if __name__ == "__main__":168 main()169 