Spaces:
Sleeping
Sleeping
File size: 6,051 Bytes
e86a6ff 3af94fa 34a93bb 9ae9432 e86a6ff 95f11da 87c40c2 95f11da e86a6ff 95f11da e86a6ff 9ae9432 e86a6ff 95f11da 87c40c2 95f11da e86a6ff 95f11da e86a6ff 9ae9432 e86a6ff 3af94fa 9ae9432 3af94fa 9ae9432 34a93bb e86a6ff 34a93bb e86a6ff 34a93bb e86a6ff a6b0c55 95f11da a6b0c55 95f11da a6b0c55 37bfd28 a6b0c55 e86a6ff 87c40c2 e86a6ff | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | """FastAPI application for ChargebackOps."""
from __future__ import annotations
import logging
import os
from fastapi import HTTPException
from fastapi.responses import JSONResponse
try:
from openenv.core.env_server.http_server import create_app
except Exception as exc: # pragma: no cover
raise ImportError(
"openenv-core is required to run ChargebackOps. Install project dependencies first."
) from exc
try:
from ..runners.baseline_runner import run_baseline
from ..core.episode_store import get_report, list_reports
from ..runners.inference import run_inference
from ..core.models import (
BaselineRunResult,
ChargebackOpsAction,
ChargebackOpsObservation,
TasksResponse,
TaskSummary,
)
from ..scenarios.simulation import list_tasks
from .chargeback_ops_environment import ChargebackOpsEnvironment
from .demo_ui import build_demo
except ImportError: # pragma: no cover
from runners.baseline_runner import run_baseline
from core.episode_store import get_report, list_reports
from runners.inference import run_inference
from core.models import (
BaselineRunResult,
ChargebackOpsAction,
ChargebackOpsObservation,
TasksResponse,
TaskSummary,
)
from scenarios.simulation import list_tasks
from server.chargeback_ops_environment import ChargebackOpsEnvironment
from server.demo_ui import build_demo
app = create_app(
ChargebackOpsEnvironment,
ChargebackOpsAction,
ChargebackOpsObservation,
env_name="chargeback_ops",
max_concurrent_envs=8,
)
try:
import gradio as gr
app = gr.mount_gradio_app(app, build_demo(), path="/demo")
except Exception:
logging.getLogger(__name__).warning("Gradio demo unavailable", exc_info=True)
# Canonical Space card URL for README / judges (not the relative /demo path).
_DEFAULT_DEMO_SPACE_URL = "https://huggingface.co/spaces/mitudrudutta/ChargeBackOps"
def _canonical_demo_space_url() -> str:
"""Human-facing Hugging Face Space URL (Space card + embedded app)."""
space_id = (os.environ.get("SPACE_ID") or "").strip()
if space_id:
return f"https://huggingface.co/spaces/{space_id}"
override = (os.environ.get("DEMO_SPACE_URL") or "").strip()
if override:
return override
return _DEFAULT_DEMO_SPACE_URL
def _interactive_demo_url() -> str:
"""Same-origin Gradio mount; absolute URL when Hugging Face sets SPACE_HOST."""
host = (os.environ.get("SPACE_HOST") or "").strip()
if host:
return f"https://{host.rstrip('/')}/demo/"
return "/demo"
@app.get("/")
def root() -> JSONResponse:
"""Return a lightweight root response for HF Space and validator pings.
``demo_url`` is always the canonical Hugging Face Space page (shareable,
stable, matches README badges). ``interactive_demo_url`` is the live
Gradio app on this deployment (relative locally, absolute on Spaces).
"""
return JSONResponse(
{
"name": "ChargebackOps",
"status": "ok",
"docs_url": "/docs",
"health_url": "/health",
"tasks_url": "/tasks",
"demo_url": _canonical_demo_space_url(),
"interactive_demo_url": _interactive_demo_url(),
}
)
@app.get("/tasks", response_model=TasksResponse)
def tasks() -> TasksResponse:
"""List built-in tasks and the action schema."""
return TasksResponse(
tasks=[
TaskSummary(
task_id=task.task_id,
title=task.title,
difficulty=task.difficulty,
objective=task.objective,
description=task.description,
max_steps=task.max_steps,
case_count=len(task.cases),
)
for task in list_tasks()
],
action_schema=ChargebackOpsAction.model_json_schema(),
)
@app.get("/generate")
def generate_tasks(
seed: int = 42,
easy: int = 2,
medium: int = 2,
hard: int = 2,
) -> list[dict]:
"""Generate parametric tasks from a seed for infinite scenario variety."""
try:
from scenarios.case_generator import generate_task_suite
except ImportError: # pragma: no cover
from ..scenarios.case_generator import generate_task_suite
suite = generate_task_suite(
base_seed=seed,
easy_count=easy,
medium_count=medium,
hard_count=hard,
)
return [
{
"task_id": t.task_id,
"title": t.title,
"difficulty": t.difficulty,
"objective": t.objective,
"case_count": len(t.cases),
"max_steps": t.max_steps,
}
for t in suite
]
@app.get("/grader")
@app.post("/grader")
def grader(episode_id: str | None = None):
"""Return a stored grade for a completed episode."""
report = get_report(episode_id)
if report is None:
raise HTTPException(
status_code=404,
detail="No completed episode report found. Finish an episode first or provide a valid episode_id.",
)
return report.model_dump()
@app.get("/baseline", response_model=BaselineRunResult)
@app.post("/baseline", response_model=BaselineRunResult)
def baseline(
provider: str | None = None,
model_name: str | None = None,
) -> BaselineRunResult:
"""Run the baseline inference policy across all tasks."""
if provider is None and model_name is None:
return run_inference()
return run_baseline(provider=provider, model_name=model_name)
@app.get("/results")
def results():
"""Return all completed episode reports for inspection and replay."""
reports = list_reports()
return [report.model_dump() for report in reports]
def main(host: str = "0.0.0.0", port: int = 8000) -> None:
"""Local entry point for uvicorn."""
import uvicorn
uvicorn.run(app, host=host, port=port)
if __name__ == "__main__": # pragma: no cover
main()
|