Spaces:
Sleeping
Sleeping
Tarkeshwar Claude Opus 4.6 (1M context) commited on
Commit ·
bb2fc43
1
Parent(s): bdb516f
Fix stateful HTTP endpoints and add HF Spaces deployment config
Browse files- Add HF Spaces YAML frontmatter to README.md (sdk: docker, app_port: 8000)
- Rewrite app.py to use stateful shared environment instance instead of
framework's stateless per-request design
- Fix inference.py step payload to use {"action": {"command": ...}} format
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- README.md +9 -0
- data_clean_env/server/app.py +70 -7
- inference.py +1 -1
README.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# DataCleanEnv — Data Quality Analysis & Cleaning Environment
|
| 2 |
|
| 3 |
A real-world OpenEnv environment where AI agents learn to identify and fix data quality issues through iterative inspection, correction, and validation.
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: DataCleanEnv
|
| 3 |
+
emoji: 🧹
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: green
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 8000
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
# DataCleanEnv — Data Quality Analysis & Cleaning Environment
|
| 11 |
|
| 12 |
A real-world OpenEnv environment where AI agents learn to identify and fix data quality issues through iterative inspection, correction, and validation.
|
data_clean_env/server/app.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
| 1 |
"""FastAPI application for the DataClean Environment."""
|
| 2 |
|
| 3 |
-
from
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
try:
|
| 6 |
from .environment import DataCleanEnvironment
|
|
@@ -11,12 +14,72 @@ except ImportError:
|
|
| 11 |
from server.environment import DataCleanEnvironment
|
| 12 |
from models import DataCleanAction, DataCleanObservation
|
| 13 |
|
| 14 |
-
app =
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
|
| 22 |
def main():
|
|
|
|
| 1 |
"""FastAPI application for the DataClean Environment."""
|
| 2 |
|
| 3 |
+
from fastapi import FastAPI, Body
|
| 4 |
+
from fastapi.responses import JSONResponse
|
| 5 |
+
from pydantic import BaseModel
|
| 6 |
+
from typing import Any, Dict, List, Optional
|
| 7 |
|
| 8 |
try:
|
| 9 |
from .environment import DataCleanEnvironment
|
|
|
|
| 14 |
from server.environment import DataCleanEnvironment
|
| 15 |
from models import DataCleanAction, DataCleanObservation
|
| 16 |
|
| 17 |
+
app = FastAPI(title="DataCleanEnv", version="1.0.0")
|
| 18 |
+
|
| 19 |
+
# Shared stateful environment instance
|
| 20 |
+
_env = DataCleanEnvironment()
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
# ---------------------------------------------------------------------------
|
| 24 |
+
# Request / response models
|
| 25 |
+
# ---------------------------------------------------------------------------
|
| 26 |
+
class ResetRequest(BaseModel):
|
| 27 |
+
task_id: str = "customer_contacts"
|
| 28 |
+
seed: Optional[int] = None
|
| 29 |
+
episode_id: Optional[str] = None
|
| 30 |
+
model_config = {"extra": "allow"}
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
class StepRequest(BaseModel):
|
| 34 |
+
action: Dict[str, Any]
|
| 35 |
+
model_config = {"extra": "allow"}
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def _obs_dict(obs: DataCleanObservation) -> dict:
|
| 39 |
+
return obs.model_dump()
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
# ---------------------------------------------------------------------------
|
| 43 |
+
# Endpoints
|
| 44 |
+
# ---------------------------------------------------------------------------
|
| 45 |
+
@app.get("/health")
|
| 46 |
+
async def health():
|
| 47 |
+
return {"status": "ok"}
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
@app.post("/reset")
|
| 51 |
+
async def reset(request: ResetRequest = Body(default_factory=ResetRequest)):
|
| 52 |
+
obs = _env.reset(seed=request.seed, episode_id=request.episode_id, task_id=request.task_id)
|
| 53 |
+
return {"observation": _obs_dict(obs), "reward": None, "done": False}
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
@app.post("/step")
|
| 57 |
+
async def step(request: StepRequest):
|
| 58 |
+
action = DataCleanAction(**request.action)
|
| 59 |
+
obs = _env.step(action)
|
| 60 |
+
return {"observation": _obs_dict(obs), "reward": obs.reward, "done": obs.done}
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
@app.get("/state")
|
| 64 |
+
async def state():
|
| 65 |
+
return _env.state.model_dump()
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
@app.get("/metadata")
|
| 69 |
+
async def metadata():
|
| 70 |
+
return {
|
| 71 |
+
"env_name": "data_clean_env",
|
| 72 |
+
"action_schema": DataCleanAction.model_json_schema(),
|
| 73 |
+
"observation_schema": DataCleanObservation.model_json_schema(),
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
@app.get("/schema")
|
| 78 |
+
async def schema():
|
| 79 |
+
return {
|
| 80 |
+
"action": DataCleanAction.model_json_schema(),
|
| 81 |
+
"observation": DataCleanObservation.model_json_schema(),
|
| 82 |
+
}
|
| 83 |
|
| 84 |
|
| 85 |
def main():
|
inference.py
CHANGED
|
@@ -94,7 +94,7 @@ def env_step(command: str) -> Dict[str, Any]:
|
|
| 94 |
"""Execute a command in the environment."""
|
| 95 |
resp = requests.post(
|
| 96 |
f"{ENV_URL}/step",
|
| 97 |
-
json={"command": command},
|
| 98 |
timeout=30,
|
| 99 |
)
|
| 100 |
resp.raise_for_status()
|
|
|
|
| 94 |
"""Execute a command in the environment."""
|
| 95 |
resp = requests.post(
|
| 96 |
f"{ENV_URL}/step",
|
| 97 |
+
json={"action": {"command": command}},
|
| 98 |
timeout=30,
|
| 99 |
)
|
| 100 |
resp.raise_for_status()
|