Files changed (1) hide show
  1. graders.py +123 -59
graders.py CHANGED
@@ -1,83 +1,147 @@
1
- import os
2
- import json
3
- import urllib.request
 
4
 
5
- SPACE_URL = os.environ.get("SPACE_URL", "http://localhost:7860")
6
 
7
- def call_reset():
8
- req = urllib.request.Request(f"{SPACE_URL}/reset", method="POST")
9
- req.add_header("Content-Type", "application/json")
10
- with urllib.request.urlopen(req, data=b"{}") as r:
11
- return json.loads(r.read())
12
-
13
- def call_step(action):
14
- payload = json.dumps({"action": action}).encode()
15
- req = urllib.request.Request(f"{SPACE_URL}/step", method="POST")
16
- req.add_header("Content-Type", "application/json")
17
- with urllib.request.urlopen(req, data=payload) as r:
18
- return json.loads(r.read())
19
 
20
  EASY_EMAILS = [
21
- {"subject": "You won $1,000,000!", "body": "Click here to claim your prize.", "label": "spam"},
22
- {"subject": "FREE iPhone giveaway", "body": "You have been selected. Claim now!", "label": "spam"},
23
- {"subject": "Meeting at 3pm today", "body": "Reminder about our team sync.", "label": "important"},
24
- {"subject": "Your invoice is ready", "body": "Your monthly invoice is attached.", "label": "important"},
25
- {"subject": "50% off this weekend", "body": "Flash sale on all items this weekend.", "label": "promotion"},
26
  ]
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  MEDIUM_EMAILS = [
29
- {"subject": "Exclusive member offer", "body": "As a valued member enjoy 20% off.", "label": "promotion"},
30
- {"subject": "Action required: password expiry", "body": "Your password expires in 3 days.", "label": "important"},
31
- {"subject": "Urgent: verify your account", "body": "Your account will be suspended click to verify.", "label": "spam"},
32
  {"subject": "New arrivals just for you", "body": "Check out our latest summer collection.", "label": "promotion"},
33
- {"subject": "RE: Project update", "body": "Thanks for the update lets connect tomorrow.", "label": "important"},
34
- {"subject": "Congratulations you are selected", "body": "Send your details to collect reward.", "label": "spam"},
 
 
35
  ]
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  HARD_EMAILS = [
38
  {"subject": "Your account statement", "body": "Your monthly statement from XYZ Bank is ready.", "label": "important"},
39
- {"subject": "Limited time upgrade your plan", "body": "Switch to premium and save 30% this month.", "label": "promotion"},
40
- {"subject": "Security alert", "body": "A new login was detected from unknown device.", "label": "important"},
41
  {"subject": "You have unclaimed rewards", "body": "Collect your loyalty points before they expire.", "label": "promotion"},
42
- {"subject": "Final notice payment overdue", "body": "Send money now to avoid service interruption.", "label": "spam"},
43
- {"subject": "Team offsite next Friday", "body": "Please confirm attendance for the offsite.", "label": "important"},
44
- {"subject": "Claim your free trial", "body": "Start your 30 day free trial no credit card needed.", "label": "promotion"},
45
- {"subject": "You have been pre-approved", "body": "You qualify for a loan apply now.", "label": "spam"},
46
  ]
47
 
48
- def baseline_agent(email):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  text = (email.get("subject", "") + " " + email.get("body", "")).lower()
50
- spam_kw = ["won", "free", "prize", "claim", "urgent", "congratulations", "selected", "suspended", "overdue", "approved"]
51
- promo_kw = ["off", "sale", "deal", "discount", "offer", "save", "upgrade", "trial", "rewards", "loyalty"]
52
- if sum(1 for k in spam_kw if k in text) >= 2: return "spam"
53
- if sum(1 for k in promo_kw if k in text) >= 1: return "promotion"
 
 
 
 
54
  return "important"
55
 
56
- def clamp(score):
57
- """Ensure score is strictly between 0 and 1."""
58
- return max(0.01, min(0.99, score))
59
 
60
- def grade_task(emails, task_name):
61
- correct = 0
62
- for email in emails:
63
- prediction = baseline_agent(email)
64
- if prediction == email["label"]:
65
- correct += 1
66
- raw_score = correct / len(emails)
67
- score = clamp(round(raw_score, 2))
68
- print(f"[GRADER] task={task_name} score={score} correct={correct}/{len(emails)}", flush=True)
69
- return {"task": task_name, "score": score, "correct": correct, "total": len(emails)}
70
 
71
  def run_all_graders(agent_fn=None):
 
 
 
72
  results = []
73
- results.append(grade_task(EASY_EMAILS, "easy"))
74
- results.append(grade_task(MEDIUM_EMAILS, "medium"))
75
- results.append(grade_task(HARD_EMAILS, "hard"))
76
- avg = clamp(round(sum(r["score"] for r in results) / len(results), 4))
77
- return {"tasks": results, "average_score": avg, "all_passed": True}
 
 
 
 
 
 
 
 
 
 
78
 
79
  if __name__ == "__main__":
80
- r = run_all_graders()
81
- for t in r["tasks"]:
82
- print(f"{t['task']}: {t['score']}")
83
- print(f"Average: {r['average_score']}")
 
 
1
+ """
2
+ graders.py — Email Sorting OpenEnv
3
+ 3 grader tasks: easy, medium, hard. Scores 0.0–1.0.
4
+ """
5
 
6
+ from env import EMAILS
7
 
8
+ # ============================================
9
+ # TASK 1 — EASY: Obvious spam detection
10
+ # ============================================
 
 
 
 
 
 
 
 
 
11
 
12
  EASY_EMAILS = [
13
+ {"subject": "You won $1,000,000!", "body": "Click here to claim your prize now.", "label": "spam"},
14
+ {"subject": "FREE iPhone giveaway", "body": "You have been selected. Claim before midnight!", "label": "spam"},
15
+ {"subject": "Congratulations! You're a winner", "body": "Send your details to collect your reward.", "label": "spam"},
16
+ {"subject": "Meeting at 3pm today", "body": "Hi, reminder about our team sync at 3pm.", "label": "important"},
17
+ {"subject": "Your invoice is ready", "body": "Please find your monthly invoice attached.", "label": "important"},
18
  ]
19
 
20
+ def grade_easy_sorting(agent_fn=None):
21
+ """
22
+ Easy task: classify obvious spam vs important emails.
23
+ agent_fn(email) -> 'spam' | 'important' | 'promotion'
24
+ Returns score strictly in (0.0, 1.0)
25
+ """
26
+ if agent_fn is None:
27
+ agent_fn = baseline_agent
28
+ correct = 0
29
+ for email in EASY_EMAILS:
30
+ prediction = agent_fn(email)
31
+ if prediction == email["label"]:
32
+ correct += 1
33
+ raw = correct / len(EASY_EMAILS)
34
+ score = round(min(0.99, max(0.01, raw)), 2)
35
+ return {"task": "easy_sorting", "correct": correct, "total": len(EASY_EMAILS), "score": score}
36
+
37
+
38
+ # ============================================
39
+ # TASK 2 — MEDIUM: Spam + Promotion + Important
40
+ # ============================================
41
+
42
  MEDIUM_EMAILS = [
43
+ {"subject": "50% off this weekend only!", "body": "Flash sale on all items. Use code SAVE50.", "label": "promotion"},
 
 
44
  {"subject": "New arrivals just for you", "body": "Check out our latest summer collection.", "label": "promotion"},
45
+ {"subject": "Exclusive member offer inside", "body": "As a valued member, enjoy 20% off.", "label": "promotion"},
46
+ {"subject": "Action required: password expiry", "body": "Your password expires in 3 days. Reset it now.", "label": "important"},
47
+ {"subject": "RE: Project update", "body": "Thanks for the update. Let's connect tomorrow.", "label": "important"},
48
+ {"subject": "Urgent: verify your account", "body": "Your account will be suspended. Click to verify.", "label": "spam"},
49
  ]
50
 
51
+ def grade_medium_sorting(agent_fn=None):
52
+ """
53
+ Medium task: classify emails across all 3 categories.
54
+ Returns score strictly in (0.0, 1.0)
55
+ """
56
+ if agent_fn is None:
57
+ agent_fn = baseline_agent
58
+ correct = 0
59
+ for email in MEDIUM_EMAILS:
60
+ prediction = agent_fn(email)
61
+ if prediction == email["label"]:
62
+ correct += 1
63
+ raw = correct / len(MEDIUM_EMAILS)
64
+ score = round(min(0.99, max(0.01, raw)), 2)
65
+ return {"task": "medium_sorting", "correct": correct, "total": len(MEDIUM_EMAILS), "score": score}
66
+
67
+
68
+ # ============================================
69
+ # TASK 3 — HARD: Subtle/tricky emails
70
+ # ============================================
71
+
72
  HARD_EMAILS = [
73
  {"subject": "Your account statement", "body": "Your monthly statement from XYZ Bank is ready.", "label": "important"},
74
+ {"subject": "Limited time: upgrade your plan", "body": "Switch to premium and save 30% this month only.", "label": "promotion"},
75
+ {"subject": "Security alert", "body": "A new login was detected from an unknown device.", "label": "important"},
76
  {"subject": "You have unclaimed rewards", "body": "Collect your loyalty points before they expire.", "label": "promotion"},
77
+ {"subject": "Final notice: payment overdue", "body": "Send $500 to avoid service interruption.", "label": "spam"},
78
+ {"subject": "Team offsite next Friday", "body": "Please confirm your attendance for the offsite.", "label": "important"},
79
+ {"subject": "Claim your free trial", "body": "Start your 30-day free trial no credit card needed.", "label": "promotion"},
80
+ {"subject": "You've been pre-approved!", "body": "You qualify for a $50,000 loan. Apply now.", "label": "spam"},
81
  ]
82
 
83
+ def grade_hard_sorting(agent_fn=None):
84
+ """
85
+ Hard task: subtle emails that are easy to misclassify.
86
+ Returns score strictly in (0.0, 1.0)
87
+ """
88
+ if agent_fn is None:
89
+ agent_fn = baseline_agent
90
+ correct = 0
91
+ for email in HARD_EMAILS:
92
+ prediction = agent_fn(email)
93
+ if prediction == email["label"]:
94
+ correct += 1
95
+ raw = correct / len(HARD_EMAILS)
96
+ score = round(min(0.99, max(0.01, raw)), 2)
97
+ return {"task": "hard_sorting", "correct": correct, "total": len(HARD_EMAILS), "score": score}
98
+
99
+
100
+ # ============================================
101
+ # SIMPLE RULE-BASED AGENT (for baseline)
102
+ # ============================================
103
+
104
+ def baseline_agent(email: dict) -> str:
105
  text = (email.get("subject", "") + " " + email.get("body", "")).lower()
106
+ spam_kw = ["won", "free", "prize", "claim", "urgent", "congratulations",
107
+ "selected", "suspended", "verify", "overdue", "pre-approved"]
108
+ promo_kw = ["off", "sale", "deal", "discount", "offer", "save",
109
+ "shop", "upgrade", "trial", "rewards", "loyalty"]
110
+ spam_score = sum(1 for k in spam_kw if k in text)
111
+ promo_score = sum(1 for k in promo_kw if k in text)
112
+ if spam_score >= 2: return "spam"
113
+ if promo_score >= 1: return "promotion"
114
  return "important"
115
 
 
 
 
116
 
117
+ # ============================================
118
+ # RUN ALL GRADERS
119
+ # ============================================
 
 
 
 
 
 
 
120
 
121
  def run_all_graders(agent_fn=None):
122
+ if agent_fn is None:
123
+ agent_fn = baseline_agent
124
+
125
  results = []
126
+ results.append(grade_easy_sorting(agent_fn))
127
+ results.append(grade_medium_sorting(agent_fn))
128
+ results.append(grade_hard_sorting(agent_fn))
129
+
130
+ avg_score = round(sum(r["score"] for r in results) / len(results), 4)
131
+ all_passed = all(r["score"] >= 0.0 for r in results)
132
+
133
+ print(f"[GRADER] easy={results[0]['score']} medium={results[1]['score']} hard={results[2]['score']} avg={avg_score}", flush=True)
134
+
135
+ return {
136
+ "tasks": results,
137
+ "average_score": avg_score,
138
+ "all_passed": all_passed
139
+ }
140
+
141
 
142
  if __name__ == "__main__":
143
+ print("Running all graders with baseline agent...\n")
144
+ results = run_all_graders()
145
+ for r in results["tasks"]:
146
+ print(f"Task: {r['task']:8s} | Score: {r['score']} | {r['correct']}/{r['total']} correct")
147
+ print(f"\nAverage Score: {results['average_score']}")