Upload folder using huggingface_hub
Browse files- grader.py +1 -1
- guidelines.txt +113 -0
- inference.py +15 -3
- server/layout_environment.py +1 -1
grader.py
CHANGED
|
@@ -20,7 +20,7 @@ class TaskGrade:
|
|
| 20 |
q_delta: float
|
| 21 |
|
| 22 |
|
| 23 |
-
OPEN_INTERVAL_EPS =
|
| 24 |
|
| 25 |
|
| 26 |
def _clamp01(x: float) -> float:
|
|
|
|
| 20 |
q_delta: float
|
| 21 |
|
| 22 |
|
| 23 |
+
OPEN_INTERVAL_EPS = 5e-2
|
| 24 |
|
| 25 |
|
| 26 |
def _clamp01(x: float) -> float:
|
guidelines.txt
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
🚀 Hackathon Submission Guidelines (OpenEnv RL Challenge)
|
| 2 |
+
1. Project Structure
|
| 3 |
+
Your inference script must be named inference.py
|
| 4 |
+
It must be located in the root directory of your project
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
2. LLM Usage Requirements
|
| 9 |
+
You must use the OpenAI Client for all LLM calls
|
| 10 |
+
Do not use alternative SDKs or direct HTTP calls
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
3. Required Environment Variables
|
| 15 |
+
Your inference.py must read the following environment variables:
|
| 16 |
+
API_BASE_URL
|
| 17 |
+
Description: API endpoint for the LLM
|
| 18 |
+
Requirement: Must include a default value
|
| 19 |
+
MODEL_NAME
|
| 20 |
+
Description: Model identifier used for inference
|
| 21 |
+
Requirement: Must include a default value
|
| 22 |
+
HF_TOKEN
|
| 23 |
+
Description: Hugging Face API token
|
| 24 |
+
Requirement: Mandatory (no default required)
|
| 25 |
+
|
| 26 |
+
4. INFERENCE OUTPUT FORMAT
|
| 27 |
+
The script must emit exactly three line types to stdout, in this order:
|
| 28 |
+
[START] task=<task_name> env=<benchmark> model=<model_name>
|
| 29 |
+
[STEP] step=<n> action=<action_str> reward=<0.00> done=<true|false> error=<msg|null>
|
| 30 |
+
[END] success=<true|false> steps=<n> rewards=<r1,r2,...,rn>
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
Rules:
|
| 35 |
+
- One [START] line at episode begin.
|
| 36 |
+
- One [STEP] line per step, immediately after env.step() returns.
|
| 37 |
+
- One [END] line after env.close(), always emitted (even on exception).
|
| 38 |
+
- reward and rewards are formatted to 2 decimal places.
|
| 39 |
+
- done and success are lowercase booleans: true or false.
|
| 40 |
+
- error is the raw last_action_error string, or null if none.
|
| 41 |
+
- All fields on a single line with no newlines within a line.
|
| 42 |
+
Example:
|
| 43 |
+
[START] task=click-test env=miniwob model=Qwen3-VL-30B
|
| 44 |
+
[STEP] step=1 action=click('123') reward=0.00 done=false error=null
|
| 45 |
+
[STEP] step=2 action=fill('456','text') reward=0.00 done=false error=null
|
| 46 |
+
[STEP] step=3 action=click('789') reward=1.00 done=true error=null
|
| 47 |
+
[END] success=true steps=3 rewards=0.00,0.00,1.00
|
| 48 |
+
✅ Example (inference.py)
|
| 49 |
+
import os
|
| 50 |
+
from openai import OpenAI
|
| 51 |
+
|
| 52 |
+
# Read environment variables with defaults where required
|
| 53 |
+
API_BASE_URL = os.getenv("API_BASE_URL", "https://api.openai.com/v1")
|
| 54 |
+
MODEL_NAME = os.getenv("MODEL_NAME", "gpt-4.1-mini")
|
| 55 |
+
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 56 |
+
|
| 57 |
+
if HF_TOKEN is None:
|
| 58 |
+
raise ValueError("HF_TOKEN environment variable is required")
|
| 59 |
+
|
| 60 |
+
# Initialize OpenAI client
|
| 61 |
+
client = OpenAI(
|
| 62 |
+
base_url=API_BASE_URL,
|
| 63 |
+
api_key=HF_TOKEN
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
def run_inference(prompt: str):
|
| 67 |
+
response = client.chat.completions.create(
|
| 68 |
+
model=MODEL_NAME,
|
| 69 |
+
messages=[
|
| 70 |
+
{"role": "user", "content": prompt}
|
| 71 |
+
]
|
| 72 |
+
)
|
| 73 |
+
response = response.choices[0].message.content
|
| 74 |
+
# Print output based on above given format
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
if __name__ == "__main__":
|
| 78 |
+
print(run_inference("Hello from OpenEnv!"))
|
| 79 |
+
|
| 80 |
+
4. Hugging Face Space Guidelines
|
| 81 |
+
Building a Hugging Face Space can take significant time, especially if multiple spaces are active
|
| 82 |
+
To avoid delays:
|
| 83 |
+
Turn off all unnecessary spaces
|
| 84 |
+
Keep only your primary submission space running
|
| 85 |
+
|
| 86 |
+
5. Submission Validation Rules
|
| 87 |
+
The system will check if your Hugging Face Space is live
|
| 88 |
+
If your space is not in a running state, your submission will fail automatically
|
| 89 |
+
Before submitting:
|
| 90 |
+
Ensure your space is fully built
|
| 91 |
+
Confirm it is in the “Running” state
|
| 92 |
+
|
| 93 |
+
6. Hardware Requirements
|
| 94 |
+
Your solution will be executed inside a Docker container with limited resources
|
| 95 |
+
It must run within the following constraints:
|
| 96 |
+
2 vCPU
|
| 97 |
+
8 GB RAM
|
| 98 |
+
👉 Ensure your model, dependencies, and runtime fit within these limits. Submissions exceeding these constraints may fail during evaluation.
|
| 99 |
+
|
| 100 |
+
6. Resubmissions
|
| 101 |
+
You are allowed to resubmit your project multiple times
|
| 102 |
+
If your submission fails validation, you can:
|
| 103 |
+
Fix the issues
|
| 104 |
+
Ensure your Hugging Face Space is running
|
| 105 |
+
Submit again
|
| 106 |
+
👉 There is no penalty for resubmitting, so iterate until your submission passes all checks.
|
| 107 |
+
|
| 108 |
+
⚠️ Common Failure Cases (Avoid These)
|
| 109 |
+
inference.py not in root directory
|
| 110 |
+
Missing default values for API_BASE_URL or MODEL_NAME
|
| 111 |
+
Missing HF_TOKEN
|
| 112 |
+
Hugging Face Space still building during submission
|
| 113 |
+
Space stopped due to multiple active deployments
|
inference.py
CHANGED
|
@@ -11,6 +11,7 @@ STDOUT FORMAT
|
|
| 11 |
import argparse
|
| 12 |
import asyncio
|
| 13 |
import json
|
|
|
|
| 14 |
import os
|
| 15 |
import sys
|
| 16 |
from pathlib import Path
|
|
@@ -39,6 +40,8 @@ BENCHMARK = os.getenv("LAYOUT_BENCHMARK", "layoutenv")
|
|
| 39 |
TEMPERATURE = float(os.getenv("TEMPERATURE", "0.0"))
|
| 40 |
MAX_TOKENS = 200
|
| 41 |
SUCCESS_Q_DELTA = 0.1
|
|
|
|
|
|
|
| 42 |
PRINT_SUMMARY_STDERR = os.getenv("PRINT_SUMMARY_STDERR", "0") == "1"
|
| 43 |
EARLY_STOP_ON_SUCCESS = os.getenv("EARLY_STOP_ON_SUCCESS", "1") == "1"
|
| 44 |
|
|
@@ -67,21 +70,30 @@ def resolve_background_image_path(sample: Dict[str, Any], dataset_json_path: str
|
|
| 67 |
return abs_path
|
| 68 |
|
| 69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
def log_start(task: str, env: str, model: str) -> None:
|
| 71 |
print(f"[START] task={task} env={env} model={model}", flush=True)
|
| 72 |
|
| 73 |
|
| 74 |
def log_step(step: int, action_str: str, reward: float, done: bool, error: Optional[str]) -> None:
|
| 75 |
error_val = error if error else "null"
|
|
|
|
| 76 |
print(
|
| 77 |
-
f"[STEP] step={step} action={action_str} reward={
|
| 78 |
f"done={str(done).lower()} error={error_val}",
|
| 79 |
flush=True,
|
| 80 |
)
|
| 81 |
|
| 82 |
|
| 83 |
def log_end(success: bool, steps: int, rewards: List[float]) -> None:
|
| 84 |
-
|
|
|
|
| 85 |
print(
|
| 86 |
f"[END] success={str(success).lower()} steps={steps} rewards={rewards_str}",
|
| 87 |
flush=True,
|
|
@@ -208,7 +220,7 @@ async def run_episode(
|
|
| 208 |
action_str = action_to_string(action, raw)
|
| 209 |
result = await env.step(action)
|
| 210 |
obs = result.observation
|
| 211 |
-
reward = result.reward
|
| 212 |
done = result.done
|
| 213 |
raw_error = getattr(result, "last_action_error", None)
|
| 214 |
if raw_error is None:
|
|
|
|
| 11 |
import argparse
|
| 12 |
import asyncio
|
| 13 |
import json
|
| 14 |
+
import math
|
| 15 |
import os
|
| 16 |
import sys
|
| 17 |
from pathlib import Path
|
|
|
|
| 40 |
TEMPERATURE = float(os.getenv("TEMPERATURE", "0.0"))
|
| 41 |
MAX_TOKENS = 200
|
| 42 |
SUCCESS_Q_DELTA = 0.1
|
| 43 |
+
# Clamp epsilon — keep printed rewards strictly inside (0, 1).
|
| 44 |
+
_REWARD_EPS = 0.05
|
| 45 |
PRINT_SUMMARY_STDERR = os.getenv("PRINT_SUMMARY_STDERR", "0") == "1"
|
| 46 |
EARLY_STOP_ON_SUCCESS = os.getenv("EARLY_STOP_ON_SUCCESS", "1") == "1"
|
| 47 |
|
|
|
|
| 70 |
return abs_path
|
| 71 |
|
| 72 |
|
| 73 |
+
def _clamp_reward(r: float) -> float:
|
| 74 |
+
"""Ensure reward is strictly inside (0, 1) — never exact 0.0 or 1.0."""
|
| 75 |
+
if r is None or math.isnan(r) or math.isinf(r):
|
| 76 |
+
return 0.5
|
| 77 |
+
return min(max(float(r), _REWARD_EPS), 1.0 - _REWARD_EPS)
|
| 78 |
+
|
| 79 |
+
|
| 80 |
def log_start(task: str, env: str, model: str) -> None:
|
| 81 |
print(f"[START] task={task} env={env} model={model}", flush=True)
|
| 82 |
|
| 83 |
|
| 84 |
def log_step(step: int, action_str: str, reward: float, done: bool, error: Optional[str]) -> None:
|
| 85 |
error_val = error if error else "null"
|
| 86 |
+
safe_reward = _clamp_reward(reward)
|
| 87 |
print(
|
| 88 |
+
f"[STEP] step={step} action={action_str} reward={safe_reward:.2f} "
|
| 89 |
f"done={str(done).lower()} error={error_val}",
|
| 90 |
flush=True,
|
| 91 |
)
|
| 92 |
|
| 93 |
|
| 94 |
def log_end(success: bool, steps: int, rewards: List[float]) -> None:
|
| 95 |
+
safe_rewards = [_clamp_reward(r) for r in rewards]
|
| 96 |
+
rewards_str = ",".join(f"{r:.2f}" for r in safe_rewards)
|
| 97 |
print(
|
| 98 |
f"[END] success={str(success).lower()} steps={steps} rewards={rewards_str}",
|
| 99 |
flush=True,
|
|
|
|
| 220 |
action_str = action_to_string(action, raw)
|
| 221 |
result = await env.step(action)
|
| 222 |
obs = result.observation
|
| 223 |
+
reward = _clamp_reward(result.reward)
|
| 224 |
done = result.done
|
| 225 |
raw_error = getattr(result, "last_action_error", None)
|
| 226 |
if raw_error is None:
|
server/layout_environment.py
CHANGED
|
@@ -503,7 +503,7 @@ TERMINAL_BONUS_SCALE = 5.0
|
|
| 503 |
TERMINAL_PENALTY = -1.0
|
| 504 |
# Align terminal shaping with the easiest grader delta threshold.
|
| 505 |
Q_DELTA_THRESHOLD = 0.05
|
| 506 |
-
VISIBLE_REWARD_EPS = 0.
|
| 507 |
|
| 508 |
|
| 509 |
def _normalize_visible_reward(raw_reward: float | int) -> float:
|
|
|
|
| 503 |
TERMINAL_PENALTY = -1.0
|
| 504 |
# Align terminal shaping with the easiest grader delta threshold.
|
| 505 |
Q_DELTA_THRESHOLD = 0.05
|
| 506 |
+
VISIBLE_REWARD_EPS = 0.05
|
| 507 |
|
| 508 |
|
| 509 |
def _normalize_visible_reward(raw_reward: float | int) -> float:
|