Prithvigg commited on
Commit
d151777
Β·
verified Β·
1 Parent(s): cf6fec1

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. inference.py +127 -89
inference.py CHANGED
@@ -7,8 +7,13 @@ MANDATORY env vars:
7
  HF_TOKEN Your Hugging Face / API key
8
 
9
  Optional env vars:
10
- ENV_URL QueryForge environment server URL (default: http://localhost:8000)
11
  ANTHROPIC_API_KEY Enables AI judge for scores up to 1.0 (default: deterministic mode)
 
 
 
 
 
12
  """
13
 
14
  import os
@@ -31,9 +36,10 @@ API_KEY = os.getenv("HF_TOKEN") or os.getenv("API_KEY")
31
  MODEL_NAME = os.getenv("MODEL_NAME")
32
  ENV_URL = os.getenv("ENV_URL", "https://prithvigg-queryforge.hf.space")
33
 
34
- MAX_STEPS = 5 # max attempts per task (overridden by task's own max_steps)
35
- TEMPERATURE = 0.2
36
- MAX_TOKENS = 512
 
37
 
38
  TASK_IDS = [
39
  "task_easy_syntax",
@@ -58,20 +64,44 @@ SYSTEM_PROMPT = textwrap.dedent("""
58
  - If you receive grading feedback on a previous attempt, use it to improve.
59
  """).strip()
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  # ── SQL extraction ─────────────────────────────────────────────────────────────
62
 
63
  _SQL_BLOCK = re.compile(r"```(?:sql)?\s*(.*?)```", re.DOTALL | re.IGNORECASE)
64
 
65
 
66
  def extract_sql(text: str) -> str:
67
- """Pull the first SQL code block from the model response."""
68
  match = _SQL_BLOCK.search(text)
69
  if match:
70
  return match.group(1).strip()
71
  return text.strip()
72
 
73
 
74
- # ── Formatting ────────────────────────────────────────────────────────────────
75
 
76
  def score_bar(score: float, width: int = 25) -> str:
77
  filled = int(score * width)
@@ -85,15 +115,14 @@ def hr(char="═", width=70):
85
  # ── Per-task agent loop ────────────────────────────────────────────────────────
86
 
87
  def run_task(task_id: str, llm: OpenAI, env_client) -> dict:
88
- """
89
- Run one episode for a single task.
90
- Returns dict with task_id, task_title, task_level, best_score, attempts, done.
91
- """
92
  result = env_client.reset(task_id=task_id)
93
- obs = result.observation
 
 
94
 
95
  if result.done:
96
  print(f" ERROR loading task: {obs.feedback}")
 
97
  return {"task_id": task_id, "best_score": 0.0, "attempts": 0, "done": False}
98
 
99
  print(f"\n Task : {obs.task_title} [{obs.task_level}]")
@@ -109,89 +138,100 @@ def run_task(task_id: str, llm: OpenAI, env_client) -> dict:
109
  },
110
  ]
111
 
112
- step = 0
113
- while not result.done:
114
- step += 1
115
-
116
- try:
117
- completion = llm.chat.completions.create(
118
- model=MODEL_NAME,
119
- messages=messages,
120
- temperature=TEMPERATURE,
121
- max_tokens=MAX_TOKENS,
122
- stream=False,
123
- )
124
- response_text = completion.choices[0].message.content or ""
125
- except Exception as exc:
126
- print(f" LLM call failed at step {step}: {exc}")
127
- break
128
-
129
- sql = extract_sql(response_text)
130
-
131
- # ── Print generated SQL ───────────────────────────────────────────────
132
- print(f"\n β”Œβ”€ Step {step} Β· SQL submitted {'─' * (50 - len(str(step)))}")
133
- for line in sql.splitlines():
134
- print(f" β”‚ {line}")
135
- print(f" β””{'─' * 56}")
136
-
137
- result = env_client.step(SQLAction(sql=sql))
138
- obs = result.observation
139
-
140
- score = result.reward or 0.0
141
- done_marker = " βœ“ DONE" if result.done else ""
142
- print(f" Score : {score_bar(score)}{done_marker}")
143
-
144
- if not obs.syntax_valid:
145
- print(f" βœ— Syntax error β€” query could not be parsed")
146
- elif not obs.execution_success:
147
- print(f" βœ— Execution failed β€” {(obs.execution_error or '')[:80]}")
148
- else:
149
- print(f" βœ“ Executed Β· rows returned: {obs.rows_returned}")
150
-
151
- if result.done:
152
- break
153
-
154
- # ── Why are we going to the next step? ───────────────────────────────
155
- print(f"\n ↻ Retrying β€” score {score:.3f} below threshold")
156
- if obs.feedback:
157
- # Split the feedback into its tagged sections for readable multi-line output
158
- for part in obs.feedback.split(" "):
159
- part = part.strip()
160
- if part:
161
- print(f" {part}")
162
- if obs.hint:
163
- print(f" Hint : {obs.hint[:120]}")
164
-
165
- # Feed grading result back to the model for the next attempt
166
- messages.append({"role": "assistant", "content": response_text})
167
- messages.append({
168
- "role": "user",
169
- "content": (
170
- f"Your query scored {result.reward:.3f}.\n\n"
171
- f"Feedback: {obs.feedback}\n\n"
172
- f"Hint: {obs.hint}\n\n"
173
- "Please submit an improved SQL query."
174
- ),
175
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
  return {
178
- "task_id": task_id,
179
  "task_title": obs.task_title,
180
  "task_level": obs.task_level,
181
  "best_score": obs.best_score,
182
- "attempts": obs.attempt,
183
- "done": result.done,
184
  }
185
 
186
 
187
  # ── Main ──────────────────────────────────────���────────────────────────────────
188
 
189
  def main() -> None:
190
- # ── Validate required config ──────────────────────────────────────────────
191
  if not MODEL_NAME:
192
  print("ERROR: MODEL_NAME env var is not set.")
193
  sys.exit(1)
194
-
195
  if not API_KEY:
196
  print("ERROR: HF_TOKEN (or API_KEY) is not set.")
197
  sys.exit(1)
@@ -206,14 +246,12 @@ def main() -> None:
206
  hr()
207
 
208
  results = []
209
-
210
  with QueryforgeEnv(base_url=ENV_URL).sync() as env_client:
211
  for task_id in TASK_IDS:
212
  print(f"\n{'─' * 70}")
213
- result = run_task(task_id, llm, env_client)
214
- results.append(result)
215
 
216
- # ── Results table ─────────────────────────────────────────────────────────
217
  print(f"\n{'═' * 70}")
218
  print(" RESULTS")
219
  print(f" Model: {MODEL_NAME}")
@@ -223,11 +261,11 @@ def main() -> None:
223
 
224
  total = 0.0
225
  for r in results:
226
- title = r.get("task_title", r["task_id"])[:27]
227
- level = r.get("task_level", "?")
228
- steps = r.get("attempts", "?")
229
- score = r["best_score"]
230
- total += score
231
  print(f" {title:<28} {level:<8} {steps:>5} {score_bar(score)}")
232
 
233
  avg = total / len(results) if results else 0.0
 
7
  HF_TOKEN Your Hugging Face / API key
8
 
9
  Optional env vars:
10
+ ENV_URL QueryForge environment server URL (default: live HF Space)
11
  ANTHROPIC_API_KEY Enables AI judge for scores up to 1.0 (default: deterministic mode)
12
+
13
+ STDOUT FORMAT (required by evaluator):
14
+ [START] task=<task_id> env=queryforge model=<model_name>
15
+ [STEP] step=<n> action=<sql_oneline> reward=<0.00> done=<true|false> error=<msg|null>
16
+ [END] success=<true|false> steps=<n> score=<0.000> rewards=<r1,r2,...>
17
  """
18
 
19
  import os
 
36
  MODEL_NAME = os.getenv("MODEL_NAME")
37
  ENV_URL = os.getenv("ENV_URL", "https://prithvigg-queryforge.hf.space")
38
 
39
+ MAX_STEPS = 5
40
+ TEMPERATURE = 0.2
41
+ MAX_TOKENS = 512
42
+ SUCCESS_SCORE_THRESHOLD = 0.9
43
 
44
  TASK_IDS = [
45
  "task_easy_syntax",
 
64
  - If you receive grading feedback on a previous attempt, use it to improve.
65
  """).strip()
66
 
67
+ # ── Structured log helpers (evaluator-required format) ────────────────────────
68
+
69
+ def log_start(task: str, model: str) -> None:
70
+ print(f"[START] task={task} env=queryforge model={model}", flush=True)
71
+
72
+
73
+ def log_step(step: int, action: str, reward: float, done: bool, error: Optional[str]) -> None:
74
+ # SQL may contain newlines β€” collapse to single line (spec: no newlines within a line)
75
+ action_oneline = " ".join(action.split())
76
+ error_val = error if error else "null"
77
+ print(
78
+ f"[STEP] step={step} action={action_oneline} reward={reward:.2f}"
79
+ f" done={str(done).lower()} error={error_val}",
80
+ flush=True,
81
+ )
82
+
83
+
84
+ def log_end(success: bool, steps: int, score: float, rewards: List[float]) -> None:
85
+ rewards_str = ",".join(f"{r:.2f}" for r in rewards)
86
+ print(
87
+ f"[END] success={str(success).lower()} steps={steps}"
88
+ f" score={score:.3f} rewards={rewards_str}",
89
+ flush=True,
90
+ )
91
+
92
  # ── SQL extraction ─────────────────────────────────────────────────────────────
93
 
94
  _SQL_BLOCK = re.compile(r"```(?:sql)?\s*(.*?)```", re.DOTALL | re.IGNORECASE)
95
 
96
 
97
  def extract_sql(text: str) -> str:
 
98
  match = _SQL_BLOCK.search(text)
99
  if match:
100
  return match.group(1).strip()
101
  return text.strip()
102
 
103
 
104
+ # ── Formatting helpers (human-readable output) ────────────────────────────────
105
 
106
  def score_bar(score: float, width: int = 25) -> str:
107
  filled = int(score * width)
 
115
  # ── Per-task agent loop ────────────────────────────────────────────────────────
116
 
117
  def run_task(task_id: str, llm: OpenAI, env_client) -> dict:
 
 
 
 
118
  result = env_client.reset(task_id=task_id)
119
+ obs = result.observation
120
+
121
+ log_start(task=task_id, model=MODEL_NAME)
122
 
123
  if result.done:
124
  print(f" ERROR loading task: {obs.feedback}")
125
+ log_end(success=False, steps=0, score=0.0, rewards=[])
126
  return {"task_id": task_id, "best_score": 0.0, "attempts": 0, "done": False}
127
 
128
  print(f"\n Task : {obs.task_title} [{obs.task_level}]")
 
138
  },
139
  ]
140
 
141
+ step = 0
142
+ rewards: List[float] = []
143
+ success = False
144
+
145
+ try:
146
+ while not result.done:
147
+ step += 1
148
+
149
+ try:
150
+ completion = llm.chat.completions.create(
151
+ model=MODEL_NAME,
152
+ messages=messages,
153
+ temperature=TEMPERATURE,
154
+ max_tokens=MAX_TOKENS,
155
+ stream=False,
156
+ )
157
+ response_text = completion.choices[0].message.content or ""
158
+ except Exception as exc:
159
+ print(f" LLM call failed at step {step}: {exc}")
160
+ break
161
+
162
+ sql = extract_sql(response_text)
163
+
164
+ print(f"\n β”Œβ”€ Step {step} Β· SQL submitted {'─' * (50 - len(str(step)))}")
165
+ for line in sql.splitlines():
166
+ print(f" β”‚ {line}")
167
+ print(f" β””{'─' * 56}")
168
+
169
+ result = env_client.step(SQLAction(sql=sql))
170
+ obs = result.observation
171
+
172
+ reward = result.reward or 0.0
173
+ rewards.append(reward)
174
+
175
+ # Determine error string for [STEP] log
176
+ if not obs.syntax_valid:
177
+ step_error = "syntax_error"
178
+ print(f" βœ— Syntax error β€” query could not be parsed")
179
+ elif not obs.execution_success:
180
+ step_error = (obs.execution_error or "execution_error")[:120]
181
+ print(f" βœ— Execution failed β€” {step_error[:80]}")
182
+ else:
183
+ step_error = None
184
+ print(f" βœ“ Executed Β· rows returned: {obs.rows_returned}")
185
+
186
+ done_marker = " βœ“ DONE" if result.done else ""
187
+ print(f" Score : {score_bar(reward)}{done_marker}")
188
+
189
+ log_step(step=step, action=sql, reward=reward, done=result.done, error=step_error)
190
+
191
+ if result.done:
192
+ break
193
+
194
+ print(f"\n ↻ Retrying β€” score {reward:.3f} below threshold")
195
+ if obs.feedback:
196
+ for part in obs.feedback.split(" "):
197
+ part = part.strip()
198
+ if part:
199
+ print(f" {part}")
200
+ if obs.hint:
201
+ print(f" Hint : {obs.hint[:120]}")
202
+
203
+ messages.append({"role": "assistant", "content": response_text})
204
+ messages.append({
205
+ "role": "user",
206
+ "content": (
207
+ f"Your query scored {reward:.3f}.\n\n"
208
+ f"Feedback: {obs.feedback}\n\n"
209
+ f"Hint: {obs.hint}\n\n"
210
+ "Please submit an improved SQL query."
211
+ ),
212
+ })
213
+
214
+ success = obs.best_score >= SUCCESS_SCORE_THRESHOLD
215
+
216
+ finally:
217
+ log_end(success=success, steps=step, score=obs.best_score, rewards=rewards)
218
 
219
  return {
220
+ "task_id": task_id,
221
  "task_title": obs.task_title,
222
  "task_level": obs.task_level,
223
  "best_score": obs.best_score,
224
+ "attempts": obs.attempt,
225
+ "done": result.done,
226
  }
227
 
228
 
229
  # ── Main ──────────────────────────────────────���────────────────────────────────
230
 
231
  def main() -> None:
 
232
  if not MODEL_NAME:
233
  print("ERROR: MODEL_NAME env var is not set.")
234
  sys.exit(1)
 
235
  if not API_KEY:
236
  print("ERROR: HF_TOKEN (or API_KEY) is not set.")
237
  sys.exit(1)
 
246
  hr()
247
 
248
  results = []
 
249
  with QueryforgeEnv(base_url=ENV_URL).sync() as env_client:
250
  for task_id in TASK_IDS:
251
  print(f"\n{'─' * 70}")
252
+ results.append(run_task(task_id, llm, env_client))
 
253
 
254
+ # ── Results summary ───────────────────────────────────────────────────────
255
  print(f"\n{'═' * 70}")
256
  print(" RESULTS")
257
  print(f" Model: {MODEL_NAME}")
 
261
 
262
  total = 0.0
263
  for r in results:
264
+ title = r.get("task_title", r["task_id"])[:27]
265
+ level = r.get("task_level", "?")
266
+ steps = r.get("attempts", "?")
267
+ score = r["best_score"]
268
+ total += score
269
  print(f" {title:<28} {level:<8} {steps:>5} {score_bar(score)}")
270
 
271
  avg = total / len(results) if results else 0.0