amanmurari commited on
Commit
f68b823
·
verified ·
1 Parent(s): 044eac2

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. inference.py +58 -31
inference.py CHANGED
@@ -3,9 +3,11 @@
3
  import os
4
  import sys
5
  import json
 
 
6
  from typing import List, Optional
7
 
8
- # Allow imports from repo root
9
  _HERE = os.path.dirname(os.path.abspath(__file__))
10
  _PARENT = os.path.dirname(_HERE)
11
  for _p in (_HERE, _PARENT):
@@ -21,14 +23,16 @@ except ImportError:
21
  from client import TrafficControlEnv # type: ignore
22
  from models import TrafficAction, TrafficObservation # type: ignore
23
 
24
- # Environment variables - read per validator spec
25
- API_BASE_URL = os.environ["API_BASE_URL"]
26
- API_KEY = os.environ["API_KEY"]
27
- MODEL_NAME = os.getenv("MODEL_NAME", "gpt-4o-mini")
28
- SERVER_URL = os.getenv("SERVER_URL", "http://localhost:7860")
29
- SEED = 42
30
- MAX_TOKENS = 64
31
- TEMPERATURE = 0.0
 
 
32
 
33
  # ---------------------------------------------------------------------------
34
  # LLM Prompt
@@ -64,8 +68,6 @@ def _sanitize(s: str) -> str:
64
  return s.replace('"', "'").replace("\n", " ")
65
 
66
 
67
-
68
-
69
  def _parse_phase(raw: str) -> int:
70
  """Extract phase from LLM response."""
71
  try:
@@ -79,12 +81,12 @@ def _parse_phase(raw: str) -> int:
79
 
80
 
81
  def get_llm_action(client: OpenAI, obs: TrafficObservation, step: int) -> TrafficAction:
82
- """Call LLM for decision."""
83
  resp = client.chat.completions.create(
84
  model=MODEL_NAME,
85
  messages=[
86
  {"role": "system", "content": SYSTEM_PROMPT},
87
- {"role": "user", "content": _build_prompt(obs, step)},
88
  ],
89
  temperature=TEMPERATURE,
90
  max_tokens=MAX_TOKENS,
@@ -94,6 +96,22 @@ def get_llm_action(client: OpenAI, obs: TrafficObservation, step: int) -> Traffi
94
  return TrafficAction(light_phase=phase)
95
 
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  def run_task(task: str, client: OpenAI) -> dict:
98
  """Run a single task episode."""
99
  print(f'[START] task={task} env=traffic_control model={MODEL_NAME}', flush=True)
@@ -105,27 +123,33 @@ def run_task(task: str, client: OpenAI) -> dict:
105
 
106
  try:
107
  with TrafficControlEnv(base_url=SERVER_URL).sync() as env:
108
- obs = env.reset(task_id=task, seed=SEED)
 
109
 
110
  while not obs.done:
111
  step += 1
 
 
112
  action = get_llm_action(client, obs, step)
113
  action_str = f"light_phase={action.light_phase}"
114
 
115
  try:
116
- obs = env.step(action)
117
- reward_val = obs.reward if obs.reward is not None else 0.0
 
 
118
  rewards.append(reward_val)
119
- done = obs.done
120
  last_error = None
121
  except Exception as exc:
122
  reward_val = 0.0
123
- done = True
124
  last_error = _sanitize(str(exc))
125
 
126
  error_str = "null" if last_error is None else f'"{last_error}"'
127
  print(
128
- f'[STEP] step={step} action={action_str} reward={reward_val:.2f} done={str(done).lower()} error={error_str}',
 
129
  flush=True,
130
  )
131
 
@@ -134,20 +158,20 @@ def run_task(task: str, client: OpenAI) -> dict:
134
 
135
  except Exception as exc:
136
  last_error = _sanitize(str(exc))
 
137
 
138
- success = done and last_error is None
139
- rewards_str = ",".join(f"{r:.2f}" for r in rewards)
140
-
141
- # Calculate normalized score [0, 1]
142
  total_reward = sum(rewards)
143
- max_possible = step * 10.0 # Approximate max per step
144
- score = min(1.0, max(0.0, total_reward / max_possible)) if max_possible > 0 else 0.0
145
-
146
  print(
147
- f'[END] success={str(success).lower()} steps={step} score={score:.2f} rewards={rewards_str}',
 
148
  flush=True,
149
  )
150
-
151
  return {"success": success, "steps": step, "rewards": rewards}
152
 
153
 
@@ -157,10 +181,13 @@ def run_task(task: str, client: OpenAI) -> dict:
157
 
158
  def main():
159
  """Main entry point."""
160
- # Initialize OpenAI client with environment variables
 
 
 
161
  client = OpenAI(
162
- base_url=os.environ["API_BASE_URL"],
163
- api_key=os.environ["API_KEY"]
164
  )
165
 
166
  tasks = ["basic_flow", "emergency_priority", "dynamic_scenarios"]
 
3
  import os
4
  import sys
5
  import json
6
+ import time
7
+ import urllib.request
8
  from typing import List, Optional
9
 
10
+ # Allow imports from repo root so both container-root and package contexts work
11
  _HERE = os.path.dirname(os.path.abspath(__file__))
12
  _PARENT = os.path.dirname(_HERE)
13
  for _p in (_HERE, _PARENT):
 
23
  from client import TrafficControlEnv # type: ignore
24
  from models import TrafficAction, TrafficObservation # type: ignore
25
 
26
+ # ---------------------------------------------------------------------------
27
+ # Environment variables — MUST be injected by the hackathon validator
28
+ # ---------------------------------------------------------------------------
29
+ API_BASE_URL = os.environ["API_BASE_URL"] # e.g. the LiteLLM proxy URL
30
+ API_KEY = os.environ["API_KEY"] # LiteLLM proxy API key
31
+ MODEL_NAME = os.getenv("MODEL_NAME", "gpt-4o-mini")
32
+ SERVER_URL = os.getenv("SERVER_URL", "http://localhost:7860")
33
+ SEED = 42
34
+ MAX_TOKENS = 64
35
+ TEMPERATURE = 0.0
36
 
37
  # ---------------------------------------------------------------------------
38
  # LLM Prompt
 
68
  return s.replace('"', "'").replace("\n", " ")
69
 
70
 
 
 
71
  def _parse_phase(raw: str) -> int:
72
  """Extract phase from LLM response."""
73
  try:
 
81
 
82
 
83
  def get_llm_action(client: OpenAI, obs: TrafficObservation, step: int) -> TrafficAction:
84
+ """Call LLM proxy for a traffic phase decision."""
85
  resp = client.chat.completions.create(
86
  model=MODEL_NAME,
87
  messages=[
88
  {"role": "system", "content": SYSTEM_PROMPT},
89
+ {"role": "user", "content": _build_prompt(obs, step)},
90
  ],
91
  temperature=TEMPERATURE,
92
  max_tokens=MAX_TOKENS,
 
96
  return TrafficAction(light_phase=phase)
97
 
98
 
99
+ def _wait_for_server(url: str, timeout: int = 60) -> None:
100
+ """Block until the env server is healthy or timeout expires."""
101
+ health_url = url.rstrip("/") + "/health"
102
+ deadline = time.time() + timeout
103
+ while time.time() < deadline:
104
+ try:
105
+ with urllib.request.urlopen(health_url, timeout=3) as r:
106
+ if r.status == 200:
107
+ return
108
+ except Exception:
109
+ pass
110
+ time.sleep(2)
111
+ # If the server never came up, log and continue anyway
112
+ print(f"[WARN] Server not healthy after {timeout}s — proceeding anyway", flush=True)
113
+
114
+
115
  def run_task(task: str, client: OpenAI) -> dict:
116
  """Run a single task episode."""
117
  print(f'[START] task={task} env=traffic_control model={MODEL_NAME}', flush=True)
 
123
 
124
  try:
125
  with TrafficControlEnv(base_url=SERVER_URL).sync() as env:
126
+ # env.reset() returns a TrafficObservation directly
127
+ obs: TrafficObservation = env.reset(task_id=task, seed=SEED)
128
 
129
  while not obs.done:
130
  step += 1
131
+
132
+ # Call the LLM proxy — this is the call the validator monitors
133
  action = get_llm_action(client, obs, step)
134
  action_str = f"light_phase={action.light_phase}"
135
 
136
  try:
137
+ # env.step() returns a StepResult; unwrap the observation
138
+ result = env.step(action)
139
+ obs = result.observation # TrafficObservation
140
+ reward_val = result.reward if result.reward is not None else 0.0
141
  rewards.append(reward_val)
142
+ done = result.done
143
  last_error = None
144
  except Exception as exc:
145
  reward_val = 0.0
146
+ done = True
147
  last_error = _sanitize(str(exc))
148
 
149
  error_str = "null" if last_error is None else f'"{last_error}"'
150
  print(
151
+ f'[STEP] step={step} action={action_str} '
152
+ f'reward={reward_val:.2f} done={str(done).lower()} error={error_str}',
153
  flush=True,
154
  )
155
 
 
158
 
159
  except Exception as exc:
160
  last_error = _sanitize(str(exc))
161
+ print(f"[WARN] Episode error: {last_error}", flush=True)
162
 
163
+ success = done and last_error is None
164
+ rewards_str = ",".join(f"{r:.2f}" for r in rewards) if rewards else "0.00"
 
 
165
  total_reward = sum(rewards)
166
+ max_possible = step * 10.0
167
+ score = min(1.0, max(0.0, total_reward / max_possible)) if max_possible > 0 else 0.0
168
+
169
  print(
170
+ f'[END] success={str(success).lower()} steps={step} '
171
+ f'score={score:.2f} rewards={rewards_str}',
172
  flush=True,
173
  )
174
+
175
  return {"success": success, "steps": step, "rewards": rewards}
176
 
177
 
 
181
 
182
  def main():
183
  """Main entry point."""
184
+ # Wait for the env server to be ready before starting inference
185
+ _wait_for_server(SERVER_URL)
186
+
187
+ # Initialize OpenAI client with hackathon-injected proxy credentials
188
  client = OpenAI(
189
+ base_url=API_BASE_URL,
190
+ api_key=API_KEY,
191
  )
192
 
193
  tasks = ["basic_flow", "emergency_priority", "dynamic_scenarios"]