jamalinu commited on
Commit
2d7f235
·
verified ·
1 Parent(s): 677f869

Upload 2 files

Browse files
Files changed (2) hide show
  1. eval/test_set.json +32 -0
  2. run_eval.py +112 -0
eval/test_set.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {"text": "People like you are a disease on this country.", "expected": "Direct Hate Speech"},
3
+ {"text": "Immigrants are just parasites who ruin everything.", "expected": "Direct Hate Speech"},
4
+ {"text": "Go back to your own country, you don't belong here.", "expected": "Direct Hate Speech"},
5
+ {"text": "You people are all criminals and always will be.", "expected": "Direct Hate Speech"},
6
+ {"text": "Women are too stupid to work in engineering.", "expected": "Direct Hate Speech"},
7
+ {"text": "Oh sure, because people from your country are always SO trustworthy.", "expected": "Sarcastic Hate Speech"},
8
+ {"text": "Wow, another brilliant contribution from someone who clearly finished school.", "expected": "Sarcastic Hate Speech"},
9
+ {"text": "Of course you'd say that, your kind is always so reasonable.", "expected": "Sarcastic Hate Speech"},
10
+ {"text": "Sure, because everyone from that religion is SO peaceful, right?", "expected": "Sarcastic Hate Speech"},
11
+ {"text": "Oh yes, women are definitely 'too emotional' to lead, how original.", "expected": "Sarcastic Hate Speech"},
12
+ {"text": "Great, my flight got cancelled again. Best day ever.", "expected": "Sarcastic/Ironic (Non-Hateful)"},
13
+ {"text": "Oh sure, because waiting three hours in line is exactly how I wanted to spend my Saturday.", "expected": "Sarcastic/Ironic (Non-Hateful)"},
14
+ {"text": "Wonderful, the WiFi is down again during my presentation.", "expected": "Sarcastic/Ironic (Non-Hateful)"},
15
+ {"text": "Sure, because losing my keys twice in one day is exactly what I needed.", "expected": "Sarcastic/Ironic (Non-Hateful)"},
16
+ {"text": "Oh fantastic, another meeting that could have been an email.", "expected": "Sarcastic/Ironic (Non-Hateful)"},
17
+ {"text": "The meeting is scheduled for 3pm tomorrow.", "expected": "Neutral"},
18
+ {"text": "I really enjoyed the concert last night.", "expected": "Neutral"},
19
+ {"text": "She works as a software engineer at a tech company.", "expected": "Neutral"},
20
+ {"text": "The recipe calls for two cups of flour and one egg.", "expected": "Neutral"},
21
+ {"text": "He moved to Barcelona last year for a new job.", "expected": "Neutral"},
22
+ {"text": "Those who don't eat pork tend to keep to themselves around here.", "expected": "Coded/Dogwhistle Hate — Needs Review"},
23
+ {"text": "The Austrian painter really had some interesting ideas about unity.", "expected": "Coded/Dogwhistle Hate — Needs Review"},
24
+ {"text": "You know how 'those people' are with money.", "expected": "Coded/Dogwhistle Hate — Needs Review"},
25
+ {"text": "The new engineers are really taking over the department, aren't they.", "expected": "Coded/Dogwhistle Hate — Needs Review"},
26
+ {"text": "Funny how certain neighborhoods have changed so much lately.", "expected": "Coded/Dogwhistle Hate — Needs Review"},
27
+ {"text": "I don't eat pork because of a health condition, not religion.", "expected": "Neutral"},
28
+ {"text": "He studied painting in Austria before switching careers.", "expected": "Neutral"},
29
+ {"text": "Our engineering team grew by ten people this quarter.", "expected": "Neutral"},
30
+ {"text": "Sure, blame the weather again for the delay.", "expected": "Sarcastic/Ironic (Non-Hateful)"},
31
+ {"text": "Some people just don't know how to use a turn signal, unbelievable.", "expected": "Neutral"}
32
+ ]
run_eval.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Evaluation script for DeepPragma Classifier.
3
+
4
+ Runs the labeled test set against GroqClient.classify() and reports:
5
+ - overall accuracy
6
+ - per-category accuracy
7
+ - a confusion list of misclassified examples (for manual inspection)
8
+
9
+ Usage:
10
+ python run_eval.py
11
+
12
+ Requires GROQ_API_KEY to be set in the environment.
13
+ Place this file at the project root (same level as app.py),
14
+ and test_set.json inside an eval/ folder (or adjust TEST_SET_PATH below).
15
+ """
16
+
17
+ import json
18
+ import os
19
+ import time
20
+ from collections import defaultdict
21
+
22
+ from src.llm_client import GroqClient
23
+
24
+ TEST_SET_PATH = os.path.join("eval", "test_set.json")
25
+
26
+
27
+ def load_test_set(path):
28
+ with open(path, "r", encoding="utf-8") as f:
29
+ return json.load(f)
30
+
31
+
32
+ def run_evaluation():
33
+ if not os.environ.get("GROQ_API_KEY"):
34
+ print("ERROR: GROQ_API_KEY not set in environment.")
35
+ return
36
+
37
+ test_cases = load_test_set(TEST_SET_PATH)
38
+ llm = GroqClient()
39
+
40
+ total = len(test_cases)
41
+ correct = 0
42
+ per_category_total = defaultdict(int)
43
+ per_category_correct = defaultdict(int)
44
+ errors = []
45
+
46
+ for i, case in enumerate(test_cases, start=1):
47
+ text = case["text"]
48
+ expected = case["expected"]
49
+
50
+ result = llm.classify(text)
51
+ predicted = result["label"]
52
+
53
+ per_category_total[expected] += 1
54
+ is_correct = predicted == expected
55
+ if is_correct:
56
+ correct += 1
57
+ per_category_correct[expected] += 1
58
+ else:
59
+ errors.append({
60
+ "text": text,
61
+ "expected": expected,
62
+ "predicted": predicted,
63
+ "reasoning": result.get("reasoning", ""),
64
+ })
65
+
66
+ print(f"[{i}/{total}] {'OK ' if is_correct else 'FAIL'} "
67
+ f"expected={expected!r} predicted={predicted!r}")
68
+
69
+ # small delay to be gentle with API rate limits
70
+ time.sleep(0.5)
71
+
72
+ print("\n" + "=" * 60)
73
+ print(f"OVERALL ACCURACY: {correct}/{total} ({100 * correct / total:.1f}%)")
74
+ print("=" * 60)
75
+
76
+ print("\nPER-CATEGORY ACCURACY:")
77
+ for category in per_category_total:
78
+ cat_total = per_category_total[category]
79
+ cat_correct = per_category_correct[category]
80
+ print(f" {category}: {cat_correct}/{cat_total} "
81
+ f"({100 * cat_correct / cat_total:.1f}%)")
82
+
83
+ if errors:
84
+ print(f"\nMISCLASSIFIED EXAMPLES ({len(errors)}):")
85
+ for err in errors:
86
+ print(f"\n Text: {err['text']}")
87
+ print(f" Expected: {err['expected']}")
88
+ print(f" Predicted: {err['predicted']}")
89
+ print(f" Reasoning: {err['reasoning']}")
90
+
91
+ # Save results to a JSON report for later reference (e.g. in your CV/interview prep)
92
+ report = {
93
+ "total": total,
94
+ "correct": correct,
95
+ "accuracy": round(100 * correct / total, 1),
96
+ "per_category": {
97
+ cat: {
98
+ "total": per_category_total[cat],
99
+ "correct": per_category_correct[cat],
100
+ "accuracy": round(100 * per_category_correct[cat] / per_category_total[cat], 1),
101
+ }
102
+ for cat in per_category_total
103
+ },
104
+ "errors": errors,
105
+ }
106
+ with open("eval_report.json", "w", encoding="utf-8") as f:
107
+ json.dump(report, f, indent=2, ensure_ascii=False)
108
+ print("\nFull report saved to eval_report.json")
109
+
110
+
111
+ if __name__ == "__main__":
112
+ run_evaluation()