CoolFace
Apppublic

Raje19112003/Invoice_Dispute_Resolution_Environment

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes
app.py169 linesDownload Raw Back to server
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