Spaces:
Sleeping
Sleeping
Commit Β·
b4cf41e
1
Parent(s): 95b11e6
new fixed
Browse files- env/graders.py +21 -26
env/graders.py
CHANGED
|
@@ -20,10 +20,10 @@ def _safe_get(payload: dict, key: str, default=None):
|
|
| 20 |
def _score_explanation(explanation: str) -> float:
|
| 21 |
"""Score explanation quality by length and keyword richness."""
|
| 22 |
if not explanation or not isinstance(explanation, str):
|
| 23 |
-
return 0.
|
| 24 |
explanation = explanation.strip()
|
| 25 |
if len(explanation) < 10:
|
| 26 |
-
return 0.
|
| 27 |
if len(explanation) < 30:
|
| 28 |
return 0.05
|
| 29 |
if len(explanation) < 80:
|
|
@@ -38,7 +38,7 @@ def _score_confidence(confidence) -> float:
|
|
| 38 |
return 0.05
|
| 39 |
except (TypeError, ValueError):
|
| 40 |
pass
|
| 41 |
-
return 0.
|
| 42 |
|
| 43 |
def _query_similarity(submitted: str, expected: str) -> float:
|
| 44 |
"""
|
|
@@ -51,14 +51,14 @@ def _query_similarity(submitted: str, expected: str) -> float:
|
|
| 51 |
|
| 52 |
# Exact match after normalization
|
| 53 |
if s == e:
|
| 54 |
-
return
|
| 55 |
|
| 56 |
# Tokenize and check keyword overlap
|
| 57 |
s_tokens = set(s.split())
|
| 58 |
e_tokens = set(e.split())
|
| 59 |
|
| 60 |
if not e_tokens:
|
| 61 |
-
return 0.
|
| 62 |
|
| 63 |
overlap = len(s_tokens & e_tokens) / len(e_tokens)
|
| 64 |
|
|
@@ -68,7 +68,8 @@ def _query_similarity(submitted: str, expected: str) -> float:
|
|
| 68 |
critical_score = critical_found / len(critical_keywords) if critical_keywords else 0.0
|
| 69 |
|
| 70 |
# Weighted combination
|
| 71 |
-
|
|
|
|
| 72 |
|
| 73 |
def _extract_critical_keywords(query: str) -> list[str]:
|
| 74 |
"""Extract SQL keywords that are critical to correctness."""
|
|
@@ -90,7 +91,7 @@ def _extract_critical_keywords(query: str) -> list[str]:
|
|
| 90 |
def _score_error_type(submitted_type: str, expected_type: str) -> float:
|
| 91 |
"""Score for correctly identifying the error type."""
|
| 92 |
if not submitted_type:
|
| 93 |
-
return 0.
|
| 94 |
s = submitted_type.strip().lower()
|
| 95 |
e = expected_type.strip().lower()
|
| 96 |
if s == e:
|
|
@@ -104,12 +105,12 @@ def _score_error_type(submitted_type: str, expected_type: str) -> float:
|
|
| 104 |
for canonical, aliases in related.items():
|
| 105 |
if e == canonical and any(alias in s for alias in aliases):
|
| 106 |
return 0.05
|
| 107 |
-
return 0.
|
| 108 |
|
| 109 |
def _score_error_location(submitted_location: str, expected_location: str) -> float:
|
| 110 |
"""Score for correctly identifying WHERE in the query the error is."""
|
| 111 |
if not submitted_location or not expected_location:
|
| 112 |
-
return 0.
|
| 113 |
s = submitted_location.strip().lower()
|
| 114 |
e = expected_location.strip().lower()
|
| 115 |
if s == e:
|
|
@@ -118,7 +119,7 @@ def _score_error_location(submitted_location: str, expected_location: str) -> fl
|
|
| 118 |
e_words = set(e.split())
|
| 119 |
s_words = set(s.split())
|
| 120 |
overlap = len(e_words & s_words) / len(e_words) if e_words else 0.0
|
| 121 |
-
return round(overlap * 0.10, 4)
|
| 122 |
|
| 123 |
|
| 124 |
# GRADERS PER DIFFICULTY
|
|
@@ -210,7 +211,7 @@ def grade_medium(action: Action, ground_truth: dict) -> tuple[float, dict, str]:
|
|
| 210 |
DETERMINISTIC: same input always returns same score.
|
| 211 |
"""
|
| 212 |
if action is None or action.payload is None:
|
| 213 |
-
return 0.
|
| 214 |
|
| 215 |
payload = action.payload
|
| 216 |
score = 0.0
|
|
@@ -255,7 +256,7 @@ def grade_medium(action: Action, ground_truth: dict) -> tuple[float, dict, str]:
|
|
| 255 |
keywords_to_check = logic_keywords.get(error_type, logic_keywords["logic"])
|
| 256 |
expl_lower = explanation.lower()
|
| 257 |
keyword_hits = sum(1 for kw in keywords_to_check if kw in expl_lower)
|
| 258 |
-
logic_score = min(keyword_hits * 0.05, 0.20)
|
| 259 |
score += logic_score
|
| 260 |
breakdown["logic_flaw_identification"] = round(logic_score, 4)
|
| 261 |
if logic_score > 0:
|
|
@@ -286,7 +287,7 @@ def grade_medium(action: Action, ground_truth: dict) -> tuple[float, dict, str]:
|
|
| 286 |
breakdown["impact_analysis"] = 0.05
|
| 287 |
feedback_parts.append("Impact analysis provided.")
|
| 288 |
else:
|
| 289 |
-
breakdown["impact_analysis"] = 0.
|
| 290 |
|
| 291 |
final_score = round(max(min(score, 0.999), 0.001), 4)
|
| 292 |
feedback = " ".join(feedback_parts) if feedback_parts else "No valid response provided."
|
|
@@ -301,13 +302,7 @@ def grade_hard(action: Action, ground_truth: dict) -> tuple[float, dict, str]:
|
|
| 301 |
DETERMINISTIC: same input always returns same score.
|
| 302 |
"""
|
| 303 |
if action is None or action.payload is None:
|
| 304 |
-
return 0.
|
| 305 |
-
|
| 306 |
-
payload = action.payload
|
| 307 |
-
score = 0.0
|
| 308 |
-
breakdown = {}
|
| 309 |
-
feedback_parts = []
|
| 310 |
-
|
| 311 |
rubric = ground_truth.get("scoring_rubric", {})
|
| 312 |
|
| 313 |
# ββ 1. Query correctness (0.30) ββββββββββββββββββββββββββββββ
|
|
@@ -353,11 +348,11 @@ def grade_hard(action: Action, ground_truth: dict) -> tuple[float, dict, str]:
|
|
| 353 |
"window function": ["window function", "partition by", "row_number", "subquery filter", "where clause window"]
|
| 354 |
}
|
| 355 |
|
| 356 |
-
concept_score = 0.
|
| 357 |
for concept, keywords in performance_concept_map.items():
|
| 358 |
if any(concept_part in issue_type for concept_part in concept.split()):
|
| 359 |
hits = sum(1 for kw in keywords if kw in combined_text)
|
| 360 |
-
concept_score = min(hits * 0.06, 0.30)
|
| 361 |
break
|
| 362 |
|
| 363 |
score += concept_score
|
|
@@ -380,7 +375,7 @@ def grade_hard(action: Action, ground_truth: dict) -> tuple[float, dict, str]:
|
|
| 380 |
breakdown["root_cause_analysis"] = 0.10
|
| 381 |
feedback_parts.append("Root cause analysis provided.")
|
| 382 |
else:
|
| 383 |
-
breakdown["root_cause_analysis"] = 0.
|
| 384 |
|
| 385 |
# ββ 5. Expected improvement (0.10) ββββββββββββββββββββββββββββ
|
| 386 |
improvement = str(_safe_get(payload, "expected_improvement", "") or "")
|
|
@@ -389,7 +384,7 @@ def grade_hard(action: Action, ground_truth: dict) -> tuple[float, dict, str]:
|
|
| 389 |
breakdown["expected_improvement"] = 0.10
|
| 390 |
feedback_parts.append("Performance improvement estimate provided.")
|
| 391 |
else:
|
| 392 |
-
breakdown["expected_improvement"] = 0.
|
| 393 |
|
| 394 |
# ββ 6. Confidence (0.05) ββββββββββββββββββββββββββββββββββββββ
|
| 395 |
confidence = _safe_get(payload, "confidence", None)
|
|
@@ -416,7 +411,7 @@ def grade(action: Action, task_id: str) -> tuple[float, dict, str]:
|
|
| 416 |
"""
|
| 417 |
# Edge case: null action
|
| 418 |
if action is None:
|
| 419 |
-
return 0.
|
| 420 |
|
| 421 |
# Edge case: unknown task
|
| 422 |
ground_truth = task_manager.get_ground_truth(task_id)
|
|
@@ -434,7 +429,7 @@ def grade(action: Action, task_id: str) -> tuple[float, dict, str]:
|
|
| 434 |
elif difficulty == "hard":
|
| 435 |
return grade_hard(action, ground_truth)
|
| 436 |
else:
|
| 437 |
-
return 0.
|
| 438 |
except Exception as e:
|
| 439 |
# Never crash β return 0.0 with error info
|
| 440 |
return 0.001, {"error": str(e)}, f"Grader error: {str(e)}"
|
|
|
|
| 20 |
def _score_explanation(explanation: str) -> float:
|
| 21 |
"""Score explanation quality by length and keyword richness."""
|
| 22 |
if not explanation or not isinstance(explanation, str):
|
| 23 |
+
return 0.001
|
| 24 |
explanation = explanation.strip()
|
| 25 |
if len(explanation) < 10:
|
| 26 |
+
return 0.001
|
| 27 |
if len(explanation) < 30:
|
| 28 |
return 0.05
|
| 29 |
if len(explanation) < 80:
|
|
|
|
| 38 |
return 0.05
|
| 39 |
except (TypeError, ValueError):
|
| 40 |
pass
|
| 41 |
+
return 0.001
|
| 42 |
|
| 43 |
def _query_similarity(submitted: str, expected: str) -> float:
|
| 44 |
"""
|
|
|
|
| 51 |
|
| 52 |
# Exact match after normalization
|
| 53 |
if s == e:
|
| 54 |
+
return 0.999
|
| 55 |
|
| 56 |
# Tokenize and check keyword overlap
|
| 57 |
s_tokens = set(s.split())
|
| 58 |
e_tokens = set(e.split())
|
| 59 |
|
| 60 |
if not e_tokens:
|
| 61 |
+
return 0.001
|
| 62 |
|
| 63 |
overlap = len(s_tokens & e_tokens) / len(e_tokens)
|
| 64 |
|
|
|
|
| 68 |
critical_score = critical_found / len(critical_keywords) if critical_keywords else 0.0
|
| 69 |
|
| 70 |
# Weighted combination
|
| 71 |
+
similarity = round((overlap * 0.4) + (critical_score * 0.6), 4)
|
| 72 |
+
return max(min(similarity, 0.999), 0.001)
|
| 73 |
|
| 74 |
def _extract_critical_keywords(query: str) -> list[str]:
|
| 75 |
"""Extract SQL keywords that are critical to correctness."""
|
|
|
|
| 91 |
def _score_error_type(submitted_type: str, expected_type: str) -> float:
|
| 92 |
"""Score for correctly identifying the error type."""
|
| 93 |
if not submitted_type:
|
| 94 |
+
return 0.001
|
| 95 |
s = submitted_type.strip().lower()
|
| 96 |
e = expected_type.strip().lower()
|
| 97 |
if s == e:
|
|
|
|
| 105 |
for canonical, aliases in related.items():
|
| 106 |
if e == canonical and any(alias in s for alias in aliases):
|
| 107 |
return 0.05
|
| 108 |
+
return 0.001
|
| 109 |
|
| 110 |
def _score_error_location(submitted_location: str, expected_location: str) -> float:
|
| 111 |
"""Score for correctly identifying WHERE in the query the error is."""
|
| 112 |
if not submitted_location or not expected_location:
|
| 113 |
+
return 0.001
|
| 114 |
s = submitted_location.strip().lower()
|
| 115 |
e = expected_location.strip().lower()
|
| 116 |
if s == e:
|
|
|
|
| 119 |
e_words = set(e.split())
|
| 120 |
s_words = set(s.split())
|
| 121 |
overlap = len(e_words & s_words) / len(e_words) if e_words else 0.0
|
| 122 |
+
return max(round(overlap * 0.10, 4), 0.001)
|
| 123 |
|
| 124 |
|
| 125 |
# GRADERS PER DIFFICULTY
|
|
|
|
| 211 |
DETERMINISTIC: same input always returns same score.
|
| 212 |
"""
|
| 213 |
if action is None or action.payload is None:
|
| 214 |
+
return 0.001, {"error": "null_action"}, "No action provided."
|
| 215 |
|
| 216 |
payload = action.payload
|
| 217 |
score = 0.0
|
|
|
|
| 256 |
keywords_to_check = logic_keywords.get(error_type, logic_keywords["logic"])
|
| 257 |
expl_lower = explanation.lower()
|
| 258 |
keyword_hits = sum(1 for kw in keywords_to_check if kw in expl_lower)
|
| 259 |
+
logic_score = max(min(keyword_hits * 0.05, 0.20), 0.001)
|
| 260 |
score += logic_score
|
| 261 |
breakdown["logic_flaw_identification"] = round(logic_score, 4)
|
| 262 |
if logic_score > 0:
|
|
|
|
| 287 |
breakdown["impact_analysis"] = 0.05
|
| 288 |
feedback_parts.append("Impact analysis provided.")
|
| 289 |
else:
|
| 290 |
+
breakdown["impact_analysis"] = 0.001
|
| 291 |
|
| 292 |
final_score = round(max(min(score, 0.999), 0.001), 4)
|
| 293 |
feedback = " ".join(feedback_parts) if feedback_parts else "No valid response provided."
|
|
|
|
| 302 |
DETERMINISTIC: same input always returns same score.
|
| 303 |
"""
|
| 304 |
if action is None or action.payload is None:
|
| 305 |
+
return 0.001, {"error": "null_action"}, "No action provided."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 306 |
rubric = ground_truth.get("scoring_rubric", {})
|
| 307 |
|
| 308 |
# ββ 1. Query correctness (0.30) ββββββββββββββββββββββββββββββ
|
|
|
|
| 348 |
"window function": ["window function", "partition by", "row_number", "subquery filter", "where clause window"]
|
| 349 |
}
|
| 350 |
|
| 351 |
+
concept_score = 0.001
|
| 352 |
for concept, keywords in performance_concept_map.items():
|
| 353 |
if any(concept_part in issue_type for concept_part in concept.split()):
|
| 354 |
hits = sum(1 for kw in keywords if kw in combined_text)
|
| 355 |
+
concept_score = max(min(hits * 0.06, 0.30), 0.001)
|
| 356 |
break
|
| 357 |
|
| 358 |
score += concept_score
|
|
|
|
| 375 |
breakdown["root_cause_analysis"] = 0.10
|
| 376 |
feedback_parts.append("Root cause analysis provided.")
|
| 377 |
else:
|
| 378 |
+
breakdown["root_cause_analysis"] = 0.001
|
| 379 |
|
| 380 |
# ββ 5. Expected improvement (0.10) ββββββββββββββββββββββββββββ
|
| 381 |
improvement = str(_safe_get(payload, "expected_improvement", "") or "")
|
|
|
|
| 384 |
breakdown["expected_improvement"] = 0.10
|
| 385 |
feedback_parts.append("Performance improvement estimate provided.")
|
| 386 |
else:
|
| 387 |
+
breakdown["expected_improvement"] = 0.001
|
| 388 |
|
| 389 |
# ββ 6. Confidence (0.05) ββββββββββββββββββββββββββββββββββββββ
|
| 390 |
confidence = _safe_get(payload, "confidence", None)
|
|
|
|
| 411 |
"""
|
| 412 |
# Edge case: null action
|
| 413 |
if action is None:
|
| 414 |
+
return 0.001, {"error": "null_action"}, "No action provided."
|
| 415 |
|
| 416 |
# Edge case: unknown task
|
| 417 |
ground_truth = task_manager.get_ground_truth(task_id)
|
|
|
|
| 429 |
elif difficulty == "hard":
|
| 430 |
return grade_hard(action, ground_truth)
|
| 431 |
else:
|
| 432 |
+
return 0.001, {"error": "unknown_difficulty"}, f"Unknown difficulty: {difficulty}"
|
| 433 |
except Exception as e:
|
| 434 |
# Never crash β return 0.0 with error info
|
| 435 |
return 0.001, {"error": str(e)}, f"Grader error: {str(e)}"
|