Spaces:
No application file
No application file
Upload 6 files
Browse files- __init__.py +0 -0
- app.py +17 -0
- dockerfile +21 -0
- environment.py +46 -0
- requirements.txt +4 -0
- schemas.py +33 -0
__init__.py
ADDED
|
File without changes
|
app.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from openenv.core.env_server import create_app
|
| 2 |
+
from .environment import AccountantEng
|
| 3 |
+
from .schemas import Action, AccountantState
|
| 4 |
+
|
| 5 |
+
# This creates the API server
|
| 6 |
+
# It automatically handles the WebSocket connections for you!
|
| 7 |
+
app = create_app(
|
| 8 |
+
env=AccountantEng,
|
| 9 |
+
action_cls=Action,
|
| 10 |
+
observation_cls=AccountantState,
|
| 11 |
+
env_name="mini-accountant",
|
| 12 |
+
)
|
| 13 |
+
|
| 14 |
+
if __name__ == "__main__":
|
| 15 |
+
import uvicorn
|
| 16 |
+
# This runs the server locally on port 8000
|
| 17 |
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
dockerfile
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 1. Use an official Python runtime as a parent image
|
| 2 |
+
FROM python:3.10-slim
|
| 3 |
+
|
| 4 |
+
# 2. Set the working directory in the container
|
| 5 |
+
WORKDIR /app
|
| 6 |
+
|
| 7 |
+
# 3. Copy the requirements file first (better for Docker caching)
|
| 8 |
+
COPY requirements.txt .
|
| 9 |
+
|
| 10 |
+
# 4. Install dependencies
|
| 11 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 12 |
+
|
| 13 |
+
# 5. Copy the rest of your application code
|
| 14 |
+
COPY . .
|
| 15 |
+
|
| 16 |
+
# 6. Expose the port the app runs on
|
| 17 |
+
EXPOSE 8000
|
| 18 |
+
|
| 19 |
+
# 7. Run the application
|
| 20 |
+
# We use the same command you used locally!
|
| 21 |
+
CMD ["python", "-m", "mini_accountant_env.app"]
|
environment.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from openenv.core.env_server import Environment as BaseEnv
|
| 2 |
+
from .schemas import CalculateAction, SubmitAction, AccountantState, Action
|
| 3 |
+
|
| 4 |
+
class AccountantEng(BaseEnv):
|
| 5 |
+
def __init__(self):
|
| 6 |
+
self.target_answer = 3000
|
| 7 |
+
self.max_steps = 5
|
| 8 |
+
self.messy_text = "Revenue was 5000, costs were 2000. What is the net profit?"
|
| 9 |
+
self.current_step = 0
|
| 10 |
+
|
| 11 |
+
def reset(self) -> AccountantState:
|
| 12 |
+
self.current_state = 0
|
| 13 |
+
return AccountantState(
|
| 14 |
+
observation=self.messy_text,
|
| 15 |
+
is_done=False
|
| 16 |
+
)
|
| 17 |
+
|
| 18 |
+
def step(self, action:Action)->tuple[AccountantState, float, bool, dict]:
|
| 19 |
+
self.current_step+=1
|
| 20 |
+
reward=-0.1
|
| 21 |
+
done=False
|
| 22 |
+
observation=""
|
| 23 |
+
|
| 24 |
+
if self.current_step==self.max_steps:
|
| 25 |
+
observation="Max steps reached."
|
| 26 |
+
|
| 27 |
+
if action.action_type=="calculate":
|
| 28 |
+
try:
|
| 29 |
+
result=eval(action.expression)
|
| 30 |
+
observation = f"Calculation result: {result}"
|
| 31 |
+
except Exception as e:
|
| 32 |
+
reward-=0.5
|
| 33 |
+
|
| 34 |
+
elif action.action_type=="submit":
|
| 35 |
+
done=True
|
| 36 |
+
if action.net_profit==self.target_answer:
|
| 37 |
+
reward+=1.0
|
| 38 |
+
observation = "Correct! Task complete."
|
| 39 |
+
else:
|
| 40 |
+
reward-=0.5
|
| 41 |
+
observation = f"Incorrect. The target was not {action.net_profit}."
|
| 42 |
+
if self.current_step==self.max_steps:
|
| 43 |
+
observation="Max steps reached."
|
| 44 |
+
|
| 45 |
+
state = AccountantState(observation=observation, is_done=done)
|
| 46 |
+
return state, float(reward), done, {}
|
requirements.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
openenv
|
| 2 |
+
pydantic>=2.0.0
|
| 3 |
+
fastapi
|
| 4 |
+
uvicorn
|
schemas.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pydantic import BaseModel, Field
|
| 2 |
+
from typing import Union, Literal
|
| 3 |
+
|
| 4 |
+
# ==========================================
|
| 5 |
+
# 1. TOOL ARGUMENTS (What the agent can do)
|
| 6 |
+
# ==========================================
|
| 7 |
+
|
| 8 |
+
class CalculateAction(BaseModel):
|
| 9 |
+
"""Tool to calculate mathematical expressions."""
|
| 10 |
+
action_type: Literal["calculate"] = "calculate"
|
| 11 |
+
expression: str = Field(
|
| 12 |
+
...,
|
| 13 |
+
description="A strict mathematical expression to evaluate. ONLY use numbers and operators (+, -, *, /). Example: '5000 - 1200 - 800'"
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
class SubmitAction(BaseModel):
|
| 17 |
+
"""Submits the final answer"""
|
| 18 |
+
action_type : Literal["submit"]="submit"
|
| 19 |
+
net_profit: float = Field(
|
| 20 |
+
...,
|
| 21 |
+
description="The final calculated net profit as a floating point number."
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
# The agent's action must be exactly one of these two
|
| 25 |
+
Action = Union[CalculateAction, SubmitAction]
|
| 26 |
+
# ==========================================
|
| 27 |
+
# 2. STATE (What the agent sees)
|
| 28 |
+
# ==========================================
|
| 29 |
+
|
| 30 |
+
class AccountantState(BaseModel):
|
| 31 |
+
"""The observation space returned to the agent after every step."""
|
| 32 |
+
observation: str = Field(..., description="The current text prompt, system message, or calculator result.")
|
| 33 |
+
is_done: bool = Field(default=False, description="True if the episode has finished.")
|