sravaniamere commited on
Commit
0a9f157
·
1 Parent(s): 2184846

fix server entry point

Browse files
Files changed (3) hide show
  1. inference.py +114 -49
  2. openenv.yaml +2 -1
  3. server/app.py +8 -0
inference.py CHANGED
@@ -19,6 +19,7 @@ from typing import List, Optional
19
  import re
20
 
21
  import httpx
 
22
  try:
23
  from openai import OpenAI
24
  except Exception:
@@ -34,6 +35,10 @@ MAX_STEPS = 8
34
  SUCCESS_SCORE_THRESHOLD = 0.5
35
 
36
 
 
 
 
 
37
  def log_start(task: str, env: str, model: str) -> None:
38
  print(f"[START] task={task} env={env} model={model}", flush=True)
39
 
@@ -47,6 +52,7 @@ def log_step(
47
  ) -> None:
48
  err = error if error else "null"
49
  done_val = str(done).lower()
 
50
  action_clean = action.replace("\n", " ").replace("\r", "").strip()
51
  print(
52
  f"[STEP] step={step} action={action_clean} "
@@ -56,7 +62,7 @@ def log_step(
56
 
57
 
58
  def log_end(success: bool, steps: int, score: float, rewards: List[float]) -> None:
59
- rewards_str = ",".join(f"{r:.2f}" for r in rewards)
60
  print(
61
  f"[END] success={str(success).lower()} steps={steps} "
62
  f"score={score:.3f} rewards={rewards_str}",
@@ -64,6 +70,10 @@ def log_end(success: bool, steps: int, score: float, rewards: List[float]) -> No
64
  )
65
 
66
 
 
 
 
 
67
  SYSTEM_PROMPT = textwrap.dedent(
68
  """
69
  You are an expert SQL debugger.
@@ -94,14 +104,21 @@ SQL_REPLACEMENTS = {
94
 
95
 
96
  def heuristic_correct_sql(query: str) -> str:
 
97
  corrected = query
98
  for broken, fixed in SQL_REPLACEMENTS.items():
99
- corrected = re.sub(rf"\b{re.escape(broken)}\b", fixed, corrected, flags=re.IGNORECASE)
 
 
100
  return corrected.strip()
101
 
102
 
103
- def get_model_action(client: Optional["OpenAI"], obs: dict, history: List[str]) -> str:
104
- heuristic = heuristic_correct_sql(obs["broken_query"])
 
 
 
 
105
  if client is None:
106
  return heuristic
107
 
@@ -109,7 +126,7 @@ def get_model_action(client: Optional["OpenAI"], obs: dict, history: List[str])
109
  user_prompt = textwrap.dedent(
110
  f"""
111
  Broken SQL query:
112
- {obs["broken_query"]}
113
 
114
  Schema context: {obs.get("schema_context") or "Not provided"}
115
  Error hint: {obs.get("error_hint") or "None"}
@@ -141,93 +158,141 @@ def get_model_action(client: Optional["OpenAI"], obs: dict, history: List[str])
141
  return heuristic
142
 
143
 
 
 
 
 
144
  async def run_task(task_name: str) -> None:
145
- client = None
146
- if OpenAI is not None and API_KEY not in {"", "dummy"}:
147
- try:
148
- client = OpenAI(base_url=API_BASE_URL, api_key=API_KEY)
149
- except Exception as exc:
150
- print(f"[DEBUG] OpenAI client init failed: {exc}", flush=True)
151
 
 
 
 
 
 
152
  rewards: List[float] = []
153
  history: List[str] = []
154
  steps_taken = 0
155
  score = 0.0
156
  success = False
157
 
 
 
 
 
 
 
 
 
158
  log_start(task_name, BENCHMARK, MODEL_NAME)
159
 
160
- http = None
161
  try:
162
  http = httpx.AsyncClient(base_url=ENV_URL, timeout=60.0)
163
 
 
 
 
164
  try:
165
  reset_resp = await http.post("/reset", json={"difficulty": task_name})
166
  reset_resp.raise_for_status()
167
  obs = reset_resp.json()
168
  except Exception as exc:
169
  print(f"[DEBUG] Reset failed: {exc}", flush=True)
170
- return
171
-
172
- for step in range(1, MAX_STEPS + 1):
173
- try:
174
- action_str = get_model_action(client, obs, history)
175
- except Exception as exc:
176
- print(f"[DEBUG] Model failed: {exc}", flush=True)
177
- action_str = heuristic_correct_sql(obs["broken_query"])
178
-
179
- try:
180
- step_resp = await http.post("/step", json={"corrected_query": action_str})
181
- step_resp.raise_for_status()
182
- result = step_resp.json()
183
- except Exception as exc:
184
- print(f"[DEBUG] Step failed: {exc}", flush=True)
185
- break
186
-
187
- obs = result["observation"]
188
- reward = float(result["reward"])
189
- done = bool(result["done"])
190
- error = result.get("info", {}).get("error")
191
-
192
- rewards.append(reward)
193
- steps_taken = step
194
- history.append(f"Step {step}: attempt={action_str!r} reward={reward:+.2f}")
195
-
196
- log_step(step, action_str, reward, done, error)
197
-
198
- if done:
199
- break
200
-
201
- score = min(max(sum(rewards) / len(rewards) if rewards else 0.0, 0.0), 1.0)
202
- success = score >= SUCCESS_SCORE_THRESHOLD
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
 
204
  except Exception as exc:
205
- print(f"[DEBUG] Episode error: {exc}", flush=True)
 
206
 
207
  finally:
 
208
  if http is not None:
209
  try:
210
  await http.aclose()
211
  except Exception as exc:
212
  print(f"[DEBUG] HTTP close error: {exc}", flush=True)
 
213
  log_end(success, steps_taken, score, rewards)
214
 
215
 
 
 
 
 
216
  async def main() -> None:
 
 
 
 
 
217
  try:
218
  difficulties = (
219
- (TASK_NAME,) if TASK_NAME in {"easy", "medium", "hard"} else ("easy", "medium", "hard")
 
 
220
  )
221
  for difficulty in difficulties:
222
  await run_task(difficulty)
223
- print("", flush=True)
224
  except Exception as exc:
225
- print(f"[DEBUG] Main error: {exc}", flush=True)
226
 
227
 
228
  if __name__ == "__main__":
229
  try:
230
  asyncio.run(main())
 
 
231
  except Exception as exc:
232
  print(f"[DEBUG] Fatal error: {exc}", flush=True)
233
  finally:
 
19
  import re
20
 
21
  import httpx
22
+
23
  try:
24
  from openai import OpenAI
25
  except Exception:
 
35
  SUCCESS_SCORE_THRESHOLD = 0.5
36
 
37
 
38
+ # ---------------------------------------------------------------------------
39
+ # Logging helpers — must match the spec format exactly
40
+ # ---------------------------------------------------------------------------
41
+
42
  def log_start(task: str, env: str, model: str) -> None:
43
  print(f"[START] task={task} env={env} model={model}", flush=True)
44
 
 
52
  ) -> None:
53
  err = error if error else "null"
54
  done_val = str(done).lower()
55
+ # Collapse newlines so the entire step fits on one line (spec requirement)
56
  action_clean = action.replace("\n", " ").replace("\r", "").strip()
57
  print(
58
  f"[STEP] step={step} action={action_clean} "
 
62
 
63
 
64
  def log_end(success: bool, steps: int, score: float, rewards: List[float]) -> None:
65
+ rewards_str = ",".join(f"{r:.2f}" for r in rewards) if rewards else ""
66
  print(
67
  f"[END] success={str(success).lower()} steps={steps} "
68
  f"score={score:.3f} rewards={rewards_str}",
 
70
  )
71
 
72
 
73
+ # ---------------------------------------------------------------------------
74
+ # LLM / heuristic helpers
75
+ # ---------------------------------------------------------------------------
76
+
77
  SYSTEM_PROMPT = textwrap.dedent(
78
  """
79
  You are an expert SQL debugger.
 
104
 
105
 
106
  def heuristic_correct_sql(query: str) -> str:
107
+ """Deterministic fallback when the LLM is unavailable."""
108
  corrected = query
109
  for broken, fixed in SQL_REPLACEMENTS.items():
110
+ corrected = re.sub(
111
+ rf"\b{re.escape(broken)}\b", fixed, corrected, flags=re.IGNORECASE
112
+ )
113
  return corrected.strip()
114
 
115
 
116
+ def get_model_action(
117
+ client: Optional["OpenAI"], obs: dict, history: List[str]
118
+ ) -> str:
119
+ """Return a corrected SQL string. Falls back to heuristic on any failure."""
120
+ heuristic = heuristic_correct_sql(obs.get("broken_query", ""))
121
+
122
  if client is None:
123
  return heuristic
124
 
 
126
  user_prompt = textwrap.dedent(
127
  f"""
128
  Broken SQL query:
129
+ {obs.get("broken_query", "")}
130
 
131
  Schema context: {obs.get("schema_context") or "Not provided"}
132
  Error hint: {obs.get("error_hint") or "None"}
 
158
  return heuristic
159
 
160
 
161
+ # ---------------------------------------------------------------------------
162
+ # Episode runner
163
+ # ---------------------------------------------------------------------------
164
+
165
  async def run_task(task_name: str) -> None:
166
+ """
167
+ Run one full episode for `task_name`.
 
 
 
 
168
 
169
+ The [END] log line is ALWAYS emitted via the finally block, even if an
170
+ exception occurs mid-episode or the reset call fails. This is required
171
+ by the hackathon spec to avoid disqualification.
172
+ """
173
+ # Initialise all accumulators BEFORE the try so finally can always read them
174
  rewards: List[float] = []
175
  history: List[str] = []
176
  steps_taken = 0
177
  score = 0.0
178
  success = False
179
 
180
+ # Build LLM client (best-effort; None means heuristic-only mode)
181
+ client = None
182
+ if OpenAI is not None and API_KEY not in {"", "dummy"}:
183
+ try:
184
+ client = OpenAI(base_url=API_BASE_URL, api_key=API_KEY)
185
+ except Exception as exc:
186
+ print(f"[DEBUG] OpenAI client init failed: {exc}", flush=True)
187
+
188
  log_start(task_name, BENCHMARK, MODEL_NAME)
189
 
190
+ http: Optional[httpx.AsyncClient] = None
191
  try:
192
  http = httpx.AsyncClient(base_url=ENV_URL, timeout=60.0)
193
 
194
+ # --- reset ---------------------------------------------------------
195
+ reset_failed = False
196
+ obs: dict = {}
197
  try:
198
  reset_resp = await http.post("/reset", json={"difficulty": task_name})
199
  reset_resp.raise_for_status()
200
  obs = reset_resp.json()
201
  except Exception as exc:
202
  print(f"[DEBUG] Reset failed: {exc}", flush=True)
203
+ # Do NOT return here — fall through to finally so [END] is always logged
204
+ reset_failed = True
205
+
206
+ if not reset_failed:
207
+ # --- step loop -------------------------------------------------
208
+ for step in range(1, MAX_STEPS + 1):
209
+ # Get action (never raises heuristic is the ultimate fallback)
210
+ try:
211
+ action_str = get_model_action(client, obs, history)
212
+ except Exception as exc:
213
+ print(f"[DEBUG] Model action failed: {exc}", flush=True)
214
+ action_str = heuristic_correct_sql(obs.get("broken_query", ""))
215
+
216
+ # Submit action to environment
217
+ try:
218
+ step_resp = await http.post(
219
+ "/step", json={"corrected_query": action_str}
220
+ )
221
+ step_resp.raise_for_status()
222
+ result = step_resp.json()
223
+ except Exception as exc:
224
+ print(f"[DEBUG] Step {step} request failed: {exc}", flush=True)
225
+ # Treat as a 0-reward terminal step so episode ends cleanly
226
+ rewards.append(0.0)
227
+ steps_taken = step
228
+ log_step(step, action_str, 0.0, True, str(exc))
229
+ break
230
+
231
+ obs = result.get("observation", obs)
232
+ reward = float(result.get("reward", 0.0))
233
+ done = bool(result.get("done", False))
234
+ info = result.get("info")
235
+ error = info.get("error") if isinstance(info, dict) else None
236
+
237
+ rewards.append(reward)
238
+ steps_taken = step
239
+ history.append(
240
+ f"Step {step}: attempt={action_str!r} reward={reward:+.2f}"
241
+ )
242
+
243
+ log_step(step, action_str, reward, done, error)
244
+
245
+ if done:
246
+ break
247
+
248
+ # Score = average reward across all steps, clamped to [0, 1]
249
+ if rewards:
250
+ score = min(max(sum(rewards) / len(rewards), 0.0), 1.0)
251
+ success = score >= SUCCESS_SCORE_THRESHOLD
252
 
253
  except Exception as exc:
254
+ # Catch-all for any unexpected error in the episode body
255
+ print(f"[DEBUG] Unhandled episode error: {exc}", flush=True)
256
 
257
  finally:
258
+ # Always close the HTTP client
259
  if http is not None:
260
  try:
261
  await http.aclose()
262
  except Exception as exc:
263
  print(f"[DEBUG] HTTP close error: {exc}", flush=True)
264
+ # [END] MUST always be emitted — even after reset failure or exception
265
  log_end(success, steps_taken, score, rewards)
266
 
267
 
268
+ # ---------------------------------------------------------------------------
269
+ # Entry point
270
+ # ---------------------------------------------------------------------------
271
+
272
  async def main() -> None:
273
+ """
274
+ Run tasks according to SQL_ENV_TASK.
275
+ If SQL_ENV_TASK is a single valid difficulty, run only that task.
276
+ Otherwise run all three in sequence so all 3 tasks produce scores.
277
+ """
278
  try:
279
  difficulties = (
280
+ (TASK_NAME,)
281
+ if TASK_NAME in {"easy", "medium", "hard"}
282
+ else ("easy", "medium", "hard")
283
  )
284
  for difficulty in difficulties:
285
  await run_task(difficulty)
286
+ print("", flush=True) # blank line separator between tasks
287
  except Exception as exc:
288
+ print(f"[DEBUG] Main loop error: {exc}", flush=True)
289
 
290
 
291
  if __name__ == "__main__":
292
  try:
293
  asyncio.run(main())
294
+ except KeyboardInterrupt:
295
+ pass
296
  except Exception as exc:
297
  print(f"[DEBUG] Fatal error: {exc}", flush=True)
298
  finally:
openenv.yaml CHANGED
@@ -73,4 +73,5 @@ tasks:
73
  endpoints:
74
  reset: POST /reset
75
  step: POST /step
76
- state: POST /state
 
 
73
  endpoints:
74
  reset: POST /reset
75
  step: POST /step
76
+ state: GET /state
77
+ health: GET /health
server/app.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from server import app
2
+ import uvicorn
3
+
4
+ def main():
5
+ uvicorn.run(app, host="0.0.0.0", port=7860)
6
+
7
+ if __name__ == "__main__":
8
+ main()