Skip to content

Commit 006ada9

Browse files
author
stephanie gross
committed
added regex for affirmative and negative
1 parent 851d71a commit 006ada9

2 files changed

Lines changed: 440 additions & 0 deletions

File tree

ragability/checks2.py

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
"""
2+
This module defines the checking functions that are implemented for testing the answers we got from LLMs.
3+
The module defines the functions, and registers them in the CHECKS dictionary which contains, for each function
4+
name, the function definition, the kind of check (e.g. binary, multiclass, score), the default target,
5+
and the number of arguments required in addition to the answer text itself.
6+
"""
7+
import re
8+
9+
CHECKS = {}
10+
11+
12+
def register_check(name: str, kind: str, nargs: int, target: str = "", description: str = ""):
13+
"""
14+
Register a check function in the CHECKS dictionary
15+
:param name: the name of the check function
16+
:param kind: the kind of check: binary, multiclass, score
17+
:param nargs: the number of positional arguments required in addition to the answer text itself
18+
these positional arguments come from the list valued "args" field.
19+
keyward parameters are always optional and can be set via the dict valued "kwargs" field.
20+
:param description: a description of the check function
21+
"""
22+
def decorator(func):
23+
CHECKS[name] = {
24+
"func": func,
25+
"kind": kind,
26+
"nargs": nargs,
27+
"target": target, # the evaluation target: this is the value that the evaluator should consider correct for this check
28+
"description": description,
29+
}
30+
return func
31+
return decorator
32+
33+
34+
@register_check("is_eq", "binary", 1,
35+
target="1",
36+
description="Check if the answer is exactly the target")
37+
def is_eq(answer, target):
38+
"""
39+
Check if the answer is exactly the target
40+
:param answer: the answer text
41+
:param target: the target text
42+
:return: 1 if the answer is exactly the target, 0 otherwise
43+
"""
44+
return "1" if answer == target else "0"
45+
46+
47+
@register_check("is_textual_eq", "binary", 1,
48+
target="1",
49+
description="Check if the answer is eq to the target, not considering case and whitespace")
50+
def is_textual_eq(answer, target):
51+
"""
52+
Check if the answer is equal to the target, ignoring case and whitespace
53+
:param answer: the answer text
54+
:param target: the target text
55+
:return: 1 if the answer is equal to the target, ignoring case and whitespace, 0 otherwise
56+
"""
57+
return "1" if answer.strip().lower() == target.strip().lower() else "0"
58+
59+
60+
@register_check("contains", "binary", 1,
61+
target="1",
62+
description="Check if the answer contains the target")
63+
def contains(answer, target):
64+
"""
65+
Check if the answer contains the target
66+
:param answer: the answer text
67+
:param target: the target text
68+
:return: 1 if the answer contains the target, 0 otherwise
69+
"""
70+
return "1" if target in answer else "0"
71+
72+
73+
@register_check("affirmative", "binary", 0,
74+
target="1",
75+
description="Check if the answer is affirmative (yes, true, positive)")
76+
def affirmative(answer):
77+
"""
78+
Check if the answer is affirmative (yes, true, positive)
79+
:param answer: the answer text
80+
:return: 1 if the answer is affirmative, 0 otherwise
81+
"""
82+
if re.match(r'^[\.\s\']{0,10}(yes|true|positive)[\.\s\']{0,10}$', answer.lower()):
83+
return "1"
84+
else:
85+
return "0"
86+
87+
88+
@register_check("negative", "binary", 0,
89+
target="1",
90+
description="Check if the answer is negative (no, false, negative)")
91+
def negative(answer):
92+
"""
93+
Check if the answer is negative (no, false, negative)
94+
:param answer: the answer text
95+
:return: 1 if the answer is negative, 0 otherwise
96+
"""
97+
if re.match(r'^[\.\s\']{0,10}(no|false|negative)[\.\s\']{0,10}$', answer.lower()):
98+
return "1"
99+
else:
100+
return "0"
101+
102+
103+
@register_check("unknown", "binary", 0,
104+
target="1",
105+
description="Check if the answer equals 'unknown'")
106+
def unknown(answer):
107+
"""
108+
Check if the answer textually equals one of: unknown, uncertain, i do not know, i don't know
109+
:param answer: the answer text
110+
:return: 1 if the answer is unknown, 0 otherwise
111+
"""
112+
return "1" if answer.strip().lower() in ["unknown", "uncertain", "i do not know", "i don't know"] else "0"
113+
114+
115+
@register_check("is_eq_oneof", "binary", 1,
116+
description="check if the answer is exactly one of the targets")
117+
def is_eq_oneof(answer, targets):
118+
"""
119+
Check if the answer is exactly one of the targets
120+
:param answer: the answer text
121+
:param targets: a list of target texts
122+
:return: 1 if the answer is exactly one of the targets, 0 otherwise
123+
"""
124+
return "1" if answer in targets else "0"
125+
126+
127+
@register_check("is_textual_eq_oneof", "binary", 1,
128+
description="check if the answer is equal to one of the targets, ignoring case and whitespace")
129+
def is_textual_eq_oneof(answer, targets):
130+
"""
131+
Check if the answer is equal to one of the targets, ignoring case and whitespace
132+
:param answer: the answer text
133+
:param targets: a list of target texts
134+
:return: 1 if the answer is equal to one of the targets, 0 otherwise
135+
"""
136+
return "1" if answer.strip().lower() in [t.strip().lower() for t in targets] else "0"
137+
138+
139+
@register_check("contains_oneof", "binary", 1,
140+
description="check if the answer contains one of the targets")
141+
def contains_oneof(answer, targets):
142+
"""
143+
Check if the answer contains one of the targets
144+
:param answer: the answer text
145+
:param targets: a list of target texts
146+
:return: 1 if the answer contains one of the targets, 0 otherwise
147+
"""
148+
return "1" if any(t in answer for t in targets) else "0"
149+
150+
151+
@register_check("contains_all", "binary", 1,
152+
description="check if the answer contains all of the targets")
153+
def contains_all(answer, targets):
154+
"""
155+
Check if the answer contains all of the targets
156+
:param answer: the answer text
157+
:param targets: a list of target texts
158+
:return: 1 if the answer contains all of the targets, 0 otherwise
159+
"""
160+
return "1" if all(t in answer for t in targets) else "0"
161+
162+
@register_check("extract_score", "score", 0,
163+
description="Extract a score from the answer. Expext exactly one number in the answer,if more raise exception")
164+
def extract_score(answer):
165+
"""
166+
Extract a score from the answer. Expect exactly one number in the answer, if more raise exception
167+
:param answer: the answer text
168+
:return: the score
169+
"""
170+
numbers = [float(s) for s in re.findall(r'-?\d+\.?\d*', answer)]
171+
if len(numbers) != 1:
172+
raise Exception(f"Error: Expected exactly one number in the answer, got {len(numbers)}")
173+
return numbers[0]

0 commit comments

Comments
 (0)