amanmurari commited on
Commit
a1a27eb
Β·
verified Β·
1 Parent(s): 10fb04e

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +163 -187
README.md CHANGED
@@ -1,255 +1,231 @@
1
  ---
2
- title: Traffic Control Environment Server
3
- emoji: 🎯
4
- colorFrom: gray
5
- colorTo: gray
6
  sdk: docker
7
  pinned: false
8
  app_port: 7860
9
  base_path: /web
10
  tags:
11
  - openenv
 
 
 
 
12
  ---
13
 
14
- # Traffic Control Environment
15
 
16
- A simple test environment that echoes back messages. Perfect for testing the env APIs as well as demonstrating environment usage patterns.
17
 
18
- ## Quick Start
19
-
20
- The simplest way to use the Traffic Control environment is through the `TrafficControlEnv` class:
21
 
22
- ```python
23
- from traffic_control import TrafficControlAction, TrafficControlEnv
24
 
25
- try:
26
- # Create environment from Docker image
27
- traffic_controlenv = TrafficControlEnv.from_docker_image("traffic_control-env:latest")
28
 
29
- # Reset
30
- result = traffic_controlenv.reset()
31
- print(f"Reset: {result.observation.echoed_message}")
32
 
33
- # Send multiple messages
34
- messages = ["Hello, World!", "Testing echo", "Final message"]
 
 
 
35
 
36
- for msg in messages:
37
- result = traffic_controlenv.step(TrafficControlAction(message=msg))
38
- print(f"Sent: '{msg}'")
39
- print(f" β†’ Echoed: '{result.observation.echoed_message}'")
40
- print(f" β†’ Length: {result.observation.message_length}")
41
- print(f" β†’ Reward: {result.reward}")
42
 
43
- finally:
44
- # Always clean up
45
- traffic_controlenv.close()
46
- ```
47
 
48
- That's it! The `TrafficControlEnv.from_docker_image()` method handles:
49
- - Starting the Docker container
50
- - Waiting for the server to be ready
51
- - Connecting to the environment
52
- - Container cleanup when you call `close()`
53
 
54
- ## Building the Docker Image
55
 
56
- Before using the environment, you need to build the Docker image:
57
 
58
- ```bash
59
- # From project root
60
- docker build -t traffic_control-env:latest -f server/Dockerfile .
 
 
 
61
  ```
62
 
63
- ## Deploying to Hugging Face Spaces
64
-
65
- You can easily deploy your OpenEnv environment to Hugging Face Spaces using the `openenv push` command:
66
-
67
- ```bash
68
- # From the environment directory (where openenv.yaml is located)
69
- openenv push
70
-
71
- # Or specify options
72
- openenv push --namespace my-org --private
 
 
 
 
 
 
73
  ```
74
 
75
- The `openenv push` command will:
76
- 1. Validate that the directory is an OpenEnv environment (checks for `openenv.yaml`)
77
- 2. Prepare a custom build for Hugging Face Docker space (enables web interface)
78
- 3. Upload to Hugging Face (ensuring you're logged in)
79
-
80
- ### Prerequisites
81
-
82
- - Authenticate with Hugging Face: The command will prompt for login if not already authenticated
83
-
84
- ### Options
85
-
86
- - `--directory`, `-d`: Directory containing the OpenEnv environment (defaults to current directory)
87
- - `--repo-id`, `-r`: Repository ID in format 'username/repo-name' (defaults to 'username/env-name' from openenv.yaml)
88
- - `--base-image`, `-b`: Base Docker image to use (overrides Dockerfile FROM)
89
- - `--private`: Deploy the space as private (default: public)
90
 
91
- ### Examples
92
 
93
- ```bash
94
- # Push to your personal namespace (defaults to username/env-name from openenv.yaml)
95
- openenv push
 
 
 
 
 
 
96
 
97
- # Push to a specific repository
98
- openenv push --repo-id my-org/my-env
99
 
100
- # Push with a custom base image
101
- openenv push --base-image ghcr.io/meta-pytorch/openenv-base:latest
102
 
103
- # Push as a private space
104
- openenv push --private
 
 
 
 
 
105
 
106
- # Combine options
107
- openenv push --repo-id my-org/my-env --base-image custom-base:latest --private
 
 
 
108
  ```
109
 
110
- After deployment, your space will be available at:
111
- `https://huggingface.co/spaces/<repo-id>`
 
 
 
 
112
 
113
- The deployed space includes:
114
- - **Web Interface** at `/web` - Interactive UI for exploring the environment
115
- - **API Documentation** at `/docs` - Full OpenAPI/Swagger interface
116
- - **Health Check** at `/health` - Container health monitoring
117
- - **WebSocket** at `/ws` - Persistent session endpoint for low-latency interactions
118
 
119
- ## Environment Details
120
 
121
- ### Action
122
- **TrafficControlAction**: Contains a single field
123
- - `message` (str) - The message to echo back
124
 
125
- ### Observation
126
- **TrafficControlObservation**: Contains the echo response and metadata
127
- - `echoed_message` (str) - The message echoed back
128
- - `message_length` (int) - Length of the message
129
- - `reward` (float) - Reward based on message length (length Γ— 0.1)
130
- - `done` (bool) - Always False for echo environment
131
- - `metadata` (dict) - Additional info like step count
132
 
133
- ### Reward
134
- The reward is calculated as: `message_length Γ— 0.1`
135
- - "Hi" β†’ reward: 0.2
136
- - "Hello, World!" β†’ reward: 1.3
137
- - Empty message β†’ reward: 0.0
138
 
139
- ## Advanced Usage
140
 
141
- ### Connecting to an Existing Server
142
 
143
- If you already have a Traffic Control environment server running, you can connect directly:
144
 
145
- ```python
146
- from traffic_control import TrafficControlEnv
147
 
148
- # Connect to existing server
149
- traffic_controlenv = TrafficControlEnv(base_url="<ENV_HTTP_URL_HERE>")
150
 
151
- # Use as normal
152
- result = traffic_controlenv.reset()
153
- result = traffic_controlenv.step(TrafficControlAction(message="Hello!"))
 
 
 
 
 
 
 
 
 
 
154
  ```
155
 
156
- Note: When connecting to an existing server, `traffic_controlenv.close()` will NOT stop the server.
157
-
158
- ### Using the Context Manager
159
-
160
- The client supports context manager usage for automatic connection management:
161
 
162
- ```python
163
- from traffic_control import TrafficControlAction, TrafficControlEnv
 
 
 
 
164
 
165
- # Connect with context manager (auto-connects and closes)
166
- with TrafficControlEnv(base_url="http://localhost:8000") as env:
167
- result = env.reset()
168
- print(f"Reset: {result.observation.echoed_message}")
169
- # Multiple steps with low latency
170
- for msg in ["Hello", "World", "!"]:
171
- result = env.step(TrafficControlAction(message=msg))
172
- print(f"Echoed: {result.observation.echoed_message}")
173
  ```
174
 
175
- The client uses WebSocket connections for:
176
- - **Lower latency**: No HTTP connection overhead per request
177
- - **Persistent session**: Server maintains your environment state
178
- - **Efficient for episodes**: Better for many sequential steps
179
-
180
- ### Concurrent WebSocket Sessions
181
-
182
- The server supports multiple concurrent WebSocket connections. To enable this,
183
- modify `server/app.py` to use factory mode:
184
 
185
- ```python
186
- # In server/app.py - use factory mode for concurrent sessions
187
- app = create_app(
188
- TrafficControlEnvironment, # Pass class, not instance
189
- TrafficControlAction,
190
- TrafficControlObservation,
191
- max_concurrent_envs=4, # Allow 4 concurrent sessions
192
- )
193
  ```
194
 
195
- Then multiple clients can connect simultaneously:
196
-
197
- ```python
198
- from traffic_control import TrafficControlAction, TrafficControlEnv
199
- from concurrent.futures import ThreadPoolExecutor
200
 
201
- def run_episode(client_id: int):
202
- with TrafficControlEnv(base_url="http://localhost:8000") as env:
203
- result = env.reset()
204
- for i in range(10):
205
- result = env.step(TrafficControlAction(message=f"Client {client_id}, step {i}"))
206
- return client_id, result.observation.message_length
207
 
208
- # Run 4 episodes concurrently
209
- with ThreadPoolExecutor(max_workers=4) as executor:
210
- results = list(executor.map(run_episode, range(4)))
211
- ```
212
 
213
- ## Development & Testing
 
 
 
 
 
 
 
 
214
 
215
- ### Direct Environment Testing
216
 
217
- Test the environment logic directly without starting the HTTP server:
218
 
219
- ```bash
220
- # From the server directory
221
- python3 server/traffic_control_environment.py
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  ```
223
 
224
- This verifies that:
225
- - Environment resets correctly
226
- - Step executes actions properly
227
- - State tracking works
228
- - Rewards are calculated correctly
229
 
230
- ### Running Locally
231
 
232
- Run the server locally for development:
 
 
 
 
 
 
233
 
234
- ```bash
235
- uvicorn server.app:app --reload
236
- ```
237
 
238
- ## Project Structure
239
 
240
  ```
241
- traffic_control/
242
- β”œβ”€β”€ .dockerignore # Docker build exclusions
243
- β”œβ”€β”€ __init__.py # Module exports
244
- β”œβ”€β”€ README.md # This file
245
- β”œβ”€β”€ openenv.yaml # OpenEnv manifest
246
- β”œβ”€β”€ pyproject.toml # Project metadata and dependencies
247
- β”œβ”€β”€ uv.lock # Locked dependencies (generated)
248
- β”œβ”€β”€ client.py # TrafficControlEnv client
249
- β”œβ”€β”€ models.py # Action and Observation models
250
- └── server/
251
- β”œβ”€β”€ __init__.py # Server module exports
252
- β”œβ”€β”€ traffic_control_environment.py # Core environment logic
253
- ���── app.py # FastAPI application (HTTP + WebSocket endpoints)
254
- └── Dockerfile # Container image definition
255
  ```
 
1
  ---
2
+ title: Autonomous Traffic Control Environment
3
+ emoji: 🚦
4
+ colorFrom: red
5
+ colorTo: green
6
  sdk: docker
7
  pinned: false
8
  app_port: 7860
9
  base_path: /web
10
  tags:
11
  - openenv
12
+ - reinforcement-learning
13
+ - traffic-control
14
+ - emergency-vehicles
15
+ - autonomous-systems
16
  ---
17
 
18
+ # 🚦 Autonomous Traffic Control β€” OpenEnv Environment
19
 
20
+ An LLM-driven reinforcement learning environment for autonomous traffic signal control at a 4-way intersection. Built for the **Meta Γ— PyTorch Γ— SST Γ— OpenEnv Hackathon**.
21
 
22
+ - **HF Space:** [amanmurari/sst-hack](https://huggingface.co/spaces/amanmurari/sst-hack)
23
+ - **GitHub:** [amanmurari/openenv-hc2](https://github.com/amanmurari/openenv-hc2)
 
24
 
25
+ ---
 
26
 
27
+ ## Overview
 
 
28
 
29
+ An LLM agent controls traffic signals to maximise vehicle throughput while prioritising emergency vehicles. The environment features:
 
 
30
 
31
+ - Sinusoidal traffic wave patterns (realistic rush-hour simulation)
32
+ - Emergency vehicles with escalating urgency (urgency^1.5 penalty per waiting step)
33
+ - Yellow-light transition state machine
34
+ - Traffic surge events in hard tasks
35
+ - Multi-objective grading aligned with real traffic KPIs
36
 
37
+ ---
 
 
 
 
 
38
 
39
+ ## Tasks
 
 
 
40
 
41
+ | Task | Difficulty | Steps | Key Challenge |
42
+ |---|---|---|---|
43
+ | `basic_flow` | Easy | 200 | Maximise throughput (target 1.8 veh/step) |
44
+ | `emergency_priority` | Medium | 300 | Clear emergencies fast (avg delay < 3 steps) |
45
+ | `dynamic_scenarios` | Hard | 400 | Surge traffic + simultaneous emergencies, no collisions |
46
 
47
+ ---
48
 
49
+ ## Action & Observation Space
50
 
51
+ ### Action
52
+ ```python
53
+ TrafficAction(light_phase: int)
54
+ # 0 = NS_GREEN (North-South green, East-West red)
55
+ # 1 = EW_GREEN (East-West green, North-South red)
56
+ # 2 = ALL_RED (All red β€” emergency clearance)
57
  ```
58
 
59
+ ### Observation
60
+ ```python
61
+ TrafficObservation(
62
+ current_phase: int, # Active phase (0-4, incl. yellow transitions)
63
+ time_in_phase: int, # Steps held in current phase
64
+ queue_lengths: List[int], # Regular vehicle queue [N, S, E, W]
65
+ emergency_queue: List[int], # Emergency vehicle count [N, S, E, W]
66
+ emergency_urgency: List[int],# Max urgency 0-10 per approach
67
+ vehicles_passed: int, # Regular vehicles cleared this step
68
+ emergency_passed: int, # Emergency vehicles cleared this step
69
+ avg_wait_time: float, # Avg waiting time across all queued vehicles
70
+ queue_trend: List[int], # Queue growth since last step [N, S, E, W]
71
+ collision: bool, # Gridlock-induced collision flag
72
+ done: bool,
73
+ reward: float,
74
+ )
75
  ```
76
 
77
+ ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
+ ## Reward Function
80
 
81
+ ```
82
+ +0.30 Γ— regular vehicles cleared per step
83
+ +12.0 Γ— emergency vehicles cleared per step
84
+ -0.08 Γ— total vehicles waiting (queue pressure)
85
+ -(urgency^1.5) Γ— 0.5 per waiting emergency vehicle (every step!)
86
+ -0.50 to -2.0 for unnecessary phase switch (proportional to empty-queue ratio)
87
+ +0.05 stability bonus when traffic flows without switching
88
+ -200 gridlock collision (episode-ending catastrophe)
89
+ ```
90
 
91
+ ---
 
92
 
93
+ ## Grading Weights
 
94
 
95
+ ### basic_flow
96
+ ```
97
+ score = throughput_score Γ— 0.60 + efficiency_score Γ— 0.40 + stability_bonus
98
+ throughput_score = min(vehicles_per_step / 1.8, 1.0)
99
+ efficiency_score = 1 / (1 + avg_waiting Γ— 0.1)
100
+ stability_bonus = max(0, 0.05 Γ— (1 βˆ’ min(switch_rate Γ— 4, 1.0)))
101
+ ```
102
 
103
+ ### emergency_priority
104
+ ```
105
+ score = throughput Γ— 0.30 + em_rate Γ— 0.35 + delay Γ— 0.20 + efficiency Γ— 0.15
106
+ em_rate = min(emergency_cleared_per_step / (1/20), 1.0)
107
+ delay = max(0, 1 βˆ’ avg_em_delay / 12)
108
  ```
109
 
110
+ ### dynamic_scenarios
111
+ ```
112
+ score = throughput Γ— 0.25 + em_rate Γ— 0.30 + delay Γ— 0.20
113
+ + efficiency Γ— 0.15 + adaptability Γ— 0.10
114
+ adaptability = 1 / (1 + phase_changes_per_step Γ— 0.5)
115
+ ```
116
 
117
+ ---
 
 
 
 
118
 
119
+ ## Agent Architecture
120
 
121
+ The inference agent uses a **hybrid heuristic + LLM** architecture:
 
 
122
 
123
+ 1. **Heuristic recommender** β€” computes directional pressure using the actual reward formula (`urgency^1.5 Γ— 0.5`), applies 5 priority rules (critical emergency, moderate emergency, hysteresis, pressure-based switch, default hold).
 
 
 
 
 
 
124
 
125
+ 2. **Live score projection** β€” computes current projected grading scores (throughput, emergency rate, delay, efficiency, adaptability) from `env.state()` and includes them in every LLM prompt.
 
 
 
 
126
 
127
+ 3. **Chain-of-thought LLM** β€” the model reasons through scoring implications then outputs `{"light_phase": N}` on the final line.
128
 
129
+ 4. **Heuristic fallback** β€” if LLM output is unparseable, silently falls back to the heuristic. No crashes, no missed steps.
130
 
131
+ ---
132
 
133
+ ## Quick Start
 
134
 
135
+ ### Connect to the live HF Space
 
136
 
137
+ ```python
138
+ from traffic_control.client import TrafficControlEnv
139
+ from traffic_control.models import TrafficAction
140
+
141
+ with TrafficControlEnv(base_url="https://amanmurari-sst-hack.hf.space").sync() as env:
142
+ result = env.reset(task_id="basic_flow", seed=42)
143
+ obs = result.observation
144
+
145
+ while not result.done:
146
+ action = TrafficAction(light_phase=0) # replace with your agent
147
+ result = env.step(action)
148
+ obs = result.observation
149
+ print(f"Cleared: {obs.vehicles_passed} regular, {obs.emergency_passed} emergency | reward={result.reward:.2f}")
150
  ```
151
 
152
+ ### Run inference locally
 
 
 
 
153
 
154
+ ```bash
155
+ # Set required env vars
156
+ export API_BASE_URL="https://router.huggingface.co/v1"
157
+ export HF_TOKEN="hf_..."
158
+ export MODEL_NAME="Qwen/Qwen2.5-72B-Instruct"
159
+ export SERVER_URL="http://localhost:7860"
160
 
161
+ python inference.py
 
 
 
 
 
 
 
162
  ```
163
 
164
+ ### Build and run with Docker
 
 
 
 
 
 
 
 
165
 
166
+ ```bash
167
+ docker build -t traffic-control-env .
168
+ docker run -p 7860:7860 traffic-control-env
 
 
 
 
 
169
  ```
170
 
171
+ ---
 
 
 
 
172
 
173
+ ## API Endpoints
 
 
 
 
 
174
 
175
+ Once the server is running at `http://localhost:7860`:
 
 
 
176
 
177
+ | Endpoint | Description |
178
+ |---|---|
179
+ | `GET /health` | Health check β€” returns `{"status": "ok"}` |
180
+ | `POST /reset` | Reset episode β€” body: `{"task_id": "basic_flow", "seed": 42}` |
181
+ | `POST /step` | Execute action β€” body: `{"light_phase": 0}` |
182
+ | `GET /state` | Cumulative episode state |
183
+ | `WS /ws` | WebSocket endpoint for low-latency multi-step sessions |
184
+ | `GET /web` | Interactive web dashboard |
185
+ | `GET /docs` | OpenAPI / Swagger docs |
186
 
187
+ ---
188
 
189
+ ## Project Structure
190
 
191
+ ```
192
+ traffic_control/
193
+ β”œβ”€β”€ inference.py # LLM agent (heuristic + chain-of-thought LLM)
194
+ β”œβ”€β”€ client.py # TrafficControlEnv WebSocket client
195
+ β”œβ”€β”€ models.py # TrafficAction / TrafficObservation / TrafficState
196
+ β”œβ”€β”€ environment.py # Core simulation engine
197
+ β”œβ”€β”€ tasks.py # Task graders (basic_flow, emergency_priority, dynamic_scenarios)
198
+ β”œβ”€β”€ dashboard.py # Web UI dashboard
199
+ β”œβ”€β”€ analytics.py # Episode analytics
200
+ β”œβ”€β”€ arena.py # Multi-agent arena
201
+ β”œβ”€β”€ openenv.yaml # OpenEnv manifest
202
+ β”œβ”€β”€ pyproject.toml # Package metadata
203
+ β”œβ”€β”€ Dockerfile # Container (port 7860)
204
+ └── server/
205
+ β”œβ”€β”€ app.py # FastAPI app (HTTP + WebSocket)
206
+ └── traffic_control_environment.py
207
  ```
208
 
209
+ ---
 
 
 
 
210
 
211
+ ## Environment Variables
212
 
213
+ | Variable | Required | Description |
214
+ |---|---|---|
215
+ | `API_BASE_URL` | Yes | LLM proxy endpoint (injected by validator) |
216
+ | `API_KEY` | Yes | Proxy API key (injected by validator) |
217
+ | `HF_TOKEN` | Alt | Hugging Face token (used if `API_KEY` not set) |
218
+ | `MODEL_NAME` | No | LLM model (default: `Qwen/Qwen2.5-72B-Instruct`) |
219
+ | `SERVER_URL` | No | Env server URL (default: `http://localhost:7860`) |
220
 
221
+ ---
 
 
222
 
223
+ ## Stdout Format
224
 
225
  ```
226
+ [START] task=basic_flow env=traffic_control model=Qwen/Qwen2.5-72B-Instruct
227
+ [STEP] step=1 action=light_phase=0 reward=0.65 done=false error=null
228
+ [STEP] step=2 action=light_phase=0 reward=0.80 done=false error=null
229
+ ...
230
+ [END] success=true steps=200 score=0.847 rewards=0.65,0.80,...
 
 
 
 
 
 
 
 
 
231
  ```